Coverage Report

Created: 2025-10-10 06:31

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 <= 0 && !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 > 0) {
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
162
0
  DEBUGASSERT(data->conn);
163
0
  if(!nowp) {
164
0
    now = curlx_now();
165
0
    nowp = &now;
166
0
  }
167
0
  data->conn->shutdown.start[sockindex] = *nowp;
168
0
  data->conn->shutdown.timeout_ms = (timeout_ms > 0) ?
169
0
    (timediff_t)timeout_ms :
170
0
    ((data->set.shutdowntimeout > 0) ?
171
0
     data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
172
  /* Set a timer, unless we operate on the admin handle */
173
0
  if(data->mid && (data->conn->shutdown.timeout_ms > 0))
174
0
    Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
175
0
                   EXPIRE_SHUTDOWN);
176
0
}
177
178
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
179
                                  struct curltime *nowp)
180
0
{
181
0
  struct curltime now;
182
0
  timediff_t left_ms;
183
184
0
  if(!conn->shutdown.start[sockindex].tv_sec ||
185
0
     (conn->shutdown.timeout_ms <= 0))
186
0
    return 0; /* not started or no limits */
187
188
0
  if(!nowp) {
189
0
    now = curlx_now();
190
0
    nowp = &now;
191
0
  }
192
0
  left_ms = conn->shutdown.timeout_ms -
193
0
            curlx_timediff(*nowp, conn->shutdown.start[sockindex]);
194
0
  return left_ms ? left_ms : -1;
195
0
}
196
197
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
198
                                       struct curltime *nowp)
199
0
{
200
0
  timediff_t left_ms = 0, ms;
201
0
  struct curltime now;
202
0
  int i;
203
204
0
  for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
205
0
    if(!conn->shutdown.start[i].tv_sec)
206
0
      continue;
207
0
    if(!nowp) {
208
0
      now = curlx_now();
209
0
      nowp = &now;
210
0
    }
211
0
    ms = Curl_shutdown_timeleft(conn, i, nowp);
212
0
    if(ms && (!left_ms || ms < left_ms))
213
0
      left_ms = ms;
214
0
  }
215
0
  return left_ms;
216
0
}
217
218
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
219
0
{
220
0
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
221
0
  memset(pt, 0, sizeof(*pt));
222
0
}
223
224
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
225
0
{
226
0
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
227
0
  return (pt->tv_sec > 0) || (pt->tv_usec > 0);
228
0
}
229
230
/* retrieves ip address and port from a sockaddr structure. note it calls
231
   curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
232
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
233
                      char *addr, int *port)
234
0
{
235
0
  struct sockaddr_in *si = NULL;
236
0
#ifdef USE_IPV6
237
0
  struct sockaddr_in6 *si6 = NULL;
238
0
#endif
239
0
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
240
0
  struct sockaddr_un *su = NULL;
241
#else
242
  (void)salen;
243
#endif
244
245
0
  switch(sa->sa_family) {
246
0
    case AF_INET:
247
0
      si = (struct sockaddr_in *)(void *) sa;
248
0
      if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
249
0
        unsigned short us_port = ntohs(si->sin_port);
250
0
        *port = us_port;
251
0
        return TRUE;
252
0
      }
253
0
      break;
254
0
#ifdef USE_IPV6
255
0
    case AF_INET6:
256
0
      si6 = (struct sockaddr_in6 *)(void *) sa;
257
0
      if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
258
0
                         MAX_IPADR_LEN)) {
259
0
        unsigned short us_port = ntohs(si6->sin6_port);
260
0
        *port = us_port;
261
0
        return TRUE;
262
0
      }
263
0
      break;
264
0
#endif
265
0
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
266
0
    case AF_UNIX:
267
0
      if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
268
0
        su = (struct sockaddr_un*)sa;
269
0
        curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
270
0
      }
271
0
      else
272
0
        addr[0] = 0; /* socket with no name */
273
0
      *port = 0;
274
0
      return TRUE;
275
0
#endif
276
0
    default:
277
0
      break;
278
0
  }
279
280
0
  addr[0] = '\0';
281
0
  *port = 0;
282
0
  CURL_SETERRNO(SOCKEAFNOSUPPORT);
283
0
  return FALSE;
284
0
}
285
286
/*
287
 * Used to extract socket and connectdata struct for the most recent
288
 * transfer on the given Curl_easy.
289
 *
290
 * The returned socket will be CURL_SOCKET_BAD in case of failure!
291
 */
292
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
293
                                  struct connectdata **connp)
294
0
{
295
0
  DEBUGASSERT(data);
296
297
  /* this works for an easy handle:
298
   * - that has been used for curl_easy_perform()
299
   * - that is associated with a multi handle, and whose connection
300
   *   was detached with CURLOPT_CONNECT_ONLY
301
   */
302
0
  if(data->state.lastconnect_id != -1) {
303
0
    struct connectdata *conn;
304
305
0
    conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
306
0
    if(!conn) {
307
0
      data->state.lastconnect_id = -1;
308
0
      return CURL_SOCKET_BAD;
309
0
    }
310
311
0
    if(connp)
312
      /* only store this if the caller cares for it */
313
0
      *connp = conn;
314
0
    return conn->sock[FIRSTSOCKET];
315
0
  }
316
0
  return CURL_SOCKET_BAD;
317
0
}
318
319
/*
320
 * Curl_conncontrol() marks streams or connection for closure.
321
 */
322
void Curl_conncontrol(struct connectdata *conn,
323
                      int ctrl /* see defines in header */
324
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
325
                      , const char *reason
326
#endif
327
  )
328
0
{
329
  /* close if a connection, or a stream that is not multiplexed. */
330
  /* This function will be called both before and after this connection is
331
     associated with a transfer. */
332
0
  bool closeit, is_multiplex;
333
0
  DEBUGASSERT(conn);
334
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
335
  (void)reason; /* useful for debugging */
336
#endif
337
0
  is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
338
0
  closeit = (ctrl == CONNCTRL_CONNECTION) ||
339
0
    ((ctrl == CONNCTRL_STREAM) && !is_multiplex);
340
0
  if((ctrl == CONNCTRL_STREAM) && is_multiplex)
341
0
    ;  /* stream signal on multiplex conn never affects close state */
342
0
  else if((bit)closeit != conn->bits.close) {
343
0
    conn->bits.close = closeit; /* the only place in the source code that
344
                                   should assign this bit */
345
0
  }
346
0
}
347
348
typedef enum {
349
  CF_SETUP_INIT,
350
  CF_SETUP_CNNCT_EYEBALLS,
351
  CF_SETUP_CNNCT_SOCKS,
352
  CF_SETUP_CNNCT_HTTP_PROXY,
353
  CF_SETUP_CNNCT_HAPROXY,
354
  CF_SETUP_CNNCT_SSL,
355
  CF_SETUP_DONE
356
} cf_setup_state;
357
358
struct cf_setup_ctx {
359
  cf_setup_state state;
360
  int ssl_mode;
361
  int transport;
362
};
363
364
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
365
                                 struct Curl_easy *data,
366
                                 bool *done)
367
0
{
368
0
  struct cf_setup_ctx *ctx = cf->ctx;
369
0
  CURLcode result = CURLE_OK;
370
0
  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
371
372
0
  if(cf->connected) {
373
0
    *done = TRUE;
374
0
    return CURLE_OK;
375
0
  }
376
377
  /* connect current sub-chain */
378
0
connect_sub_chain:
379
0
  if(!dns)
380
0
    return CURLE_FAILED_INIT;
381
382
0
  if(cf->next && !cf->next->connected) {
383
0
    result = Curl_conn_cf_connect(cf->next, data, done);
384
0
    if(result || !*done)
385
0
      return result;
386
0
  }
387
388
0
  if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
389
0
    result = cf_ip_happy_insert_after(cf, data, ctx->transport);
390
0
    if(result)
391
0
      return result;
392
0
    ctx->state = CF_SETUP_CNNCT_EYEBALLS;
393
0
    if(!cf->next || !cf->next->connected)
394
0
      goto connect_sub_chain;
395
0
  }
396
397
  /* sub-chain connected, do we need to add more? */
398
0
#ifndef CURL_DISABLE_PROXY
399
0
  if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
400
0
    result = Curl_cf_socks_proxy_insert_after(cf, data);
401
0
    if(result)
402
0
      return result;
403
0
    ctx->state = CF_SETUP_CNNCT_SOCKS;
404
0
    if(!cf->next || !cf->next->connected)
405
0
      goto connect_sub_chain;
406
0
  }
407
408
0
  if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
409
0
#ifdef USE_SSL
410
0
    if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype)
411
0
       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
412
0
      result = Curl_cf_ssl_proxy_insert_after(cf, data);
413
0
      if(result)
414
0
        return result;
415
0
    }
416
0
#endif /* USE_SSL */
417
418
0
#ifndef CURL_DISABLE_HTTP
419
0
    if(cf->conn->bits.tunnel_proxy) {
420
0
      result = Curl_cf_http_proxy_insert_after(cf, data);
421
0
      if(result)
422
0
        return result;
423
0
    }
424
0
#endif /* !CURL_DISABLE_HTTP */
425
0
    ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
426
0
    if(!cf->next || !cf->next->connected)
427
0
      goto connect_sub_chain;
428
0
  }
429
0
#endif /* !CURL_DISABLE_PROXY */
430
431
0
  if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
432
0
#ifndef CURL_DISABLE_PROXY
433
0
    if(data->set.haproxyprotocol) {
434
0
      if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
435
0
        failf(data, "haproxy protocol not support with SSL "
436
0
              "encryption in place (QUIC?)");
437
0
        return CURLE_UNSUPPORTED_PROTOCOL;
438
0
      }
439
0
      result = Curl_cf_haproxy_insert_after(cf, data);
440
0
      if(result)
441
0
        return result;
442
0
    }
443
0
#endif /* !CURL_DISABLE_PROXY */
444
0
    ctx->state = CF_SETUP_CNNCT_HAPROXY;
445
0
    if(!cf->next || !cf->next->connected)
446
0
      goto connect_sub_chain;
447
0
  }
448
449
0
  if(ctx->state < CF_SETUP_CNNCT_SSL) {
450
0
#ifdef USE_SSL
451
0
    if((ctx->ssl_mode == CURL_CF_SSL_ENABLE
452
0
        || (ctx->ssl_mode != CURL_CF_SSL_DISABLE
453
0
           && cf->conn->handler->flags & PROTOPT_SSL)) /* we want SSL */
454
0
       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
455
0
      result = Curl_cf_ssl_insert_after(cf, data);
456
0
      if(result)
457
0
        return result;
458
0
    }
459
0
#endif /* USE_SSL */
460
0
    ctx->state = CF_SETUP_CNNCT_SSL;
461
0
    if(!cf->next || !cf->next->connected)
462
0
      goto connect_sub_chain;
463
0
  }
464
465
0
  ctx->state = CF_SETUP_DONE;
466
0
  cf->connected = TRUE;
467
0
  *done = TRUE;
468
0
  return CURLE_OK;
469
0
}
470
471
static void cf_setup_close(struct Curl_cfilter *cf,
472
                           struct Curl_easy *data)
473
0
{
474
0
  struct cf_setup_ctx *ctx = cf->ctx;
475
476
0
  CURL_TRC_CF(data, cf, "close");
477
0
  cf->connected = FALSE;
478
0
  ctx->state = CF_SETUP_INIT;
479
480
0
  if(cf->next) {
481
0
    cf->next->cft->do_close(cf->next, data);
482
0
    Curl_conn_cf_discard_chain(&cf->next, data);
483
0
  }
484
0
}
485
486
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
487
0
{
488
0
  struct cf_setup_ctx *ctx = cf->ctx;
489
490
0
  (void)data;
491
0
  CURL_TRC_CF(data, cf, "destroy");
492
0
  Curl_safefree(ctx);
493
0
}
494
495
496
struct Curl_cftype Curl_cft_setup = {
497
  "SETUP",
498
  0,
499
  CURL_LOG_LVL_NONE,
500
  cf_setup_destroy,
501
  cf_setup_connect,
502
  cf_setup_close,
503
  Curl_cf_def_shutdown,
504
  Curl_cf_def_adjust_pollset,
505
  Curl_cf_def_data_pending,
506
  Curl_cf_def_send,
507
  Curl_cf_def_recv,
508
  Curl_cf_def_cntrl,
509
  Curl_cf_def_conn_is_alive,
510
  Curl_cf_def_conn_keep_alive,
511
  Curl_cf_def_query,
512
};
513
514
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
515
                                struct Curl_easy *data,
516
                                int transport,
517
                                int ssl_mode)
518
0
{
519
0
  struct Curl_cfilter *cf = NULL;
520
0
  struct cf_setup_ctx *ctx;
521
0
  CURLcode result = CURLE_OK;
522
523
0
  (void)data;
524
0
  ctx = calloc(1, sizeof(*ctx));
525
0
  if(!ctx) {
526
0
    result = CURLE_OUT_OF_MEMORY;
527
0
    goto out;
528
0
  }
529
0
  ctx->state = CF_SETUP_INIT;
530
0
  ctx->ssl_mode = ssl_mode;
531
0
  ctx->transport = transport;
532
533
0
  result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
534
0
  if(result)
535
0
    goto out;
536
0
  ctx = NULL;
537
538
0
out:
539
0
  *pcf = result ? NULL : cf;
540
0
  if(ctx) {
541
0
    free(ctx);
542
0
  }
543
0
  return result;
544
0
}
545
546
static CURLcode cf_setup_add(struct Curl_easy *data,
547
                             struct connectdata *conn,
548
                             int sockindex,
549
                             int transport,
550
                             int ssl_mode)
551
0
{
552
0
  struct Curl_cfilter *cf;
553
0
  CURLcode result = CURLE_OK;
554
555
0
  DEBUGASSERT(data);
556
0
  result = cf_setup_create(&cf, data, transport, ssl_mode);
557
0
  if(result)
558
0
    goto out;
559
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
560
0
out:
561
0
  return result;
562
0
}
563
564
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
565
                                    struct Curl_easy *data,
566
                                    int transport,
567
                                    int ssl_mode)
568
0
{
569
0
  struct Curl_cfilter *cf;
570
0
  CURLcode result;
571
572
0
  DEBUGASSERT(data);
573
0
  result = cf_setup_create(&cf, data, transport, ssl_mode);
574
0
  if(result)
575
0
    goto out;
576
0
  Curl_conn_cf_insert_after(cf_at, cf);
577
0
out:
578
0
  return result;
579
0
}
580
581
CURLcode Curl_conn_setup(struct Curl_easy *data,
582
                         struct connectdata *conn,
583
                         int sockindex,
584
                         struct Curl_dns_entry *dns,
585
                         int ssl_mode)
586
0
{
587
0
  CURLcode result = CURLE_OK;
588
589
0
  DEBUGASSERT(data);
590
0
  DEBUGASSERT(conn->handler);
591
0
  DEBUGASSERT(dns);
592
593
0
  Curl_resolv_unlink(data, &data->state.dns[sockindex]);
594
0
  data->state.dns[sockindex] = dns;
595
596
0
#ifndef CURL_DISABLE_HTTP
597
0
  if(!conn->cfilter[sockindex] &&
598
0
     conn->handler->protocol == CURLPROTO_HTTPS) {
599
0
    DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
600
0
    result = Curl_cf_https_setup(data, conn, sockindex);
601
0
    if(result)
602
0
      goto out;
603
0
  }
604
0
#endif /* !CURL_DISABLE_HTTP */
605
606
  /* Still no cfilter set, apply default. */
607
0
  if(!conn->cfilter[sockindex]) {
608
0
    result = cf_setup_add(data, conn, sockindex,
609
0
                          conn->transport_wanted, ssl_mode);
610
0
    if(result)
611
0
      goto out;
612
0
  }
613
614
0
  DEBUGASSERT(conn->cfilter[sockindex]);
615
0
out:
616
0
  if(result)
617
0
    Curl_resolv_unlink(data, &data->state.dns[sockindex]);
618
0
  return result;
619
0
}
620
621
void Curl_conn_set_multiplex(struct connectdata *conn)
622
0
{
623
0
  if(!conn->bits.multiplex) {
624
0
    conn->bits.multiplex = TRUE;
625
0
    if(conn->attached_multi) {
626
0
      Curl_multi_connchanged(conn->attached_multi);
627
0
    }
628
0
  }
629
0
}