Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/curl/lib/cf-socket.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 "bufq.h"
58
#include "sendf.h"
59
#include "if2ip.h"
60
#include "strerror.h"
61
#include "cfilters.h"
62
#include "cf-socket.h"
63
#include "connect.h"
64
#include "select.h"
65
#include "url.h" /* for Curl_safefree() */
66
#include "multiif.h"
67
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
68
#include "inet_ntop.h"
69
#include "inet_pton.h"
70
#include "progress.h"
71
#include "warnless.h"
72
#include "conncache.h"
73
#include "multihandle.h"
74
#include "rand.h"
75
#include "share.h"
76
#include "version_win32.h"
77
78
/* The last 3 #include files should be in this order */
79
#include "curl_printf.h"
80
#include "curl_memory.h"
81
#include "memdebug.h"
82
83
84
#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
85
/* It makes support for IPv4-mapped IPv6 addresses.
86
 * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
87
 * Windows Vista and later: default is on;
88
 * DragonFly BSD: acts like off, and dummy setting;
89
 * OpenBSD and earlier Windows: unsupported.
90
 * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
91
 */
92
static void set_ipv6_v6only(curl_socket_t sockfd, int on)
93
{
94
  (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
95
}
96
#else
97
#define set_ipv6_v6only(x,y)
98
#endif
99
100
static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
101
0
{
102
0
#if defined(TCP_NODELAY)
103
0
  curl_socklen_t onoff = (curl_socklen_t) 1;
104
0
  int level = IPPROTO_TCP;
105
0
  char buffer[STRERROR_LEN];
106
107
0
  if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
108
0
                sizeof(onoff)) < 0)
109
0
    infof(data, "Could not set TCP_NODELAY: %s",
110
0
          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
111
#else
112
  (void)data;
113
  (void)sockfd;
114
#endif
115
0
}
116
117
#ifdef SO_NOSIGPIPE
118
/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
119
   sending data to a dead peer (instead of relying on the 4th argument to send
120
   being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
121
   systems? */
122
static void nosigpipe(struct Curl_easy *data,
123
                      curl_socket_t sockfd)
124
{
125
  int onoff = 1;
126
  (void)data;
127
  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
128
                sizeof(onoff)) < 0) {
129
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
130
    char buffer[STRERROR_LEN];
131
    infof(data, "Could not set SO_NOSIGPIPE: %s",
132
          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
133
#endif
134
  }
135
}
136
#else
137
0
#define nosigpipe(x,y) Curl_nop_stmt
138
#endif
139
140
#if defined(__DragonFly__) || defined(USE_WINSOCK)
141
/* DragonFlyBSD and Windows use millisecond units */
142
#define KEEPALIVE_FACTOR(x) (x *= 1000)
143
#else
144
#define KEEPALIVE_FACTOR(x)
145
#endif
146
147
#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
148
#define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
149
150
struct tcp_keepalive {
151
  u_long onoff;
152
  u_long keepalivetime;
153
  u_long keepaliveinterval;
154
};
155
#endif
156
157
static void
158
tcpkeepalive(struct Curl_easy *data,
159
             curl_socket_t sockfd)
160
0
{
161
0
  int optval = data->set.tcp_keepalive?1:0;
162
163
  /* only set IDLE and INTVL if setting KEEPALIVE is successful */
164
0
  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
165
0
        (void *)&optval, sizeof(optval)) < 0) {
166
0
    infof(data, "Failed to set SO_KEEPALIVE on fd "
167
0
          "%" CURL_FORMAT_SOCKET_T ": errno %d",
168
0
          sockfd, SOCKERRNO);
169
0
  }
170
0
  else {
171
#if defined(SIO_KEEPALIVE_VALS)
172
    struct tcp_keepalive vals;
173
    DWORD dummy;
174
    vals.onoff = 1;
175
    optval = curlx_sltosi(data->set.tcp_keepidle);
176
    KEEPALIVE_FACTOR(optval);
177
    vals.keepalivetime = optval;
178
    optval = curlx_sltosi(data->set.tcp_keepintvl);
179
    KEEPALIVE_FACTOR(optval);
180
    vals.keepaliveinterval = optval;
181
    if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
182
                NULL, 0, &dummy, NULL, NULL) != 0) {
183
      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
184
                  "%" CURL_FORMAT_SOCKET_T ": errno %d",
185
                  sockfd, SOCKERRNO);
186
    }
187
#else
188
0
#ifdef TCP_KEEPIDLE
189
0
    optval = curlx_sltosi(data->set.tcp_keepidle);
190
0
    KEEPALIVE_FACTOR(optval);
191
0
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
192
0
          (void *)&optval, sizeof(optval)) < 0) {
193
0
      infof(data, "Failed to set TCP_KEEPIDLE on fd "
194
0
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
195
0
            sockfd, SOCKERRNO);
196
0
    }
197
#elif defined(TCP_KEEPALIVE)
198
    /* Mac OS X style */
199
    optval = curlx_sltosi(data->set.tcp_keepidle);
200
    KEEPALIVE_FACTOR(optval);
201
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
202
      (void *)&optval, sizeof(optval)) < 0) {
203
      infof(data, "Failed to set TCP_KEEPALIVE on fd "
204
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
205
            sockfd, SOCKERRNO);
206
    }
207
#endif
208
0
#ifdef TCP_KEEPINTVL
209
0
    optval = curlx_sltosi(data->set.tcp_keepintvl);
210
0
    KEEPALIVE_FACTOR(optval);
211
0
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
212
0
          (void *)&optval, sizeof(optval)) < 0) {
213
0
      infof(data, "Failed to set TCP_KEEPINTVL on fd "
214
0
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
215
0
            sockfd, SOCKERRNO);
216
0
    }
217
0
#endif
218
0
#endif
219
0
  }
220
0
}
221
222
/**
223
 * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
224
 * set the transport used.
225
 */
226
void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
227
                           const struct Curl_addrinfo *ai,
228
                           int transport)
229
0
{
230
  /*
231
   * The Curl_sockaddr_ex structure is basically libcurl's external API
232
   * curl_sockaddr structure with enough space available to directly hold
233
   * any protocol-specific address structures. The variable declared here
234
   * will be used to pass / receive data to/from the fopensocket callback
235
   * if this has been set, before that, it is initialized from parameters.
236
   */
237
0
  dest->family = ai->ai_family;
238
0
  switch(transport) {
239
0
  case TRNSPRT_TCP:
240
0
    dest->socktype = SOCK_STREAM;
241
0
    dest->protocol = IPPROTO_TCP;
242
0
    break;
243
0
  case TRNSPRT_UNIX:
244
0
    dest->socktype = SOCK_STREAM;
245
0
    dest->protocol = IPPROTO_IP;
246
0
    break;
247
0
  default: /* UDP and QUIC */
248
0
    dest->socktype = SOCK_DGRAM;
249
0
    dest->protocol = IPPROTO_UDP;
250
0
    break;
251
0
  }
252
0
  dest->addrlen = ai->ai_addrlen;
253
254
0
  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
255
0
    dest->addrlen = sizeof(struct Curl_sockaddr_storage);
256
0
  memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
257
0
}
258
259
static CURLcode socket_open(struct Curl_easy *data,
260
                            struct Curl_sockaddr_ex *addr,
261
                            curl_socket_t *sockfd)
262
0
{
263
0
  DEBUGASSERT(data);
264
0
  DEBUGASSERT(data->conn);
265
0
  if(data->set.fopensocket) {
266
   /*
267
    * If the opensocket callback is set, all the destination address
268
    * information is passed to the callback. Depending on this information the
269
    * callback may opt to abort the connection, this is indicated returning
270
    * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
271
    * the callback returns a valid socket the destination address information
272
    * might have been changed and this 'new' address will actually be used
273
    * here to connect.
274
    */
275
0
    Curl_set_in_callback(data, true);
276
0
    *sockfd = data->set.fopensocket(data->set.opensocket_client,
277
0
                                    CURLSOCKTYPE_IPCXN,
278
0
                                    (struct curl_sockaddr *)addr);
279
0
    Curl_set_in_callback(data, false);
280
0
  }
281
0
  else {
282
    /* opensocket callback not set, so simply create the socket now */
283
0
    *sockfd = socket(addr->family, addr->socktype, addr->protocol);
284
0
  }
285
286
0
  if(*sockfd == CURL_SOCKET_BAD)
287
    /* no socket, no connection */
288
0
    return CURLE_COULDNT_CONNECT;
289
290
0
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
291
0
  if(data->conn->scope_id && (addr->family == AF_INET6)) {
292
0
    struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
293
0
    sa6->sin6_scope_id = data->conn->scope_id;
294
0
  }
295
0
#endif
296
0
  return CURLE_OK;
297
0
}
298
299
/*
300
 * Create a socket based on info from 'conn' and 'ai'.
301
 *
302
 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
303
 * 'sockfd' must be a pointer to a socket descriptor.
304
 *
305
 * If the open socket callback is set, used that!
306
 *
307
 */
308
CURLcode Curl_socket_open(struct Curl_easy *data,
309
                            const struct Curl_addrinfo *ai,
310
                            struct Curl_sockaddr_ex *addr,
311
                            int transport,
312
                            curl_socket_t *sockfd)
313
0
{
314
0
  struct Curl_sockaddr_ex dummy;
315
316
0
  if(!addr)
317
    /* if the caller doesn't want info back, use a local temp copy */
318
0
    addr = &dummy;
319
320
0
  Curl_sock_assign_addr(addr, ai, transport);
321
0
  return socket_open(data, addr, sockfd);
322
0
}
323
324
static int socket_close(struct Curl_easy *data, struct connectdata *conn,
325
                        int use_callback, curl_socket_t sock)
326
0
{
327
0
  if(use_callback && conn && conn->fclosesocket) {
328
0
    int rc;
329
0
    Curl_multi_closed(data, sock);
330
0
    Curl_set_in_callback(data, true);
331
0
    rc = conn->fclosesocket(conn->closesocket_client, sock);
332
0
    Curl_set_in_callback(data, false);
333
0
    return rc;
334
0
  }
335
336
0
  if(conn)
337
    /* tell the multi-socket code about this */
338
0
    Curl_multi_closed(data, sock);
339
340
0
  sclose(sock);
341
342
0
  return 0;
343
0
}
344
345
/*
346
 * Close a socket.
347
 *
348
 * 'conn' can be NULL, beware!
349
 */
350
int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
351
                      curl_socket_t sock)
352
0
{
353
0
  return socket_close(data, conn, FALSE, sock);
354
0
}
355
356
#ifdef USE_WINSOCK
357
/* When you run a program that uses the Windows Sockets API, you may
358
   experience slow performance when you copy data to a TCP server.
359
360
   https://support.microsoft.com/kb/823764
361
362
   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
363
   Buffer Size
364
365
   The problem described in this knowledge-base is applied only to pre-Vista
366
   Windows.  Following function trying to detect OS version and skips
367
   SO_SNDBUF adjustment for Windows Vista and above.
368
*/
369
#define DETECT_OS_NONE 0
370
#define DETECT_OS_PREVISTA 1
371
#define DETECT_OS_VISTA_OR_LATER 2
372
373
void Curl_sndbufset(curl_socket_t sockfd)
374
{
375
  int val = CURL_MAX_WRITE_SIZE + 32;
376
  int curval = 0;
377
  int curlen = sizeof(curval);
378
379
  static int detectOsState = DETECT_OS_NONE;
380
381
  if(detectOsState == DETECT_OS_NONE) {
382
    if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
383
                                    VERSION_GREATER_THAN_EQUAL))
384
      detectOsState = DETECT_OS_VISTA_OR_LATER;
385
    else
386
      detectOsState = DETECT_OS_PREVISTA;
387
  }
388
389
  if(detectOsState == DETECT_OS_VISTA_OR_LATER)
390
    return;
391
392
  if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
393
    if(curval > val)
394
      return;
395
396
  setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
397
}
398
#endif
399
400
#ifndef CURL_DISABLE_BINDLOCAL
401
static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
402
                          curl_socket_t sockfd, int af, unsigned int scope)
403
0
{
404
0
  struct Curl_sockaddr_storage sa;
405
0
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
406
0
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
407
0
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
408
0
#ifdef ENABLE_IPV6
409
0
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
410
0
#endif
411
412
0
  struct Curl_dns_entry *h = NULL;
413
0
  unsigned short port = data->set.localport; /* use this port number, 0 for
414
                                                "random" */
415
  /* how many port numbers to try to bind to, increasing one at a time */
416
0
  int portnum = data->set.localportrange;
417
0
  const char *dev = data->set.str[STRING_DEVICE];
418
0
  int error;
419
0
#ifdef IP_BIND_ADDRESS_NO_PORT
420
0
  int on = 1;
421
0
#endif
422
#ifndef ENABLE_IPV6
423
  (void)scope;
424
#endif
425
426
  /*************************************************************
427
   * Select device to bind socket to
428
   *************************************************************/
429
0
  if(!dev && !port)
430
    /* no local kind of binding was requested */
431
0
    return CURLE_OK;
432
433
0
  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
434
435
0
  if(dev && (strlen(dev)<255) ) {
436
0
    char myhost[256] = "";
437
0
    int done = 0; /* -1 for error, 1 for address found */
438
0
    bool is_interface = FALSE;
439
0
    bool is_host = FALSE;
440
0
    static const char *if_prefix = "if!";
441
0
    static const char *host_prefix = "host!";
442
443
0
    if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
444
0
      dev += strlen(if_prefix);
445
0
      is_interface = TRUE;
446
0
    }
447
0
    else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
448
0
      dev += strlen(host_prefix);
449
0
      is_host = TRUE;
450
0
    }
451
452
    /* interface */
453
0
    if(!is_host) {
454
0
#ifdef SO_BINDTODEVICE
455
      /*
456
       * This binds the local socket to a particular interface. This will
457
       * force even requests to other local interfaces to go out the external
458
       * interface. Only bind to the interface when specified as interface,
459
       * not just as a hostname or ip address.
460
       *
461
       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
462
       * converted to an IP address and would fail Curl_if2ip. Simply try to
463
       * use it straight away.
464
       */
465
0
      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
466
0
                    dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
467
        /* This is often "errno 1, error: Operation not permitted" if you're
468
         * not running as root or another suitable privileged user. If it
469
         * succeeds it means the parameter was a valid interface and not an IP
470
         * address. Return immediately.
471
         */
472
0
        infof(data, "socket successfully bound to interface '%s'", dev);
473
0
        return CURLE_OK;
474
0
      }
475
0
#endif
476
477
0
      switch(Curl_if2ip(af,
478
0
#ifdef ENABLE_IPV6
479
0
                        scope, conn->scope_id,
480
0
#endif
481
0
                        dev, myhost, sizeof(myhost))) {
482
0
        case IF2IP_NOT_FOUND:
483
0
          if(is_interface) {
484
            /* Do not fall back to treating it as a host name */
485
0
            failf(data, "Couldn't bind to interface '%s'", dev);
486
0
            return CURLE_INTERFACE_FAILED;
487
0
          }
488
0
          break;
489
0
        case IF2IP_AF_NOT_SUPPORTED:
490
          /* Signal the caller to try another address family if available */
491
0
          return CURLE_UNSUPPORTED_PROTOCOL;
492
0
        case IF2IP_FOUND:
493
0
          is_interface = TRUE;
494
          /*
495
           * We now have the numerical IP address in the 'myhost' buffer
496
           */
497
0
          infof(data, "Local Interface %s is ip %s using address family %i",
498
0
                dev, myhost, af);
499
0
          done = 1;
500
0
          break;
501
0
      }
502
0
    }
503
0
    if(!is_interface) {
504
      /*
505
       * This was not an interface, resolve the name as a host name
506
       * or IP number
507
       *
508
       * Temporarily force name resolution to use only the address type
509
       * of the connection. The resolve functions should really be changed
510
       * to take a type parameter instead.
511
       */
512
0
      unsigned char ipver = conn->ip_version;
513
0
      int rc;
514
515
0
      if(af == AF_INET)
516
0
        conn->ip_version = CURL_IPRESOLVE_V4;
517
0
#ifdef ENABLE_IPV6
518
0
      else if(af == AF_INET6)
519
0
        conn->ip_version = CURL_IPRESOLVE_V6;
520
0
#endif
521
522
0
      rc = Curl_resolv(data, dev, 80, FALSE, &h);
523
0
      if(rc == CURLRESOLV_PENDING)
524
0
        (void)Curl_resolver_wait_resolv(data, &h);
525
0
      conn->ip_version = ipver;
526
527
0
      if(h) {
528
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
529
0
        Curl_printable_address(h->addr, myhost, sizeof(myhost));
530
0
        infof(data, "Name '%s' family %i resolved to '%s' family %i",
531
0
              dev, af, myhost, h->addr->ai_family);
532
0
        Curl_resolv_unlock(data, h);
533
0
        if(af != h->addr->ai_family) {
534
          /* bad IP version combo, signal the caller to try another address
535
             family if available */
536
0
          return CURLE_UNSUPPORTED_PROTOCOL;
537
0
        }
538
0
        done = 1;
539
0
      }
540
0
      else {
541
        /*
542
         * provided dev was no interface (or interfaces are not supported
543
         * e.g. solaris) no ip address and no domain we fail here
544
         */
545
0
        done = -1;
546
0
      }
547
0
    }
548
549
0
    if(done > 0) {
550
0
#ifdef ENABLE_IPV6
551
      /* IPv6 address */
552
0
      if(af == AF_INET6) {
553
0
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
554
0
        char *scope_ptr = strchr(myhost, '%');
555
0
        if(scope_ptr)
556
0
          *(scope_ptr++) = '\0';
557
0
#endif
558
0
        if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
559
0
          si6->sin6_family = AF_INET6;
560
0
          si6->sin6_port = htons(port);
561
0
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
562
0
          if(scope_ptr) {
563
            /* The "myhost" string either comes from Curl_if2ip or from
564
               Curl_printable_address. The latter returns only numeric scope
565
               IDs and the former returns none at all.  So the scope ID, if
566
               present, is known to be numeric */
567
0
            unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
568
0
            if(scope_id > UINT_MAX)
569
0
              return CURLE_UNSUPPORTED_PROTOCOL;
570
571
0
            si6->sin6_scope_id = (unsigned int)scope_id;
572
0
          }
573
0
#endif
574
0
        }
575
0
        sizeof_sa = sizeof(struct sockaddr_in6);
576
0
      }
577
0
      else
578
0
#endif
579
      /* IPv4 address */
580
0
      if((af == AF_INET) &&
581
0
         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
582
0
        si4->sin_family = AF_INET;
583
0
        si4->sin_port = htons(port);
584
0
        sizeof_sa = sizeof(struct sockaddr_in);
585
0
      }
586
0
    }
587
588
0
    if(done < 1) {
589
      /* errorbuf is set false so failf will overwrite any message already in
590
         the error buffer, so the user receives this error message instead of a
591
         generic resolve error. */
592
0
      data->state.errorbuf = FALSE;
593
0
      failf(data, "Couldn't bind to '%s'", dev);
594
0
      return CURLE_INTERFACE_FAILED;
595
0
    }
596
0
  }
597
0
  else {
598
    /* no device was given, prepare sa to match af's needs */
599
0
#ifdef ENABLE_IPV6
600
0
    if(af == AF_INET6) {
601
0
      si6->sin6_family = AF_INET6;
602
0
      si6->sin6_port = htons(port);
603
0
      sizeof_sa = sizeof(struct sockaddr_in6);
604
0
    }
605
0
    else
606
0
#endif
607
0
    if(af == AF_INET) {
608
0
      si4->sin_family = AF_INET;
609
0
      si4->sin_port = htons(port);
610
0
      sizeof_sa = sizeof(struct sockaddr_in);
611
0
    }
612
0
  }
613
0
#ifdef IP_BIND_ADDRESS_NO_PORT
614
0
  (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
615
0
#endif
616
0
  for(;;) {
617
0
    if(bind(sockfd, sock, sizeof_sa) >= 0) {
618
      /* we succeeded to bind */
619
0
      struct Curl_sockaddr_storage add;
620
0
      curl_socklen_t size = sizeof(add);
621
0
      memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
622
0
      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
623
0
        char buffer[STRERROR_LEN];
624
0
        data->state.os_errno = error = SOCKERRNO;
625
0
        failf(data, "getsockname() failed with errno %d: %s",
626
0
              error, Curl_strerror(error, buffer, sizeof(buffer)));
627
0
        return CURLE_INTERFACE_FAILED;
628
0
      }
629
0
      infof(data, "Local port: %hu", port);
630
0
      conn->bits.bound = TRUE;
631
0
      return CURLE_OK;
632
0
    }
633
634
0
    if(--portnum > 0) {
635
0
      port++; /* try next port */
636
0
      if(port == 0)
637
0
        break;
638
0
      infof(data, "Bind to local port %d failed, trying next", port - 1);
639
      /* We reuse/clobber the port variable here below */
640
0
      if(sock->sa_family == AF_INET)
641
0
        si4->sin_port = ntohs(port);
642
0
#ifdef ENABLE_IPV6
643
0
      else
644
0
        si6->sin6_port = ntohs(port);
645
0
#endif
646
0
    }
647
0
    else
648
0
      break;
649
0
  }
650
0
  {
651
0
    char buffer[STRERROR_LEN];
652
0
    data->state.os_errno = error = SOCKERRNO;
653
0
    failf(data, "bind failed with errno %d: %s",
654
0
          error, Curl_strerror(error, buffer, sizeof(buffer)));
655
0
  }
656
657
0
  return CURLE_INTERFACE_FAILED;
658
0
}
659
#endif
660
661
/*
662
 * verifyconnect() returns TRUE if the connect really has happened.
663
 */
664
static bool verifyconnect(curl_socket_t sockfd, int *error)
665
0
{
666
0
  bool rc = TRUE;
667
0
#ifdef SO_ERROR
668
0
  int err = 0;
669
0
  curl_socklen_t errSize = sizeof(err);
670
671
#ifdef _WIN32
672
  /*
673
   * In October 2003 we effectively nullified this function on Windows due to
674
   * problems with it using all CPU in multi-threaded cases.
675
   *
676
   * In May 2004, we bring it back to offer more info back on connect failures.
677
   * Gisle Vanem could reproduce the former problems with this function, but
678
   * could avoid them by adding this SleepEx() call below:
679
   *
680
   *    "I don't have Rational Quantify, but the hint from his post was
681
   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
682
   *    just Sleep(0) would be enough?) would release whatever
683
   *    mutex/critical-section the ntdll call is waiting on.
684
   *
685
   *    Someone got to verify this on Win-NT 4.0, 2000."
686
   */
687
688
#ifdef _WIN32_WCE
689
  Sleep(0);
690
#else
691
  SleepEx(0, FALSE);
692
#endif
693
694
#endif
695
696
0
  if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
697
0
    err = SOCKERRNO;
698
#ifdef _WIN32_WCE
699
  /* Old WinCE versions don't support SO_ERROR */
700
  if(WSAENOPROTOOPT == err) {
701
    SET_SOCKERRNO(0);
702
    err = 0;
703
  }
704
#endif
705
#if defined(EBADIOCTL) && defined(__minix)
706
  /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
707
  if(EBADIOCTL == err) {
708
    SET_SOCKERRNO(0);
709
    err = 0;
710
  }
711
#endif
712
0
  if((0 == err) || (EISCONN == err))
713
    /* we are connected, awesome! */
714
0
    rc = TRUE;
715
0
  else
716
    /* This wasn't a successful connect */
717
0
    rc = FALSE;
718
0
  if(error)
719
0
    *error = err;
720
#else
721
  (void)sockfd;
722
  if(error)
723
    *error = SOCKERRNO;
724
#endif
725
0
  return rc;
726
0
}
727
728
/**
729
 * Determine the curl code for a socket connect() == -1 with errno.
730
 */
731
static CURLcode socket_connect_result(struct Curl_easy *data,
732
                                      const char *ipaddress, int error)
733
0
{
734
0
  switch(error) {
735
0
  case EINPROGRESS:
736
0
  case EWOULDBLOCK:
737
0
#if defined(EAGAIN)
738
#if (EAGAIN) != (EWOULDBLOCK)
739
    /* On some platforms EAGAIN and EWOULDBLOCK are the
740
     * same value, and on others they are different, hence
741
     * the odd #if
742
     */
743
  case EAGAIN:
744
#endif
745
0
#endif
746
0
    return CURLE_OK;
747
748
0
  default:
749
    /* unknown error, fallthrough and try another address! */
750
#ifdef CURL_DISABLE_VERBOSE_STRINGS
751
    (void)ipaddress;
752
#else
753
0
    {
754
0
      char buffer[STRERROR_LEN];
755
0
      infof(data, "Immediate connect fail for %s: %s",
756
0
            ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
757
0
    }
758
0
#endif
759
0
    data->state.os_errno = error;
760
    /* connect failed */
761
0
    return CURLE_COULDNT_CONNECT;
762
0
  }
763
0
}
764
765
/* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
766
 * This happens often on TLS connections where the TLS implementation
767
 * tries to read the head of a TLS record, determine the length of the
768
 * full record and then make a subsequent read for that.
769
 * On large reads, we will not fill the buffer to avoid the double copy. */
770
0
#define NW_RECV_CHUNK_SIZE    (64 * 1024)
771
0
#define NW_RECV_CHUNKS         1
772
0
#define NW_SMALL_READS        (1024)
773
774
struct cf_socket_ctx {
775
  int transport;
776
  struct Curl_sockaddr_ex addr;      /* address to connect to */
777
  curl_socket_t sock;                /* current attempt socket */
778
  struct bufq recvbuf;               /* used when `buffer_recv` is set */
779
  char r_ip[MAX_IPADR_LEN];          /* remote IP as string */
780
  int r_port;                        /* remote port number */
781
  char l_ip[MAX_IPADR_LEN];          /* local IP as string */
782
  int l_port;                        /* local port number */
783
  struct curltime started_at;        /* when socket was created */
784
  struct curltime connected_at;      /* when socket connected/got first byte */
785
  struct curltime first_byte_at;     /* when first byte was recvd */
786
  int error;                         /* errno of last failure or 0 */
787
#ifdef DEBUGBUILD
788
  int wblock_percent;                /* percent of writes doing EAGAIN */
789
  int wpartial_percent;              /* percent of bytes written in send */
790
  int rblock_percent;                /* percent of reads doing EAGAIN */
791
  size_t recv_max;                  /* max enforced read size */
792
#endif
793
  BIT(got_first_byte);               /* if first byte was received */
794
  BIT(accepted);                     /* socket was accepted, not connected */
795
  BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
796
  BIT(active);
797
  BIT(buffer_recv);
798
};
799
800
static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
801
                               const struct Curl_addrinfo *ai,
802
                               int transport)
803
0
{
804
0
  memset(ctx, 0, sizeof(*ctx));
805
0
  ctx->sock = CURL_SOCKET_BAD;
806
0
  ctx->transport = transport;
807
0
  Curl_sock_assign_addr(&ctx->addr, ai, transport);
808
0
  Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
809
#ifdef DEBUGBUILD
810
  {
811
    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
812
    if(p) {
813
      long l = strtol(p, NULL, 10);
814
      if(l >= 0 && l <= 100)
815
        ctx->wblock_percent = (int)l;
816
    }
817
    p = getenv("CURL_DBG_SOCK_WPARTIAL");
818
    if(p) {
819
      long l = strtol(p, NULL, 10);
820
      if(l >= 0 && l <= 100)
821
        ctx->wpartial_percent = (int)l;
822
    }
823
    p = getenv("CURL_DBG_SOCK_RBLOCK");
824
    if(p) {
825
      long l = strtol(p, NULL, 10);
826
      if(l >= 0 && l <= 100)
827
        ctx->rblock_percent = (int)l;
828
    }
829
    p = getenv("CURL_DBG_SOCK_RMAX");
830
    if(p) {
831
      long l = strtol(p, NULL, 10);
832
      if(l >= 0)
833
        ctx->recv_max = (size_t)l;
834
    }
835
  }
836
#endif
837
0
}
838
839
struct reader_ctx {
840
  struct Curl_cfilter *cf;
841
  struct Curl_easy *data;
842
};
843
844
static ssize_t nw_in_read(void *reader_ctx,
845
                           unsigned char *buf, size_t len,
846
                           CURLcode *err)
847
0
{
848
0
  struct reader_ctx *rctx = reader_ctx;
849
0
  struct cf_socket_ctx *ctx = rctx->cf->ctx;
850
0
  ssize_t nread;
851
852
0
  *err = CURLE_OK;
853
0
  nread = sread(ctx->sock, buf, len);
854
855
0
  if(-1 == nread) {
856
0
    int sockerr = SOCKERRNO;
857
858
0
    if(
859
#ifdef WSAEWOULDBLOCK
860
      /* This is how Windows does it */
861
      (WSAEWOULDBLOCK == sockerr)
862
#else
863
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
864
         due to its inability to send off data without blocking. We therefore
865
         treat both error codes the same here */
866
0
      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
867
0
#endif
868
0
      ) {
869
      /* this is just a case of EWOULDBLOCK */
870
0
      *err = CURLE_AGAIN;
871
0
      nread = -1;
872
0
    }
873
0
    else {
874
0
      char buffer[STRERROR_LEN];
875
876
0
      failf(rctx->data, "Recv failure: %s",
877
0
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
878
0
      rctx->data->state.os_errno = sockerr;
879
0
      *err = CURLE_RECV_ERROR;
880
0
      nread = -1;
881
0
    }
882
0
  }
883
0
  CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu, fd=%"
884
0
              CURL_FORMAT_SOCKET_T ") -> %d, err=%d",
885
0
              len, ctx->sock, (int)nread, *err);
886
0
  return nread;
887
0
}
888
889
static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
890
0
{
891
0
  struct cf_socket_ctx *ctx = cf->ctx;
892
893
0
  if(ctx && CURL_SOCKET_BAD != ctx->sock) {
894
0
    CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
895
0
                ")", ctx->sock);
896
0
    if(ctx->sock == cf->conn->sock[cf->sockindex])
897
0
      cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
898
0
    socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
899
0
    ctx->sock = CURL_SOCKET_BAD;
900
0
    if(ctx->active && cf->sockindex == FIRSTSOCKET)
901
0
      cf->conn->remote_addr = NULL;
902
0
    Curl_bufq_reset(&ctx->recvbuf);
903
0
    ctx->active = FALSE;
904
0
    ctx->buffer_recv = FALSE;
905
0
    memset(&ctx->started_at, 0, sizeof(ctx->started_at));
906
0
    memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
907
0
  }
908
909
0
  cf->connected = FALSE;
910
0
}
911
912
static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
913
0
{
914
0
  struct cf_socket_ctx *ctx = cf->ctx;
915
916
0
  cf_socket_close(cf, data);
917
0
  CURL_TRC_CF(data, cf, "destroy");
918
0
  Curl_bufq_free(&ctx->recvbuf);
919
0
  free(ctx);
920
0
  cf->ctx = NULL;
921
0
}
922
923
static CURLcode set_local_ip(struct Curl_cfilter *cf,
924
                             struct Curl_easy *data)
925
0
{
926
0
  struct cf_socket_ctx *ctx = cf->ctx;
927
928
0
#ifdef HAVE_GETSOCKNAME
929
0
  if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
930
    /* TFTP does not connect, so it cannot get the IP like this */
931
932
0
    char buffer[STRERROR_LEN];
933
0
    struct Curl_sockaddr_storage ssloc;
934
0
    curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
935
936
0
    memset(&ssloc, 0, sizeof(ssloc));
937
0
    if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
938
0
      int error = SOCKERRNO;
939
0
      failf(data, "getsockname() failed with errno %d: %s",
940
0
            error, Curl_strerror(error, buffer, sizeof(buffer)));
941
0
      return CURLE_FAILED_INIT;
942
0
    }
943
0
    if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
944
0
                         ctx->l_ip, &ctx->l_port)) {
945
0
      failf(data, "ssloc inet_ntop() failed with errno %d: %s",
946
0
            errno, Curl_strerror(errno, buffer, sizeof(buffer)));
947
0
      return CURLE_FAILED_INIT;
948
0
    }
949
0
  }
950
#else
951
  (void)data;
952
  ctx->l_ip[0] = 0;
953
  ctx->l_port = -1;
954
#endif
955
0
  return CURLE_OK;
956
0
}
957
958
static CURLcode set_remote_ip(struct Curl_cfilter *cf,
959
                              struct Curl_easy *data)
960
0
{
961
0
  struct cf_socket_ctx *ctx = cf->ctx;
962
963
  /* store remote address and port used in this connection attempt */
964
0
  if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
965
0
                       ctx->r_ip, &ctx->r_port)) {
966
0
    char buffer[STRERROR_LEN];
967
968
0
    ctx->error = errno;
969
    /* malformed address or bug in inet_ntop, try next address */
970
0
    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
971
0
          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
972
0
    return CURLE_FAILED_INIT;
973
0
  }
974
0
  return CURLE_OK;
975
0
}
976
977
static CURLcode cf_socket_open(struct Curl_cfilter *cf,
978
                              struct Curl_easy *data)
979
0
{
980
0
  struct cf_socket_ctx *ctx = cf->ctx;
981
0
  int error = 0;
982
0
  bool isconnected = FALSE;
983
0
  CURLcode result = CURLE_COULDNT_CONNECT;
984
0
  bool is_tcp;
985
986
0
  (void)data;
987
0
  DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
988
0
  ctx->started_at = Curl_now();
989
0
  result = socket_open(data, &ctx->addr, &ctx->sock);
990
0
  if(result)
991
0
    goto out;
992
993
0
  result = set_remote_ip(cf, data);
994
0
  if(result)
995
0
    goto out;
996
997
0
#ifdef ENABLE_IPV6
998
0
  if(ctx->addr.family == AF_INET6) {
999
0
    set_ipv6_v6only(ctx->sock, 0);
1000
0
    infof(data, "  Trying [%s]:%d...", ctx->r_ip, ctx->r_port);
1001
0
  }
1002
0
  else
1003
0
#endif
1004
0
    infof(data, "  Trying %s:%d...", ctx->r_ip, ctx->r_port);
1005
1006
0
#ifdef ENABLE_IPV6
1007
0
  is_tcp = (ctx->addr.family == AF_INET
1008
0
            || ctx->addr.family == AF_INET6) &&
1009
0
           ctx->addr.socktype == SOCK_STREAM;
1010
#else
1011
  is_tcp = (ctx->addr.family == AF_INET) &&
1012
           ctx->addr.socktype == SOCK_STREAM;
1013
#endif
1014
0
  if(is_tcp && data->set.tcp_nodelay)
1015
0
    tcpnodelay(data, ctx->sock);
1016
1017
0
  nosigpipe(data, ctx->sock);
1018
1019
0
  Curl_sndbufset(ctx->sock);
1020
1021
0
  if(is_tcp && data->set.tcp_keepalive)
1022
0
    tcpkeepalive(data, ctx->sock);
1023
1024
0
  if(data->set.fsockopt) {
1025
    /* activate callback for setting socket options */
1026
0
    Curl_set_in_callback(data, true);
1027
0
    error = data->set.fsockopt(data->set.sockopt_client,
1028
0
                               ctx->sock,
1029
0
                               CURLSOCKTYPE_IPCXN);
1030
0
    Curl_set_in_callback(data, false);
1031
1032
0
    if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1033
0
      isconnected = TRUE;
1034
0
    else if(error) {
1035
0
      result = CURLE_ABORTED_BY_CALLBACK;
1036
0
      goto out;
1037
0
    }
1038
0
  }
1039
1040
0
#ifndef CURL_DISABLE_BINDLOCAL
1041
  /* possibly bind the local end to an IP, interface or port */
1042
0
  if(ctx->addr.family == AF_INET
1043
0
#ifdef ENABLE_IPV6
1044
0
     || ctx->addr.family == AF_INET6
1045
0
#endif
1046
0
    ) {
1047
0
    result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1048
0
                       Curl_ipv6_scope(&ctx->addr.sa_addr));
1049
0
    if(result) {
1050
0
      if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1051
        /* The address family is not supported on this interface.
1052
           We can continue trying addresses */
1053
0
        result = CURLE_COULDNT_CONNECT;
1054
0
      }
1055
0
      goto out;
1056
0
    }
1057
0
  }
1058
0
#endif
1059
1060
  /* set socket non-blocking */
1061
0
  (void)curlx_nonblock(ctx->sock, TRUE);
1062
0
  ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1063
0
out:
1064
0
  if(result) {
1065
0
    if(ctx->sock != CURL_SOCKET_BAD) {
1066
0
      socket_close(data, cf->conn, TRUE, ctx->sock);
1067
0
      ctx->sock = CURL_SOCKET_BAD;
1068
0
    }
1069
0
  }
1070
0
  else if(isconnected) {
1071
0
    set_local_ip(cf, data);
1072
0
    ctx->connected_at = Curl_now();
1073
0
    cf->connected = TRUE;
1074
0
  }
1075
0
  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
1076
0
              result, ctx->sock);
1077
0
  return result;
1078
0
}
1079
1080
static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1081
                      bool is_tcp_fastopen)
1082
0
{
1083
0
  struct cf_socket_ctx *ctx = cf->ctx;
1084
0
#ifdef TCP_FASTOPEN_CONNECT
1085
0
  int optval = 1;
1086
0
#endif
1087
0
  int rc = -1;
1088
1089
0
  (void)data;
1090
0
  if(is_tcp_fastopen) {
1091
#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1092
#  if defined(HAVE_BUILTIN_AVAILABLE)
1093
    /* while connectx function is available since macOS 10.11 / iOS 9,
1094
       it did not have the interface declared correctly until
1095
       Xcode 9 / macOS SDK 10.13 */
1096
    if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1097
      sa_endpoints_t endpoints;
1098
      endpoints.sae_srcif = 0;
1099
      endpoints.sae_srcaddr = NULL;
1100
      endpoints.sae_srcaddrlen = 0;
1101
      endpoints.sae_dstaddr = &ctx->addr.sa_addr;
1102
      endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1103
1104
      rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1105
                    CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1106
                    NULL, 0, NULL, NULL);
1107
    }
1108
    else {
1109
      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1110
    }
1111
#  else
1112
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1113
#  endif /* HAVE_BUILTIN_AVAILABLE */
1114
#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1115
0
    if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1116
0
                  (void *)&optval, sizeof(optval)) < 0)
1117
0
      infof(data, "Failed to enable TCP Fast Open on fd %"
1118
0
            CURL_FORMAT_SOCKET_T, ctx->sock);
1119
1120
0
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1121
#elif defined(MSG_FASTOPEN) /* old Linux */
1122
    if(cf->conn->given->flags & PROTOPT_SSL)
1123
      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1124
    else
1125
      rc = 0; /* Do nothing */
1126
#endif
1127
0
  }
1128
0
  else {
1129
0
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1130
0
  }
1131
0
  return rc;
1132
0
}
1133
1134
static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1135
                               struct Curl_easy *data,
1136
                               bool blocking, bool *done)
1137
0
{
1138
0
  struct cf_socket_ctx *ctx = cf->ctx;
1139
0
  CURLcode result = CURLE_COULDNT_CONNECT;
1140
0
  int rc = 0;
1141
1142
0
  (void)data;
1143
0
  if(cf->connected) {
1144
0
    *done = TRUE;
1145
0
    return CURLE_OK;
1146
0
  }
1147
1148
  /* TODO: need to support blocking connect? */
1149
0
  if(blocking)
1150
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1151
1152
0
  *done = FALSE; /* a very negative world view is best */
1153
0
  if(ctx->sock == CURL_SOCKET_BAD) {
1154
0
    int error;
1155
1156
0
    result = cf_socket_open(cf, data);
1157
0
    if(result)
1158
0
      goto out;
1159
1160
0
    if(cf->connected) {
1161
0
      *done = TRUE;
1162
0
      return CURLE_OK;
1163
0
    }
1164
1165
    /* Connect TCP socket */
1166
0
    rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1167
0
    error = SOCKERRNO;
1168
0
    set_local_ip(cf, data);
1169
0
    CURL_TRC_CF(data, cf, "local address %s port %d...",
1170
0
                ctx->l_ip, ctx->l_port);
1171
0
    if(-1 == rc) {
1172
0
      result = socket_connect_result(data, ctx->r_ip, error);
1173
0
      goto out;
1174
0
    }
1175
0
  }
1176
1177
#ifdef mpeix
1178
  /* Call this function once now, and ignore the results. We do this to
1179
     "clear" the error state on the socket so that we can later read it
1180
     reliably. This is reported necessary on the MPE/iX operating
1181
     system. */
1182
  (void)verifyconnect(ctx->sock, NULL);
1183
#endif
1184
  /* check socket for connect */
1185
0
  rc = SOCKET_WRITABLE(ctx->sock, 0);
1186
1187
0
  if(rc == 0) { /* no connection yet */
1188
0
    CURL_TRC_CF(data, cf, "not connected yet");
1189
0
    return CURLE_OK;
1190
0
  }
1191
0
  else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1192
0
    if(verifyconnect(ctx->sock, &ctx->error)) {
1193
      /* we are connected with TCP, awesome! */
1194
0
      ctx->connected_at = Curl_now();
1195
0
      set_local_ip(cf, data);
1196
0
      *done = TRUE;
1197
0
      cf->connected = TRUE;
1198
0
      CURL_TRC_CF(data, cf, "connected");
1199
0
      return CURLE_OK;
1200
0
    }
1201
0
  }
1202
0
  else if(rc & CURL_CSELECT_ERR) {
1203
0
    (void)verifyconnect(ctx->sock, &ctx->error);
1204
0
    result = CURLE_COULDNT_CONNECT;
1205
0
  }
1206
1207
0
out:
1208
0
  if(result) {
1209
0
    if(ctx->error) {
1210
0
      set_local_ip(cf, data);
1211
0
      data->state.os_errno = ctx->error;
1212
0
      SET_SOCKERRNO(ctx->error);
1213
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1214
0
      {
1215
0
        char buffer[STRERROR_LEN];
1216
0
        infof(data, "connect to %s port %u from %s port %d failed: %s",
1217
0
              ctx->r_ip, ctx->r_port, ctx->l_ip, ctx->l_port,
1218
0
              Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1219
0
      }
1220
0
#endif
1221
0
    }
1222
0
    if(ctx->sock != CURL_SOCKET_BAD) {
1223
0
      socket_close(data, cf->conn, TRUE, ctx->sock);
1224
0
      ctx->sock = CURL_SOCKET_BAD;
1225
0
    }
1226
0
    *done = FALSE;
1227
0
  }
1228
0
  return result;
1229
0
}
1230
1231
static void cf_socket_get_host(struct Curl_cfilter *cf,
1232
                               struct Curl_easy *data,
1233
                               const char **phost,
1234
                               const char **pdisplay_host,
1235
                               int *pport)
1236
0
{
1237
0
  (void)data;
1238
0
  *phost = cf->conn->host.name;
1239
0
  *pdisplay_host = cf->conn->host.dispname;
1240
0
  *pport = cf->conn->port;
1241
0
}
1242
1243
static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1244
                                      struct Curl_easy *data,
1245
                                      struct easy_pollset *ps)
1246
0
{
1247
0
  struct cf_socket_ctx *ctx = cf->ctx;
1248
1249
0
  if(ctx->sock != CURL_SOCKET_BAD) {
1250
0
    if(!cf->connected) {
1251
0
      Curl_pollset_set_out_only(data, ps, ctx->sock);
1252
0
      CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1253
0
                  CURL_FORMAT_SOCKET_T, ctx->sock);
1254
0
    }
1255
0
    else if(!ctx->active) {
1256
0
      Curl_pollset_add_in(data, ps, ctx->sock);
1257
0
      CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1258
0
                  CURL_FORMAT_SOCKET_T, ctx->sock);
1259
0
    }
1260
0
  }
1261
0
}
1262
1263
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1264
                                   const struct Curl_easy *data)
1265
0
{
1266
0
  struct cf_socket_ctx *ctx = cf->ctx;
1267
0
  int readable;
1268
1269
0
  (void)data;
1270
0
  if(!Curl_bufq_is_empty(&ctx->recvbuf))
1271
0
    return TRUE;
1272
1273
0
  readable = SOCKET_READABLE(ctx->sock, 0);
1274
0
  return (readable > 0 && (readable & CURL_CSELECT_IN));
1275
0
}
1276
1277
static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1278
                              const void *buf, size_t len, CURLcode *err)
1279
0
{
1280
0
  struct cf_socket_ctx *ctx = cf->ctx;
1281
0
  curl_socket_t fdsave;
1282
0
  ssize_t nwritten;
1283
0
  size_t orig_len = len;
1284
1285
0
  *err = CURLE_OK;
1286
0
  fdsave = cf->conn->sock[cf->sockindex];
1287
0
  cf->conn->sock[cf->sockindex] = ctx->sock;
1288
1289
#ifdef DEBUGBUILD
1290
  /* simulate network blocking/partial writes */
1291
  if(ctx->wblock_percent > 0) {
1292
    unsigned char c;
1293
    Curl_rand(data, &c, 1);
1294
    if(c >= ((100-ctx->wblock_percent)*256/100)) {
1295
      CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1296
      *err = CURLE_AGAIN;
1297
      nwritten = -1;
1298
      cf->conn->sock[cf->sockindex] = fdsave;
1299
      return nwritten;
1300
    }
1301
  }
1302
  if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1303
    len = len * ctx->wpartial_percent / 100;
1304
    if(!len)
1305
      len = 1;
1306
    CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1307
                orig_len, len);
1308
  }
1309
#endif
1310
1311
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1312
  if(cf->conn->bits.tcp_fastopen) {
1313
    nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1314
                      &cf->conn->remote_addr->sa_addr,
1315
                      cf->conn->remote_addr->addrlen);
1316
    cf->conn->bits.tcp_fastopen = FALSE;
1317
  }
1318
  else
1319
#endif
1320
0
    nwritten = swrite(ctx->sock, buf, len);
1321
1322
0
  if(-1 == nwritten) {
1323
0
    int sockerr = SOCKERRNO;
1324
1325
0
    if(
1326
#ifdef WSAEWOULDBLOCK
1327
      /* This is how Windows does it */
1328
      (WSAEWOULDBLOCK == sockerr)
1329
#else
1330
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1331
         due to its inability to send off data without blocking. We therefore
1332
         treat both error codes the same here */
1333
0
      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1334
0
      (EINPROGRESS == sockerr)
1335
0
#endif
1336
0
      ) {
1337
      /* this is just a case of EWOULDBLOCK */
1338
0
      *err = CURLE_AGAIN;
1339
0
    }
1340
0
    else {
1341
0
      char buffer[STRERROR_LEN];
1342
0
      failf(data, "Send failure: %s",
1343
0
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
1344
0
      data->state.os_errno = sockerr;
1345
0
      *err = CURLE_SEND_ERROR;
1346
0
    }
1347
0
  }
1348
1349
0
  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1350
0
              orig_len, (int)nwritten, *err);
1351
0
  cf->conn->sock[cf->sockindex] = fdsave;
1352
0
  return nwritten;
1353
0
}
1354
1355
static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1356
                              char *buf, size_t len, CURLcode *err)
1357
0
{
1358
0
  struct cf_socket_ctx *ctx = cf->ctx;
1359
0
  curl_socket_t fdsave;
1360
0
  ssize_t nread;
1361
1362
0
  *err = CURLE_OK;
1363
1364
0
  fdsave = cf->conn->sock[cf->sockindex];
1365
0
  cf->conn->sock[cf->sockindex] = ctx->sock;
1366
1367
#ifdef DEBUGBUILD
1368
  /* simulate network blocking/partial reads */
1369
  if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1370
    unsigned char c;
1371
    Curl_rand(data, &c, 1);
1372
    if(c >= ((100-ctx->rblock_percent)*256/100)) {
1373
      CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1374
      *err = CURLE_AGAIN;
1375
      nread = -1;
1376
      cf->conn->sock[cf->sockindex] = fdsave;
1377
      return nread;
1378
    }
1379
  }
1380
  if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1381
    size_t orig_len = len;
1382
    len = ctx->recv_max;
1383
    CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1384
                orig_len, len);
1385
  }
1386
#endif
1387
1388
0
  if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1389
0
    CURL_TRC_CF(data, cf, "recv from buffer");
1390
0
    nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1391
0
  }
1392
0
  else {
1393
0
    struct reader_ctx rctx;
1394
1395
0
    rctx.cf = cf;
1396
0
    rctx.data = data;
1397
1398
    /* "small" reads may trigger filling our buffer, "large" reads
1399
     * are probably not worth the additional copy */
1400
0
    if(ctx->buffer_recv && len < NW_SMALL_READS) {
1401
0
      ssize_t nwritten;
1402
0
      nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
1403
0
      if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1404
        /* we have a partial read with an error. need to deliver
1405
         * what we got, return the error later. */
1406
0
        CURL_TRC_CF(data, cf, "partial read: empty buffer first");
1407
0
        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1408
0
      }
1409
0
      else if(nwritten < 0) {
1410
0
        nread = -1;
1411
0
        goto out;
1412
0
      }
1413
0
      else if(nwritten == 0) {
1414
        /* eof */
1415
0
        *err = CURLE_OK;
1416
0
        nread = 0;
1417
0
      }
1418
0
      else {
1419
0
        CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
1420
0
        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1421
0
      }
1422
0
    }
1423
0
    else {
1424
0
      nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
1425
0
    }
1426
0
  }
1427
1428
0
out:
1429
0
  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1430
0
              *err);
1431
0
  if(nread > 0 && !ctx->got_first_byte) {
1432
0
    ctx->first_byte_at = Curl_now();
1433
0
    ctx->got_first_byte = TRUE;
1434
0
  }
1435
0
  cf->conn->sock[cf->sockindex] = fdsave;
1436
0
  return nread;
1437
0
}
1438
1439
static void conn_set_primary_ip(struct Curl_cfilter *cf,
1440
                                struct Curl_easy *data)
1441
0
{
1442
0
  struct cf_socket_ctx *ctx = cf->ctx;
1443
1444
0
  (void)data;
1445
0
  DEBUGASSERT(sizeof(ctx->r_ip) == sizeof(cf->conn->primary_ip));
1446
0
  memcpy(cf->conn->primary_ip, ctx->r_ip, sizeof(cf->conn->primary_ip));
1447
0
}
1448
1449
static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1450
0
{
1451
0
  struct cf_socket_ctx *ctx = cf->ctx;
1452
1453
  /* use this socket from now on */
1454
0
  cf->conn->sock[cf->sockindex] = ctx->sock;
1455
  /* the first socket info gets set at conn and data */
1456
0
  if(cf->sockindex == FIRSTSOCKET) {
1457
0
    cf->conn->remote_addr = &ctx->addr;
1458
0
  #ifdef ENABLE_IPV6
1459
0
    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
1460
0
  #endif
1461
0
    conn_set_primary_ip(cf, data);
1462
0
    set_local_ip(cf, data);
1463
0
    Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
1464
    /* buffering is currently disabled by default because we have stalls
1465
     * in parallel transfers where not all buffered data is consumed and no
1466
     * socket events happen.
1467
     */
1468
0
    ctx->buffer_recv = FALSE;
1469
0
  }
1470
0
  ctx->active = TRUE;
1471
0
}
1472
1473
static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1474
                                struct Curl_easy *data,
1475
                                int event, int arg1, void *arg2)
1476
0
{
1477
0
  struct cf_socket_ctx *ctx = cf->ctx;
1478
1479
0
  (void)arg1;
1480
0
  (void)arg2;
1481
0
  switch(event) {
1482
0
  case CF_CTRL_CONN_INFO_UPDATE:
1483
0
    cf_socket_active(cf, data);
1484
0
    break;
1485
0
  case CF_CTRL_DATA_SETUP:
1486
0
    Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
1487
0
    break;
1488
0
  case CF_CTRL_FORGET_SOCKET:
1489
0
    ctx->sock = CURL_SOCKET_BAD;
1490
0
    break;
1491
0
  }
1492
0
  return CURLE_OK;
1493
0
}
1494
1495
static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1496
                                    struct Curl_easy *data,
1497
                                    bool *input_pending)
1498
0
{
1499
0
  struct cf_socket_ctx *ctx = cf->ctx;
1500
0
  struct pollfd pfd[1];
1501
0
  int r;
1502
1503
0
  *input_pending = FALSE;
1504
0
  (void)data;
1505
0
  if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1506
0
    return FALSE;
1507
1508
  /* Check with 0 timeout if there are any events pending on the socket */
1509
0
  pfd[0].fd = ctx->sock;
1510
0
  pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1511
0
  pfd[0].revents = 0;
1512
1513
0
  r = Curl_poll(pfd, 1, 0);
1514
0
  if(r < 0) {
1515
0
    CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1516
0
    return FALSE;
1517
0
  }
1518
0
  else if(r == 0) {
1519
0
    CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1520
0
    return TRUE;
1521
0
  }
1522
0
  else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1523
0
    CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1524
0
    return FALSE;
1525
0
  }
1526
1527
0
  CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1528
0
  *input_pending = TRUE;
1529
0
  return TRUE;
1530
0
}
1531
1532
static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1533
                                struct Curl_easy *data,
1534
                                int query, int *pres1, void *pres2)
1535
0
{
1536
0
  struct cf_socket_ctx *ctx = cf->ctx;
1537
1538
0
  switch(query) {
1539
0
  case CF_QUERY_SOCKET:
1540
0
    DEBUGASSERT(pres2);
1541
0
    *((curl_socket_t *)pres2) = ctx->sock;
1542
0
    return CURLE_OK;
1543
0
  case CF_QUERY_CONNECT_REPLY_MS:
1544
0
    if(ctx->got_first_byte) {
1545
0
      timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1546
0
      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
1547
0
    }
1548
0
    else
1549
0
      *pres1 = -1;
1550
0
    return CURLE_OK;
1551
0
  case CF_QUERY_TIMER_CONNECT: {
1552
0
    struct curltime *when = pres2;
1553
0
    switch(ctx->transport) {
1554
0
    case TRNSPRT_UDP:
1555
0
    case TRNSPRT_QUIC:
1556
      /* Since UDP connected sockets work different from TCP, we use the
1557
       * time of the first byte from the peer as the "connect" time. */
1558
0
      if(ctx->got_first_byte) {
1559
0
        *when = ctx->first_byte_at;
1560
0
        break;
1561
0
      }
1562
0
      FALLTHROUGH();
1563
0
    default:
1564
0
      *when = ctx->connected_at;
1565
0
      break;
1566
0
    }
1567
0
    return CURLE_OK;
1568
0
  }
1569
0
  default:
1570
0
    break;
1571
0
  }
1572
0
  return cf->next?
1573
0
    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1574
0
    CURLE_UNKNOWN_OPTION;
1575
0
}
1576
1577
struct Curl_cftype Curl_cft_tcp = {
1578
  "TCP",
1579
  CF_TYPE_IP_CONNECT,
1580
  CURL_LOG_LVL_NONE,
1581
  cf_socket_destroy,
1582
  cf_tcp_connect,
1583
  cf_socket_close,
1584
  cf_socket_get_host,
1585
  cf_socket_adjust_pollset,
1586
  cf_socket_data_pending,
1587
  cf_socket_send,
1588
  cf_socket_recv,
1589
  cf_socket_cntrl,
1590
  cf_socket_conn_is_alive,
1591
  Curl_cf_def_conn_keep_alive,
1592
  cf_socket_query,
1593
};
1594
1595
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1596
                            struct Curl_easy *data,
1597
                            struct connectdata *conn,
1598
                            const struct Curl_addrinfo *ai,
1599
                            int transport)
1600
0
{
1601
0
  struct cf_socket_ctx *ctx = NULL;
1602
0
  struct Curl_cfilter *cf = NULL;
1603
0
  CURLcode result;
1604
1605
0
  (void)data;
1606
0
  (void)conn;
1607
0
  DEBUGASSERT(transport == TRNSPRT_TCP);
1608
0
  ctx = calloc(1, sizeof(*ctx));
1609
0
  if(!ctx) {
1610
0
    result = CURLE_OUT_OF_MEMORY;
1611
0
    goto out;
1612
0
  }
1613
0
  cf_socket_ctx_init(ctx, ai, transport);
1614
1615
0
  result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1616
1617
0
out:
1618
0
  *pcf = (!result)? cf : NULL;
1619
0
  if(result) {
1620
0
    Curl_safefree(cf);
1621
0
    Curl_safefree(ctx);
1622
0
  }
1623
1624
0
  return result;
1625
0
}
1626
1627
static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1628
                               struct Curl_easy *data)
1629
0
{
1630
0
  struct cf_socket_ctx *ctx = cf->ctx;
1631
0
  int rc;
1632
1633
  /* QUIC needs a connected socket, nonblocking */
1634
0
  DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1635
1636
#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
1637
  (void)rc;
1638
  /* On macOS OpenSSL QUIC fails on connected sockets.
1639
   * see: <https://github.com/openssl/openssl/issues/23251> */
1640
#else
1641
0
  rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1642
0
  if(-1 == rc) {
1643
0
    return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
1644
0
  }
1645
0
  ctx->sock_connected = TRUE;
1646
0
#endif
1647
0
  set_local_ip(cf, data);
1648
0
  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
1649
0
              " connected: [%s:%d] -> [%s:%d]",
1650
0
              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
1651
0
              ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port);
1652
1653
0
  (void)curlx_nonblock(ctx->sock, TRUE);
1654
0
  switch(ctx->addr.family) {
1655
0
#if defined(__linux__) && defined(IP_MTU_DISCOVER)
1656
0
  case AF_INET: {
1657
0
    int val = IP_PMTUDISC_DO;
1658
0
    (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1659
0
                     sizeof(val));
1660
0
    break;
1661
0
  }
1662
0
#endif
1663
0
#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1664
0
  case AF_INET6: {
1665
0
    int val = IPV6_PMTUDISC_DO;
1666
0
    (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1667
0
                     sizeof(val));
1668
0
    break;
1669
0
  }
1670
0
#endif
1671
0
  }
1672
0
  return CURLE_OK;
1673
0
}
1674
1675
static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1676
                               struct Curl_easy *data,
1677
                               bool blocking, bool *done)
1678
0
{
1679
0
  struct cf_socket_ctx *ctx = cf->ctx;
1680
0
  CURLcode result = CURLE_COULDNT_CONNECT;
1681
1682
0
  (void)blocking;
1683
0
  if(cf->connected) {
1684
0
    *done = TRUE;
1685
0
    return CURLE_OK;
1686
0
  }
1687
0
  *done = FALSE;
1688
0
  if(ctx->sock == CURL_SOCKET_BAD) {
1689
0
    result = cf_socket_open(cf, data);
1690
0
    if(result) {
1691
0
      CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1692
0
      goto out;
1693
0
    }
1694
1695
0
    if(ctx->transport == TRNSPRT_QUIC) {
1696
0
      result = cf_udp_setup_quic(cf, data);
1697
0
      if(result)
1698
0
        goto out;
1699
0
      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1700
0
                  CURL_FORMAT_SOCKET_T " (%s:%d)",
1701
0
                  ctx->sock, ctx->l_ip, ctx->l_port);
1702
0
    }
1703
0
    else {
1704
0
      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1705
0
                  CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
1706
0
    }
1707
0
    *done = TRUE;
1708
0
    cf->connected = TRUE;
1709
0
  }
1710
0
out:
1711
0
  return result;
1712
0
}
1713
1714
struct Curl_cftype Curl_cft_udp = {
1715
  "UDP",
1716
  CF_TYPE_IP_CONNECT,
1717
  CURL_LOG_LVL_NONE,
1718
  cf_socket_destroy,
1719
  cf_udp_connect,
1720
  cf_socket_close,
1721
  cf_socket_get_host,
1722
  cf_socket_adjust_pollset,
1723
  cf_socket_data_pending,
1724
  cf_socket_send,
1725
  cf_socket_recv,
1726
  cf_socket_cntrl,
1727
  cf_socket_conn_is_alive,
1728
  Curl_cf_def_conn_keep_alive,
1729
  cf_socket_query,
1730
};
1731
1732
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1733
                            struct Curl_easy *data,
1734
                            struct connectdata *conn,
1735
                            const struct Curl_addrinfo *ai,
1736
                            int transport)
1737
0
{
1738
0
  struct cf_socket_ctx *ctx = NULL;
1739
0
  struct Curl_cfilter *cf = NULL;
1740
0
  CURLcode result;
1741
1742
0
  (void)data;
1743
0
  (void)conn;
1744
0
  DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1745
0
  ctx = calloc(1, sizeof(*ctx));
1746
0
  if(!ctx) {
1747
0
    result = CURLE_OUT_OF_MEMORY;
1748
0
    goto out;
1749
0
  }
1750
0
  cf_socket_ctx_init(ctx, ai, transport);
1751
1752
0
  result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1753
1754
0
out:
1755
0
  *pcf = (!result)? cf : NULL;
1756
0
  if(result) {
1757
0
    Curl_safefree(cf);
1758
0
    Curl_safefree(ctx);
1759
0
  }
1760
1761
0
  return result;
1762
0
}
1763
1764
/* this is the TCP filter which can also handle this case */
1765
struct Curl_cftype Curl_cft_unix = {
1766
  "UNIX",
1767
  CF_TYPE_IP_CONNECT,
1768
  CURL_LOG_LVL_NONE,
1769
  cf_socket_destroy,
1770
  cf_tcp_connect,
1771
  cf_socket_close,
1772
  cf_socket_get_host,
1773
  cf_socket_adjust_pollset,
1774
  cf_socket_data_pending,
1775
  cf_socket_send,
1776
  cf_socket_recv,
1777
  cf_socket_cntrl,
1778
  cf_socket_conn_is_alive,
1779
  Curl_cf_def_conn_keep_alive,
1780
  cf_socket_query,
1781
};
1782
1783
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1784
                             struct Curl_easy *data,
1785
                             struct connectdata *conn,
1786
                             const struct Curl_addrinfo *ai,
1787
                             int transport)
1788
0
{
1789
0
  struct cf_socket_ctx *ctx = NULL;
1790
0
  struct Curl_cfilter *cf = NULL;
1791
0
  CURLcode result;
1792
1793
0
  (void)data;
1794
0
  (void)conn;
1795
0
  DEBUGASSERT(transport == TRNSPRT_UNIX);
1796
0
  ctx = calloc(1, sizeof(*ctx));
1797
0
  if(!ctx) {
1798
0
    result = CURLE_OUT_OF_MEMORY;
1799
0
    goto out;
1800
0
  }
1801
0
  cf_socket_ctx_init(ctx, ai, transport);
1802
1803
0
  result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
1804
1805
0
out:
1806
0
  *pcf = (!result)? cf : NULL;
1807
0
  if(result) {
1808
0
    Curl_safefree(cf);
1809
0
    Curl_safefree(ctx);
1810
0
  }
1811
1812
0
  return result;
1813
0
}
1814
1815
static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
1816
                                      struct Curl_easy *data,
1817
                                      bool blocking, bool *done)
1818
0
{
1819
  /* we start accepted, if we ever close, we cannot go on */
1820
0
  (void)data;
1821
0
  (void)blocking;
1822
0
  if(cf->connected) {
1823
0
    *done = TRUE;
1824
0
    return CURLE_OK;
1825
0
  }
1826
0
  return CURLE_FAILED_INIT;
1827
0
}
1828
1829
struct Curl_cftype Curl_cft_tcp_accept = {
1830
  "TCP-ACCEPT",
1831
  CF_TYPE_IP_CONNECT,
1832
  CURL_LOG_LVL_NONE,
1833
  cf_socket_destroy,
1834
  cf_tcp_accept_connect,
1835
  cf_socket_close,
1836
  cf_socket_get_host,              /* TODO: not accurate */
1837
  cf_socket_adjust_pollset,
1838
  cf_socket_data_pending,
1839
  cf_socket_send,
1840
  cf_socket_recv,
1841
  cf_socket_cntrl,
1842
  cf_socket_conn_is_alive,
1843
  Curl_cf_def_conn_keep_alive,
1844
  cf_socket_query,
1845
};
1846
1847
CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
1848
                                  struct connectdata *conn,
1849
                                  int sockindex, curl_socket_t *s)
1850
0
{
1851
0
  CURLcode result;
1852
0
  struct Curl_cfilter *cf = NULL;
1853
0
  struct cf_socket_ctx *ctx = NULL;
1854
1855
  /* replace any existing */
1856
0
  Curl_conn_cf_discard_all(data, conn, sockindex);
1857
0
  DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
1858
1859
0
  ctx = calloc(1, sizeof(*ctx));
1860
0
  if(!ctx) {
1861
0
    result = CURLE_OUT_OF_MEMORY;
1862
0
    goto out;
1863
0
  }
1864
0
  ctx->transport = conn->transport;
1865
0
  ctx->sock = *s;
1866
0
  ctx->accepted = FALSE;
1867
0
  result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
1868
0
  if(result)
1869
0
    goto out;
1870
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
1871
1872
0
  conn->sock[sockindex] = ctx->sock;
1873
0
  set_local_ip(cf, data);
1874
0
  ctx->active = TRUE;
1875
0
  ctx->connected_at = Curl_now();
1876
0
  cf->connected = TRUE;
1877
0
  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
1878
0
              CURL_FORMAT_SOCKET_T ")", ctx->sock);
1879
1880
0
out:
1881
0
  if(result) {
1882
0
    Curl_safefree(cf);
1883
0
    Curl_safefree(ctx);
1884
0
  }
1885
0
  return result;
1886
0
}
1887
1888
static void set_accepted_remote_ip(struct Curl_cfilter *cf,
1889
                                   struct Curl_easy *data)
1890
0
{
1891
0
  struct cf_socket_ctx *ctx = cf->ctx;
1892
0
#ifdef HAVE_GETPEERNAME
1893
0
  char buffer[STRERROR_LEN];
1894
0
  struct Curl_sockaddr_storage ssrem;
1895
0
  curl_socklen_t plen;
1896
1897
0
  ctx->r_ip[0] = 0;
1898
0
  ctx->r_port = 0;
1899
0
  plen = sizeof(ssrem);
1900
0
  memset(&ssrem, 0, plen);
1901
0
  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
1902
0
    int error = SOCKERRNO;
1903
0
    failf(data, "getpeername() failed with errno %d: %s",
1904
0
          error, Curl_strerror(error, buffer, sizeof(buffer)));
1905
0
    return;
1906
0
  }
1907
0
  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
1908
0
                       ctx->r_ip, &ctx->r_port)) {
1909
0
    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
1910
0
          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1911
0
    return;
1912
0
  }
1913
#else
1914
  ctx->r_ip[0] = 0;
1915
  ctx->r_port = 0;
1916
  (void)data;
1917
#endif
1918
0
}
1919
1920
CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
1921
                                    struct connectdata *conn,
1922
                                    int sockindex, curl_socket_t *s)
1923
0
{
1924
0
  struct Curl_cfilter *cf = NULL;
1925
0
  struct cf_socket_ctx *ctx = NULL;
1926
1927
0
  cf = conn->cfilter[sockindex];
1928
0
  if(!cf || cf->cft != &Curl_cft_tcp_accept)
1929
0
    return CURLE_FAILED_INIT;
1930
1931
0
  ctx = cf->ctx;
1932
  /* discard the listen socket */
1933
0
  socket_close(data, conn, TRUE, ctx->sock);
1934
0
  ctx->sock = *s;
1935
0
  conn->sock[sockindex] = ctx->sock;
1936
0
  set_accepted_remote_ip(cf, data);
1937
0
  set_local_ip(cf, data);
1938
0
  ctx->active = TRUE;
1939
0
  ctx->accepted = TRUE;
1940
0
  ctx->connected_at = Curl_now();
1941
0
  cf->connected = TRUE;
1942
0
  CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
1943
0
              ", remote=%s port=%d)",
1944
0
              ctx->sock, ctx->r_ip, ctx->r_port);
1945
1946
0
  return CURLE_OK;
1947
0
}
1948
1949
/**
1950
 * Return TRUE iff `cf` is a socket filter.
1951
 */
1952
static bool cf_is_socket(struct Curl_cfilter *cf)
1953
0
{
1954
0
  return cf && (cf->cft == &Curl_cft_tcp ||
1955
0
                cf->cft == &Curl_cft_udp ||
1956
0
                cf->cft == &Curl_cft_unix ||
1957
0
                cf->cft == &Curl_cft_tcp_accept);
1958
0
}
1959
1960
CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
1961
                             struct Curl_easy *data,
1962
                             curl_socket_t *psock,
1963
                             const struct Curl_sockaddr_ex **paddr,
1964
                             const char **pr_ip_str, int *pr_port,
1965
                             const char **pl_ip_str, int *pl_port)
1966
0
{
1967
0
  if(cf_is_socket(cf) && cf->ctx) {
1968
0
    struct cf_socket_ctx *ctx = cf->ctx;
1969
1970
0
    if(psock)
1971
0
      *psock = ctx->sock;
1972
0
    if(paddr)
1973
0
      *paddr = &ctx->addr;
1974
0
    if(pr_ip_str)
1975
0
      *pr_ip_str = ctx->r_ip;
1976
0
    if(pr_port)
1977
0
      *pr_port = ctx->r_port;
1978
0
    if(pl_port ||pl_ip_str) {
1979
0
      set_local_ip(cf, data);
1980
0
      if(pl_ip_str)
1981
0
        *pl_ip_str = ctx->l_ip;
1982
0
      if(pl_port)
1983
0
        *pl_port = ctx->l_port;
1984
0
    }
1985
0
    return CURLE_OK;
1986
0
  }
1987
0
  return CURLE_FAILED_INIT;
1988
0
}