Coverage Report

Created: 2026-04-12 06:56

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