Coverage Report

Created: 2025-10-30 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/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
25
#include "curl_setup.h"
26
27
#ifdef HAVE_NETINET_IN_H
28
#include <netinet/in.h> /* <netinet/tcp.h> may need it */
29
#endif
30
#ifdef HAVE_SYS_UN_H
31
#include <sys/un.h> /* for sockaddr_un */
32
#endif
33
#ifdef HAVE_LINUX_TCP_H
34
#include <linux/tcp.h>
35
#elif defined(HAVE_NETINET_TCP_H)
36
#include <netinet/tcp.h>
37
#endif
38
#ifdef HAVE_SYS_IOCTL_H
39
#include <sys/ioctl.h>
40
#endif
41
#ifdef HAVE_NETDB_H
42
#include <netdb.h>
43
#endif
44
#ifdef HAVE_ARPA_INET_H
45
#include <arpa/inet.h>
46
#endif
47
48
#ifdef __VMS
49
#include <in.h>
50
#include <inet.h>
51
#endif
52
53
#include "urldata.h"
54
#include "sendf.h"
55
#include "if2ip.h"
56
#include "strerror.h"
57
#include "cfilters.h"
58
#include "connect.h"
59
#include "cf-haproxy.h"
60
#include "cf-https-connect.h"
61
#include "cf-ip-happy.h"
62
#include "cf-socket.h"
63
#include "select.h"
64
#include "url.h" /* for Curl_safefree() */
65
#include "multiif.h"
66
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
67
#include "curlx/inet_ntop.h"
68
#include "curlx/inet_pton.h"
69
#include "vtls/vtls.h" /* for vtsl cfilters */
70
#include "progress.h"
71
#include "curlx/warnless.h"
72
#include "conncache.h"
73
#include "multihandle.h"
74
#include "share.h"
75
#include "http_proxy.h"
76
#include "socks.h"
77
78
/* The last 2 #include files should be in this order */
79
#include "curl_memory.h"
80
#include "memdebug.h"
81
82
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
83
84
enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
85
0
{
86
0
  if(len == 2) {
87
0
    if(curl_strnequal(name, "h1", 2))
88
0
      return ALPN_h1;
89
0
    if(curl_strnequal(name, "h2", 2))
90
0
      return ALPN_h2;
91
0
    if(curl_strnequal(name, "h3", 2))
92
0
      return ALPN_h3;
93
0
  }
94
0
  else if(len == 8) {
95
0
    if(curl_strnequal(name, "http/1.1", 8))
96
0
      return ALPN_h1;
97
0
  }
98
0
  return ALPN_none; /* unknown, probably rubbish input */
99
0
}
100
101
#endif
102
103
/*
104
 * Curl_timeleft() returns the amount of milliseconds left allowed for the
105
 * transfer/connection. If the value is 0, there is no timeout (ie there is
106
 * infinite time left). If the value is negative, the timeout time has already
107
 * elapsed.
108
 * @param data the transfer to check on
109
 * @param nowp timestamp to use for calculation, NULL to use curlx_now()
110
 * @param duringconnect TRUE iff connect timeout is also taken into account.
111
 * @unittest: 1303
112
 */
113
timediff_t Curl_timeleft(struct Curl_easy *data,
114
                         struct curltime *nowp,
115
                         bool duringconnect)
116
0
{
117
0
  timediff_t timeleft_ms = 0;
118
0
  timediff_t ctimeleft_ms = 0;
119
0
  struct curltime now;
120
121
  /* The duration of a connect and the total transfer are calculated from two
122
     different time-stamps. It can end up with the total timeout being reached
123
     before the connect timeout expires and we must acknowledge whichever
124
     timeout that is reached first. The total timeout is set per entire
125
     operation, while the connect timeout is set per connect. */
126
0
  if((!data->set.timeout || data->set.connect_only) && !duringconnect)
127
0
    return 0; /* no timeout in place or checked, return "no limit" */
128
129
0
  if(!nowp) {
130
0
    now = curlx_now();
131
0
    nowp = &now;
132
0
  }
133
134
0
  if(data->set.timeout) {
135
0
    timeleft_ms = data->set.timeout -
136
0
      curlx_timediff(*nowp, data->progress.t_startop);
137
0
    if(!timeleft_ms)
138
0
      timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
139
0
    if(!duringconnect)
140
0
      return timeleft_ms; /* no connect check, this is it */
141
0
  }
142
143
0
  if(duringconnect) {
144
0
    timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
145
0
      data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
146
0
    ctimeleft_ms = ctimeout_ms -
147
0
                   curlx_timediff(*nowp, data->progress.t_startsingle);
148
0
    if(!ctimeleft_ms)
149
0
      ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
150
0
    if(!timeleft_ms)
151
0
      return ctimeleft_ms; /* no general timeout, this is it */
152
0
  }
153
  /* return minimal time left or max amount already expired */
154
0
  return (ctimeleft_ms < timeleft_ms) ? ctimeleft_ms : timeleft_ms;
155
0
}
156
157
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
158
                         int timeout_ms, struct curltime *nowp)
159
0
{
160
0
  struct curltime now;
161
0
  struct connectdata *conn = data->conn;
162
163
0
  DEBUGASSERT(conn);
164
0
  if(!nowp) {
165
0
    now = curlx_now();
166
0
    nowp = &now;
167
0
  }
168
0
  conn->shutdown.start[sockindex] = *nowp;
169
0
  conn->shutdown.timeout_ms = (timeout_ms > 0) ?
170
0
    (timediff_t)timeout_ms :
171
0
    ((data->set.shutdowntimeout > 0) ?
172
0
     data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
173
  /* Set a timer, unless we operate on the admin handle */
174
0
  if(data->mid)
175
0
    Curl_expire_ex(data, nowp, conn->shutdown.timeout_ms,
176
0
                   EXPIRE_SHUTDOWN);
177
0
}
178
179
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
180
                                  struct curltime *nowp)
181
0
{
182
0
  struct curltime now;
183
0
  timediff_t left_ms;
184
185
0
  if(!conn->shutdown.start[sockindex].tv_sec ||
186
0
     (conn->shutdown.timeout_ms <= 0))
187
0
    return 0; /* not started or no limits */
188
189
0
  if(!nowp) {
190
0
    now = curlx_now();
191
0
    nowp = &now;
192
0
  }
193
0
  left_ms = conn->shutdown.timeout_ms -
194
0
            curlx_timediff(*nowp, conn->shutdown.start[sockindex]);
195
0
  return left_ms ? left_ms : -1;
196
0
}
197
198
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
199
                                       struct curltime *nowp)
200
0
{
201
0
  timediff_t left_ms = 0, ms;
202
0
  struct curltime now;
203
0
  int i;
204
205
0
  for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
206
0
    if(!conn->shutdown.start[i].tv_sec)
207
0
      continue;
208
0
    if(!nowp) {
209
0
      now = curlx_now();
210
0
      nowp = &now;
211
0
    }
212
0
    ms = Curl_shutdown_timeleft(conn, i, nowp);
213
0
    if(ms && (!left_ms || ms < left_ms))
214
0
      left_ms = ms;
215
0
  }
216
0
  return left_ms;
217
0
}
218
219
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
220
0
{
221
0
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
222
0
  memset(pt, 0, sizeof(*pt));
223
0
}
224
225
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
226
0
{
227
0
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
228
0
  return (pt->tv_sec > 0) || (pt->tv_usec > 0);
229
0
}
230
231
/* retrieves ip address and port from a sockaddr structure. note it calls
232
   curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
233
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
234
                      char *addr, int *port)
235
0
{
236
0
  struct sockaddr_in *si = NULL;
237
0
#ifdef USE_IPV6
238
0
  struct sockaddr_in6 *si6 = NULL;
239
0
#endif
240
0
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
241
0
  struct sockaddr_un *su = NULL;
242
#else
243
  (void)salen;
244
#endif
245
246
0
  switch(sa->sa_family) {
247
0
    case AF_INET:
248
0
      si = (struct sockaddr_in *)(void *) sa;
249
0
      if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
250
0
        unsigned short us_port = ntohs(si->sin_port);
251
0
        *port = us_port;
252
0
        return TRUE;
253
0
      }
254
0
      break;
255
0
#ifdef USE_IPV6
256
0
    case AF_INET6:
257
0
      si6 = (struct sockaddr_in6 *)(void *) sa;
258
0
      if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
259
0
                         MAX_IPADR_LEN)) {
260
0
        unsigned short us_port = ntohs(si6->sin6_port);
261
0
        *port = us_port;
262
0
        return TRUE;
263
0
      }
264
0
      break;
265
0
#endif
266
0
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
267
0
    case AF_UNIX:
268
0
      if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
269
0
        su = (struct sockaddr_un*)sa;
270
0
        curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
271
0
      }
272
0
      else
273
0
        addr[0] = 0; /* socket with no name */
274
0
      *port = 0;
275
0
      return TRUE;
276
0
#endif
277
0
    default:
278
0
      break;
279
0
  }
280
281
0
  addr[0] = '\0';
282
0
  *port = 0;
283
0
  CURL_SETERRNO(SOCKEAFNOSUPPORT);
284
0
  return FALSE;
285
0
}
286
287
/*
288
 * Used to extract socket and connectdata struct for the most recent
289
 * transfer on the given Curl_easy.
290
 *
291
 * The returned socket will be CURL_SOCKET_BAD in case of failure!
292
 */
293
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
294
                                  struct connectdata **connp)
295
0
{
296
0
  DEBUGASSERT(data);
297
298
  /* this works for an easy handle:
299
   * - that has been used for curl_easy_perform()
300
   * - that is associated with a multi handle, and whose connection
301
   *   was detached with CURLOPT_CONNECT_ONLY
302
   */
303
0
  if(data->state.lastconnect_id != -1) {
304
0
    struct connectdata *conn;
305
306
0
    conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
307
0
    if(!conn) {
308
0
      data->state.lastconnect_id = -1;
309
0
      return CURL_SOCKET_BAD;
310
0
    }
311
312
0
    if(connp)
313
      /* only store this if the caller cares for it */
314
0
      *connp = conn;
315
0
    return conn->sock[FIRSTSOCKET];
316
0
  }
317
0
  return CURL_SOCKET_BAD;
318
0
}
319
320
/*
321
 * Curl_conncontrol() marks streams or connection for closure.
322
 */
323
void Curl_conncontrol(struct connectdata *conn,
324
                      int ctrl /* see defines in header */
325
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
326
                      , const char *reason
327
#endif
328
  )
329
0
{
330
  /* close if a connection, or a stream that is not multiplexed. */
331
  /* This function will be called both before and after this connection is
332
     associated with a transfer. */
333
0
  bool closeit, is_multiplex;
334
0
  DEBUGASSERT(conn);
335
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
336
  (void)reason; /* useful for debugging */
337
#endif
338
0
  is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
339
0
  closeit = (ctrl == CONNCTRL_CONNECTION) ||
340
0
    ((ctrl == CONNCTRL_STREAM) && !is_multiplex);
341
0
  if((ctrl == CONNCTRL_STREAM) && is_multiplex)
342
0
    ;  /* stream signal on multiplex conn never affects close state */
343
0
  else if((bit)closeit != conn->bits.close) {
344
0
    conn->bits.close = closeit; /* the only place in the source code that
345
                                   should assign this bit */
346
0
  }
347
0
}
348
349
typedef enum {
350
  CF_SETUP_INIT,
351
  CF_SETUP_CNNCT_EYEBALLS,
352
  CF_SETUP_CNNCT_SOCKS,
353
  CF_SETUP_CNNCT_HTTP_PROXY,
354
  CF_SETUP_CNNCT_HAPROXY,
355
  CF_SETUP_CNNCT_SSL,
356
  CF_SETUP_DONE
357
} cf_setup_state;
358
359
struct cf_setup_ctx {
360
  cf_setup_state state;
361
  int ssl_mode;
362
  int transport;
363
};
364
365
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
366
                                 struct Curl_easy *data,
367
                                 bool *done)
368
0
{
369
0
  struct cf_setup_ctx *ctx = cf->ctx;
370
0
  CURLcode result = CURLE_OK;
371
0
  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
372
373
0
  if(cf->connected) {
374
0
    *done = TRUE;
375
0
    return CURLE_OK;
376
0
  }
377
378
  /* connect current sub-chain */
379
0
connect_sub_chain:
380
0
  if(!dns)
381
0
    return CURLE_FAILED_INIT;
382
383
0
  if(cf->next && !cf->next->connected) {
384
0
    result = Curl_conn_cf_connect(cf->next, data, done);
385
0
    if(result || !*done)
386
0
      return result;
387
0
  }
388
389
0
  if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
390
0
    result = cf_ip_happy_insert_after(cf, data, ctx->transport);
391
0
    if(result)
392
0
      return result;
393
0
    ctx->state = CF_SETUP_CNNCT_EYEBALLS;
394
0
    if(!cf->next || !cf->next->connected)
395
0
      goto connect_sub_chain;
396
0
  }
397
398
  /* sub-chain connected, do we need to add more? */
399
0
#ifndef CURL_DISABLE_PROXY
400
0
  if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
401
0
    result = Curl_cf_socks_proxy_insert_after(cf, data);
402
0
    if(result)
403
0
      return result;
404
0
    ctx->state = CF_SETUP_CNNCT_SOCKS;
405
0
    if(!cf->next || !cf->next->connected)
406
0
      goto connect_sub_chain;
407
0
  }
408
409
0
  if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
410
0
#ifdef USE_SSL
411
0
    if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype)
412
0
       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
413
0
      result = Curl_cf_ssl_proxy_insert_after(cf, data);
414
0
      if(result)
415
0
        return result;
416
0
    }
417
0
#endif /* USE_SSL */
418
419
0
#ifndef CURL_DISABLE_HTTP
420
0
    if(cf->conn->bits.tunnel_proxy) {
421
0
      result = Curl_cf_http_proxy_insert_after(cf, data);
422
0
      if(result)
423
0
        return result;
424
0
    }
425
0
#endif /* !CURL_DISABLE_HTTP */
426
0
    ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
427
0
    if(!cf->next || !cf->next->connected)
428
0
      goto connect_sub_chain;
429
0
  }
430
0
#endif /* !CURL_DISABLE_PROXY */
431
432
0
  if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
433
0
#ifndef CURL_DISABLE_PROXY
434
0
    if(data->set.haproxyprotocol) {
435
0
      if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
436
0
        failf(data, "haproxy protocol not support with SSL "
437
0
              "encryption in place (QUIC?)");
438
0
        return CURLE_UNSUPPORTED_PROTOCOL;
439
0
      }
440
0
      result = Curl_cf_haproxy_insert_after(cf, data);
441
0
      if(result)
442
0
        return result;
443
0
    }
444
0
#endif /* !CURL_DISABLE_PROXY */
445
0
    ctx->state = CF_SETUP_CNNCT_HAPROXY;
446
0
    if(!cf->next || !cf->next->connected)
447
0
      goto connect_sub_chain;
448
0
  }
449
450
0
  if(ctx->state < CF_SETUP_CNNCT_SSL) {
451
0
#ifdef USE_SSL
452
0
    if((ctx->ssl_mode == CURL_CF_SSL_ENABLE
453
0
        || (ctx->ssl_mode != CURL_CF_SSL_DISABLE
454
0
           && cf->conn->handler->flags & PROTOPT_SSL)) /* we want SSL */
455
0
       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
456
0
      result = Curl_cf_ssl_insert_after(cf, data);
457
0
      if(result)
458
0
        return result;
459
0
    }
460
0
#endif /* USE_SSL */
461
0
    ctx->state = CF_SETUP_CNNCT_SSL;
462
0
    if(!cf->next || !cf->next->connected)
463
0
      goto connect_sub_chain;
464
0
  }
465
466
0
  ctx->state = CF_SETUP_DONE;
467
0
  cf->connected = TRUE;
468
0
  *done = TRUE;
469
0
  return CURLE_OK;
470
0
}
471
472
static void cf_setup_close(struct Curl_cfilter *cf,
473
                           struct Curl_easy *data)
474
0
{
475
0
  struct cf_setup_ctx *ctx = cf->ctx;
476
477
0
  CURL_TRC_CF(data, cf, "close");
478
0
  cf->connected = FALSE;
479
0
  ctx->state = CF_SETUP_INIT;
480
481
0
  if(cf->next) {
482
0
    cf->next->cft->do_close(cf->next, data);
483
0
    Curl_conn_cf_discard_chain(&cf->next, data);
484
0
  }
485
0
}
486
487
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
488
0
{
489
0
  struct cf_setup_ctx *ctx = cf->ctx;
490
491
0
  (void)data;
492
0
  CURL_TRC_CF(data, cf, "destroy");
493
0
  Curl_safefree(ctx);
494
0
}
495
496
497
struct Curl_cftype Curl_cft_setup = {
498
  "SETUP",
499
  0,
500
  CURL_LOG_LVL_NONE,
501
  cf_setup_destroy,
502
  cf_setup_connect,
503
  cf_setup_close,
504
  Curl_cf_def_shutdown,
505
  Curl_cf_def_adjust_pollset,
506
  Curl_cf_def_data_pending,
507
  Curl_cf_def_send,
508
  Curl_cf_def_recv,
509
  Curl_cf_def_cntrl,
510
  Curl_cf_def_conn_is_alive,
511
  Curl_cf_def_conn_keep_alive,
512
  Curl_cf_def_query,
513
};
514
515
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
516
                                struct Curl_easy *data,
517
                                int transport,
518
                                int ssl_mode)
519
0
{
520
0
  struct Curl_cfilter *cf = NULL;
521
0
  struct cf_setup_ctx *ctx;
522
0
  CURLcode result = CURLE_OK;
523
524
0
  (void)data;
525
0
  ctx = calloc(1, sizeof(*ctx));
526
0
  if(!ctx) {
527
0
    result = CURLE_OUT_OF_MEMORY;
528
0
    goto out;
529
0
  }
530
0
  ctx->state = CF_SETUP_INIT;
531
0
  ctx->ssl_mode = ssl_mode;
532
0
  ctx->transport = transport;
533
534
0
  result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
535
0
  if(result)
536
0
    goto out;
537
0
  ctx = NULL;
538
539
0
out:
540
0
  *pcf = result ? NULL : cf;
541
0
  if(ctx) {
542
0
    free(ctx);
543
0
  }
544
0
  return result;
545
0
}
546
547
static CURLcode cf_setup_add(struct Curl_easy *data,
548
                             struct connectdata *conn,
549
                             int sockindex,
550
                             int transport,
551
                             int ssl_mode)
552
0
{
553
0
  struct Curl_cfilter *cf;
554
0
  CURLcode result = CURLE_OK;
555
556
0
  DEBUGASSERT(data);
557
0
  result = cf_setup_create(&cf, data, transport, ssl_mode);
558
0
  if(result)
559
0
    goto out;
560
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
561
0
out:
562
0
  return result;
563
0
}
564
565
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
566
                                    struct Curl_easy *data,
567
                                    int transport,
568
                                    int ssl_mode)
569
0
{
570
0
  struct Curl_cfilter *cf;
571
0
  CURLcode result;
572
573
0
  DEBUGASSERT(data);
574
0
  result = cf_setup_create(&cf, data, transport, ssl_mode);
575
0
  if(result)
576
0
    goto out;
577
0
  Curl_conn_cf_insert_after(cf_at, cf);
578
0
out:
579
0
  return result;
580
0
}
581
582
CURLcode Curl_conn_setup(struct Curl_easy *data,
583
                         struct connectdata *conn,
584
                         int sockindex,
585
                         struct Curl_dns_entry *dns,
586
                         int ssl_mode)
587
0
{
588
0
  CURLcode result = CURLE_OK;
589
590
0
  DEBUGASSERT(data);
591
0
  DEBUGASSERT(conn->handler);
592
0
  DEBUGASSERT(dns);
593
594
0
  Curl_resolv_unlink(data, &data->state.dns[sockindex]);
595
0
  data->state.dns[sockindex] = dns;
596
597
0
#ifndef CURL_DISABLE_HTTP
598
0
  if(!conn->cfilter[sockindex] &&
599
0
     conn->handler->protocol == CURLPROTO_HTTPS) {
600
0
    DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
601
0
    result = Curl_cf_https_setup(data, conn, sockindex);
602
0
    if(result)
603
0
      goto out;
604
0
  }
605
0
#endif /* !CURL_DISABLE_HTTP */
606
607
  /* Still no cfilter set, apply default. */
608
0
  if(!conn->cfilter[sockindex]) {
609
0
    result = cf_setup_add(data, conn, sockindex,
610
0
                          conn->transport_wanted, ssl_mode);
611
0
    if(result)
612
0
      goto out;
613
0
  }
614
615
0
  DEBUGASSERT(conn->cfilter[sockindex]);
616
0
out:
617
0
  if(result)
618
0
    Curl_resolv_unlink(data, &data->state.dns[sockindex]);
619
0
  return result;
620
0
}
621
622
void Curl_conn_set_multiplex(struct connectdata *conn)
623
0
{
624
0
  if(!conn->bits.multiplex) {
625
0
    conn->bits.multiplex = TRUE;
626
0
    if(conn->attached_multi) {
627
0
      Curl_multi_connchanged(conn->attached_multi);
628
0
    }
629
0
  }
630
0
}