Coverage Report

Created: 2025-08-11 09:23

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