Coverage Report

Created: 2026-02-26 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/connect.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#ifdef HAVE_NETINET_IN_H
27
#include <netinet/in.h> /* <netinet/tcp.h> may need it */
28
#endif
29
#ifdef HAVE_SYS_UN_H
30
#include <sys/un.h> /* for sockaddr_un */
31
#endif
32
#ifdef HAVE_LINUX_TCP_H
33
#include <linux/tcp.h>
34
#elif defined(HAVE_NETINET_TCP_H)
35
#include <netinet/tcp.h>
36
#endif
37
#ifdef HAVE_SYS_IOCTL_H
38
#include <sys/ioctl.h>
39
#endif
40
#ifdef HAVE_NETDB_H
41
#include <netdb.h>
42
#endif
43
#ifdef HAVE_ARPA_INET_H
44
#include <arpa/inet.h>
45
#endif
46
47
#ifdef __VMS
48
#include <in.h>
49
#include <inet.h>
50
#endif
51
52
#include "urldata.h"
53
#include "curl_trc.h"
54
#include "strerror.h"
55
#include "cfilters.h"
56
#include "connect.h"
57
#include "cf-haproxy.h"
58
#include "cf-https-connect.h"
59
#include "cf-ip-happy.h"
60
#include "cf-socket.h"
61
#include "multiif.h"
62
#include "curlx/inet_ntop.h"
63
#include "curlx/strparse.h"
64
#include "vtls/vtls.h" /* for vtls cfilters */
65
#include "progress.h"
66
#include "conncache.h"
67
#include "multihandle.h"
68
#include "http_proxy.h"
69
#include "socks.h"
70
71
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
72
73
enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len)
74
5.53k
{
75
5.53k
  if(len == 2) {
76
3.33k
    if(!memcmp(name, "h1", 2))
77
1.68k
      return ALPN_h1;
78
1.65k
    if(!memcmp(name, "h2", 2))
79
423
      return ALPN_h2;
80
1.22k
    if(!memcmp(name, "h3", 2))
81
350
      return ALPN_h3;
82
1.22k
  }
83
2.20k
  else if(len == 8) {
84
442
    if(!memcmp(name, "http/1.1", 8))
85
27
      return ALPN_h1;
86
442
  }
87
3.05k
  return ALPN_none; /* unknown, probably rubbish input */
88
5.53k
}
89
90
enum alpnid Curl_str2alpnid(const struct Curl_str *cstr)
91
5.53k
{
92
5.53k
  return Curl_alpn2alpnid((const unsigned char *)curlx_str(cstr),
93
5.53k
                          curlx_strlen(cstr));
94
5.53k
}
95
96
#endif
97
98
/*
99
 * Curl_timeleft_ms() returns the amount of milliseconds left allowed for the
100
 * transfer/connection. If the value is 0, there is no timeout (ie there is
101
 * infinite time left). If the value is negative, the timeout time has already
102
 * elapsed.
103
 * @unittest: 1303
104
 */
105
timediff_t Curl_timeleft_now_ms(struct Curl_easy *data,
106
                                const struct curltime *pnow)
107
79.6M
{
108
79.6M
  timediff_t timeleft_ms = 0;
109
79.6M
  timediff_t ctimeleft_ms = 0;
110
111
79.6M
  if(Curl_shutdown_started(data, FIRSTSOCKET))
112
3.29k
    return Curl_shutdown_timeleft(data, data->conn, FIRSTSOCKET);
113
79.6M
  else if(Curl_is_connecting(data)) {
114
40.2M
    timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
115
36.9M
      data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
116
40.2M
    ctimeleft_ms = ctimeout_ms -
117
40.2M
      curlx_ptimediff_ms(pnow, &data->progress.t_startsingle);
118
40.2M
    if(!ctimeleft_ms)
119
59
      ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
120
40.2M
  }
121
39.4M
  else if(!data->set.timeout || data->set.connect_only) {
122
93.5k
    return 0; /* no timeout in place or checked, return "no limit" */
123
93.5k
  }
124
125
79.5M
  if(data->set.timeout) {
126
79.5M
    timeleft_ms = data->set.timeout -
127
79.5M
      curlx_ptimediff_ms(pnow, &data->progress.t_startop);
128
79.5M
    if(!timeleft_ms)
129
864
      timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
130
79.5M
  }
131
132
79.5M
  if(!ctimeleft_ms)
133
39.3M
    return timeleft_ms;
134
40.2M
  else if(!timeleft_ms)
135
0
    return ctimeleft_ms;
136
40.2M
  return CURLMIN(ctimeleft_ms, timeleft_ms);
137
79.5M
}
138
139
timediff_t Curl_timeleft_ms(struct Curl_easy *data)
140
79.6M
{
141
79.6M
  return Curl_timeleft_now_ms(data, Curl_pgrs_now(data));
142
79.6M
}
143
144
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
145
                         int timeout_ms)
146
24.5k
{
147
24.5k
  struct connectdata *conn = data->conn;
148
149
24.5k
  DEBUGASSERT(conn);
150
24.5k
  conn->shutdown.start[sockindex] = *Curl_pgrs_now(data);
151
24.5k
  conn->shutdown.timeout_ms = (timeout_ms > 0) ?
152
0
    (timediff_t)timeout_ms :
153
24.5k
    ((data->set.shutdowntimeout > 0) ?
154
24.5k
     data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
155
  /* Set a timer, unless we operate on the admin handle */
156
24.5k
  if(data->mid)
157
614
    Curl_expire_ex(data, conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN);
158
24.5k
  CURL_TRC_M(data, "shutdown start on%s connection",
159
24.5k
             sockindex ? " secondary" : "");
160
24.5k
}
161
162
timediff_t Curl_shutdown_timeleft(struct Curl_easy *data,
163
                                  struct connectdata *conn,
164
                                  int sockindex)
165
22.1k
{
166
22.1k
  timediff_t left_ms;
167
168
22.1k
  if(!conn->shutdown.start[sockindex].tv_sec ||
169
22.1k
     (conn->shutdown.timeout_ms <= 0))
170
0
    return 0; /* not started or no limits */
171
172
22.1k
  left_ms = conn->shutdown.timeout_ms -
173
22.1k
            curlx_ptimediff_ms(Curl_pgrs_now(data),
174
22.1k
                               &conn->shutdown.start[sockindex]);
175
22.1k
  return left_ms ? left_ms : -1;
176
22.1k
}
177
178
timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data,
179
                                       struct connectdata *conn)
180
0
{
181
0
  timediff_t left_ms = 0, ms;
182
0
  int i;
183
184
0
  for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
185
0
    if(!conn->shutdown.start[i].tv_sec)
186
0
      continue;
187
0
    ms = Curl_shutdown_timeleft(data, conn, i);
188
0
    if(ms && (!left_ms || ms < left_ms))
189
0
      left_ms = ms;
190
0
  }
191
0
  return left_ms;
192
0
}
193
194
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
195
214k
{
196
214k
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
197
214k
  memset(pt, 0, sizeof(*pt));
198
214k
}
199
200
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
201
89.2M
{
202
89.2M
  if(data->conn) {
203
89.2M
    struct curltime *pt = &data->conn->shutdown.start[sockindex];
204
89.2M
    return (pt->tv_sec > 0) || (pt->tv_usec > 0);
205
89.2M
  }
206
19.3k
  return FALSE;
207
89.2M
}
208
209
/* retrieves ip address and port from a sockaddr structure. note it calls
210
   curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
211
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
212
                      char *addr, uint16_t *port)
213
244k
{
214
244k
  struct sockaddr_in *si = NULL;
215
244k
#ifdef USE_IPV6
216
244k
  struct sockaddr_in6 *si6 = NULL;
217
244k
#endif
218
244k
#ifdef USE_UNIX_SOCKETS
219
244k
  struct sockaddr_un *su = NULL;
220
#else
221
  (void)salen;
222
#endif
223
224
244k
  switch(sa->sa_family) {
225
97.5k
  case AF_INET:
226
97.5k
    si = (struct sockaddr_in *)(void *)sa;
227
97.5k
    if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
228
97.5k
      *port = ntohs(si->sin_port);
229
97.5k
      return TRUE;
230
97.5k
    }
231
0
    break;
232
0
#ifdef USE_IPV6
233
1.18k
  case AF_INET6:
234
1.18k
    si6 = (struct sockaddr_in6 *)(void *)sa;
235
1.18k
    if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
236
1.18k
      *port = ntohs(si6->sin6_port);
237
1.18k
      return TRUE;
238
1.18k
    }
239
0
    break;
240
0
#endif
241
0
#ifdef USE_UNIX_SOCKETS
242
145k
  case AF_UNIX:
243
145k
    if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
244
1.07k
      su = (struct sockaddr_un *)sa;
245
1.07k
      curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
246
1.07k
    }
247
144k
    else
248
144k
      addr[0] = 0; /* socket with no name */
249
145k
    *port = 0;
250
145k
    return TRUE;
251
0
#endif
252
0
  default:
253
0
    break;
254
244k
  }
255
256
0
  addr[0] = '\0';
257
0
  *port = 0;
258
0
  errno = SOCKEAFNOSUPPORT;
259
0
  return FALSE;
260
244k
}
261
262
/*
263
 * Used to extract socket and connectdata struct for the most recent
264
 * transfer on the given Curl_easy.
265
 *
266
 * The returned socket will be CURL_SOCKET_BAD in case of failure!
267
 */
268
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
269
                                  struct connectdata **connp)
270
15.3k
{
271
15.3k
  DEBUGASSERT(data);
272
273
  /* this works for an easy handle:
274
   * - that has been used for curl_easy_perform()
275
   * - that is associated with a multi handle, and whose connection
276
   *   was detached with CURLOPT_CONNECT_ONLY
277
   */
278
15.3k
  if(data->state.lastconnect_id != -1) {
279
3.08k
    struct connectdata *conn;
280
281
3.08k
    conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
282
3.08k
    if(!conn) {
283
0
      data->state.lastconnect_id = -1;
284
0
      return CURL_SOCKET_BAD;
285
0
    }
286
287
3.08k
    if(connp)
288
      /* only store this if the caller cares for it */
289
3.08k
      *connp = conn;
290
3.08k
    return conn->sock[FIRSTSOCKET];
291
3.08k
  }
292
12.2k
  return CURL_SOCKET_BAD;
293
15.3k
}
294
295
/*
296
 * Curl_conncontrol() marks streams or connection for closure.
297
 */
298
void Curl_conncontrol(struct connectdata *conn,
299
                      int ctrl /* see defines in header */
300
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
301
                      , const char *reason
302
#endif
303
  )
304
165k
{
305
  /* close if a connection, or a stream that is not multiplexed. */
306
  /* This function will be called both before and after this connection is
307
     associated with a transfer. */
308
165k
  bool closeit, is_multiplex;
309
165k
  DEBUGASSERT(conn);
310
165k
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
311
165k
  (void)reason; /* useful for debugging */
312
165k
#endif
313
165k
  is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
314
165k
  closeit = (ctrl == CONNCTRL_CONNECTION) ||
315
32.6k
            ((ctrl == CONNCTRL_STREAM) && !is_multiplex);
316
165k
  if((ctrl == CONNCTRL_STREAM) && is_multiplex)
317
14.1k
    ;  /* stream signal on multiplex conn never affects close state */
318
151k
  else if((curl_bit)closeit != conn->bits.close) {
319
91.9k
    conn->bits.close = closeit; /* the only place in the source code that
320
                                   should assign this bit */
321
91.9k
  }
322
165k
}
323
324
typedef enum {
325
  CF_SETUP_INIT,
326
  CF_SETUP_CNNCT_EYEBALLS,
327
  CF_SETUP_CNNCT_SOCKS,
328
  CF_SETUP_CNNCT_HTTP_PROXY,
329
  CF_SETUP_CNNCT_HAPROXY,
330
  CF_SETUP_CNNCT_SSL,
331
  CF_SETUP_DONE
332
} cf_setup_state;
333
334
struct cf_setup_ctx {
335
  cf_setup_state state;
336
  int ssl_mode;
337
  uint8_t transport;
338
};
339
340
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
341
                                 struct Curl_easy *data,
342
                                 bool *done)
343
3.04M
{
344
3.04M
  struct cf_setup_ctx *ctx = cf->ctx;
345
3.04M
  CURLcode result = CURLE_OK;
346
3.04M
  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
347
348
3.04M
  if(cf->connected) {
349
0
    *done = TRUE;
350
0
    return CURLE_OK;
351
0
  }
352
353
  /* connect current sub-chain */
354
3.19M
connect_sub_chain:
355
3.19M
  if(!dns)
356
0
    return CURLE_FAILED_INIT;
357
358
3.19M
  if(cf->next && !cf->next->connected) {
359
3.10M
    result = Curl_conn_cf_connect(cf->next, data, done);
360
3.10M
    if(result || !*done)
361
2.99M
      return result;
362
3.10M
  }
363
364
203k
  if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
365
98.6k
    result = cf_ip_happy_insert_after(cf, data, ctx->transport);
366
98.6k
    if(result)
367
0
      return result;
368
98.6k
    ctx->state = CF_SETUP_CNNCT_EYEBALLS;
369
98.6k
    if(!cf->next || !cf->next->connected)
370
98.6k
      goto connect_sub_chain;
371
98.6k
  }
372
373
  /* sub-chain connected, do we need to add more? */
374
104k
#ifndef CURL_DISABLE_PROXY
375
104k
  if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
376
1.07k
    result = Curl_cf_socks_proxy_insert_after(cf, data);
377
1.07k
    if(result)
378
0
      return result;
379
1.07k
    ctx->state = CF_SETUP_CNNCT_SOCKS;
380
1.07k
    if(!cf->next || !cf->next->connected)
381
1.07k
      goto connect_sub_chain;
382
1.07k
  }
383
384
103k
  if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
385
32.4k
#ifdef USE_SSL
386
32.4k
    if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype) &&
387
11.9k
       !Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
388
11.9k
      result = Curl_cf_ssl_proxy_insert_after(cf, data);
389
11.9k
      if(result)
390
0
        return result;
391
11.9k
    }
392
32.4k
#endif /* USE_SSL */
393
394
32.4k
#ifndef CURL_DISABLE_HTTP
395
32.4k
    if(cf->conn->bits.tunnel_proxy) {
396
31.7k
      result = Curl_cf_http_proxy_insert_after(cf, data);
397
31.7k
      if(result)
398
0
        return result;
399
31.7k
    }
400
32.4k
#endif /* !CURL_DISABLE_HTTP */
401
32.4k
    ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
402
32.4k
    if(!cf->next || !cf->next->connected)
403
31.7k
      goto connect_sub_chain;
404
32.4k
  }
405
71.9k
#endif /* !CURL_DISABLE_PROXY */
406
407
71.9k
  if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
408
71.1k
#ifndef CURL_DISABLE_PROXY
409
71.1k
    if(data->set.haproxyprotocol) {
410
808
      if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
411
0
        failf(data, "haproxy protocol not support with SSL "
412
0
              "encryption in place (QUIC?)");
413
0
        return CURLE_UNSUPPORTED_PROTOCOL;
414
0
      }
415
808
      result = Curl_cf_haproxy_insert_after(cf, data);
416
808
      if(result)
417
0
        return result;
418
808
    }
419
71.1k
#endif /* !CURL_DISABLE_PROXY */
420
71.1k
    ctx->state = CF_SETUP_CNNCT_HAPROXY;
421
71.1k
    if(!cf->next || !cf->next->connected)
422
808
      goto connect_sub_chain;
423
71.1k
  }
424
425
71.1k
  if(ctx->state < CF_SETUP_CNNCT_SSL) {
426
71.1k
#ifdef USE_SSL
427
71.1k
    if((ctx->ssl_mode == CURL_CF_SSL_ENABLE ||
428
68.5k
        (ctx->ssl_mode != CURL_CF_SSL_DISABLE &&
429
67.4k
         cf->conn->scheme->flags & PROTOPT_SSL)) &&  /* we want SSL */
430
20.0k
       !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
431
20.0k
      result = Curl_cf_ssl_insert_after(cf, data);
432
20.0k
      if(result)
433
0
        return result;
434
20.0k
    }
435
71.1k
#endif /* USE_SSL */
436
71.1k
    ctx->state = CF_SETUP_CNNCT_SSL;
437
71.1k
    if(!cf->next || !cf->next->connected)
438
20.0k
      goto connect_sub_chain;
439
71.1k
  }
440
441
51.0k
  ctx->state = CF_SETUP_DONE;
442
51.0k
  cf->connected = TRUE;
443
51.0k
  *done = TRUE;
444
51.0k
  return CURLE_OK;
445
71.1k
}
446
447
static void cf_setup_close(struct Curl_cfilter *cf,
448
                           struct Curl_easy *data)
449
98.6k
{
450
98.6k
  struct cf_setup_ctx *ctx = cf->ctx;
451
452
98.6k
  CURL_TRC_CF(data, cf, "close");
453
98.6k
  cf->connected = FALSE;
454
98.6k
  ctx->state = CF_SETUP_INIT;
455
456
98.6k
  if(cf->next) {
457
98.6k
    cf->next->cft->do_close(cf->next, data);
458
98.6k
    Curl_conn_cf_discard_chain(&cf->next, data);
459
98.6k
  }
460
98.6k
}
461
462
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
463
98.6k
{
464
98.6k
  struct cf_setup_ctx *ctx = cf->ctx;
465
466
98.6k
  CURL_TRC_CF(data, cf, "destroy");
467
98.6k
  Curl_safefree(ctx);
468
98.6k
}
469
470
struct Curl_cftype Curl_cft_setup = {
471
  "SETUP",
472
  0,
473
  CURL_LOG_LVL_NONE,
474
  cf_setup_destroy,
475
  cf_setup_connect,
476
  cf_setup_close,
477
  Curl_cf_def_shutdown,
478
  Curl_cf_def_adjust_pollset,
479
  Curl_cf_def_data_pending,
480
  Curl_cf_def_send,
481
  Curl_cf_def_recv,
482
  Curl_cf_def_cntrl,
483
  Curl_cf_def_conn_is_alive,
484
  Curl_cf_def_conn_keep_alive,
485
  Curl_cf_def_query,
486
};
487
488
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
489
                                struct Curl_easy *data,
490
                                uint8_t transport,
491
                                int ssl_mode)
492
98.6k
{
493
98.6k
  struct Curl_cfilter *cf = NULL;
494
98.6k
  struct cf_setup_ctx *ctx;
495
98.6k
  CURLcode result = CURLE_OK;
496
497
98.6k
  (void)data;
498
98.6k
  ctx = curlx_calloc(1, sizeof(*ctx));
499
98.6k
  if(!ctx) {
500
0
    result = CURLE_OUT_OF_MEMORY;
501
0
    goto out;
502
0
  }
503
98.6k
  ctx->state = CF_SETUP_INIT;
504
98.6k
  ctx->ssl_mode = ssl_mode;
505
98.6k
  ctx->transport = transport;
506
507
98.6k
  result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
508
98.6k
  if(result)
509
0
    goto out;
510
98.6k
  ctx = NULL;
511
512
98.6k
out:
513
98.6k
  *pcf = result ? NULL : cf;
514
98.6k
  if(ctx) {
515
0
    curlx_free(ctx);
516
0
  }
517
98.6k
  return result;
518
98.6k
}
519
520
static CURLcode cf_setup_add(struct Curl_easy *data,
521
                             struct connectdata *conn,
522
                             int sockindex,
523
                             uint8_t transport,
524
                             int ssl_mode)
525
93.0k
{
526
93.0k
  struct Curl_cfilter *cf;
527
93.0k
  CURLcode result = CURLE_OK;
528
529
93.0k
  DEBUGASSERT(data);
530
93.0k
  result = cf_setup_create(&cf, data, transport, ssl_mode);
531
93.0k
  if(result)
532
0
    goto out;
533
93.0k
  Curl_conn_cf_add(data, conn, sockindex, cf);
534
93.0k
out:
535
93.0k
  return result;
536
93.0k
}
537
538
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
539
                                    struct Curl_easy *data,
540
                                    uint8_t transport,
541
                                    int ssl_mode)
542
5.60k
{
543
5.60k
  struct Curl_cfilter *cf;
544
5.60k
  CURLcode result;
545
546
5.60k
  DEBUGASSERT(data);
547
5.60k
  result = cf_setup_create(&cf, data, transport, ssl_mode);
548
5.60k
  if(result)
549
0
    goto out;
550
5.60k
  Curl_conn_cf_insert_after(cf_at, cf);
551
5.60k
out:
552
5.60k
  return result;
553
5.60k
}
554
555
CURLcode Curl_conn_setup(struct Curl_easy *data,
556
                         struct connectdata *conn,
557
                         int sockindex,
558
                         struct Curl_dns_entry *dns,
559
                         int ssl_mode)
560
98.6k
{
561
98.6k
  CURLcode result = CURLE_OK;
562
563
98.6k
  DEBUGASSERT(data);
564
98.6k
  DEBUGASSERT(conn->scheme);
565
98.6k
  DEBUGASSERT(dns);
566
567
98.6k
  Curl_resolv_unlink(data, &data->state.dns[sockindex]);
568
98.6k
  data->state.dns[sockindex] = dns;
569
570
98.6k
#ifndef CURL_DISABLE_HTTP
571
98.6k
  if(!conn->cfilter[sockindex] &&
572
98.6k
     conn->scheme->protocol == CURLPROTO_HTTPS) {
573
5.65k
    DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
574
5.65k
    result = Curl_cf_https_setup(data, conn, sockindex);
575
5.65k
    if(result)
576
0
      goto out;
577
5.65k
  }
578
98.6k
#endif /* !CURL_DISABLE_HTTP */
579
580
  /* Still no cfilter set, apply default. */
581
98.6k
  if(!conn->cfilter[sockindex]) {
582
93.0k
    result = cf_setup_add(data, conn, sockindex,
583
93.0k
                          conn->transport_wanted, ssl_mode);
584
93.0k
    if(result)
585
0
      goto out;
586
93.0k
  }
587
588
98.6k
  DEBUGASSERT(conn->cfilter[sockindex]);
589
98.6k
out:
590
98.6k
  if(result)
591
0
    Curl_resolv_unlink(data, &data->state.dns[sockindex]);
592
98.6k
  return result;
593
98.6k
}
594
595
void Curl_conn_set_multiplex(struct connectdata *conn)
596
16.1k
{
597
16.1k
  if(!conn->bits.multiplex) {
598
16.1k
    conn->bits.multiplex = TRUE;
599
16.1k
    if(conn->attached_multi) {
600
16.1k
      Curl_multi_connchanged(conn->attached_multi);
601
16.1k
    }
602
16.1k
  }
603
16.1k
}