Coverage Report

Created: 2024-05-21 06:52

/src/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(USE_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
57.7k
{
102
57.7k
#if defined(TCP_NODELAY)
103
57.7k
  curl_socklen_t onoff = (curl_socklen_t) 1;
104
57.7k
  int level = IPPROTO_TCP;
105
57.7k
  char buffer[STRERROR_LEN];
106
107
57.7k
  if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
108
57.7k
                sizeof(onoff)) < 0)
109
57.7k
    infof(data, "Could not set TCP_NODELAY: %s",
110
57.7k
          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
111
#else
112
  (void)data;
113
  (void)sockfd;
114
#endif
115
57.7k
}
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
58.2k
#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
58.7k
{
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
58.7k
  dest->family = ai->ai_family;
238
58.7k
  switch(transport) {
239
58.2k
  case TRNSPRT_TCP:
240
58.2k
    dest->socktype = SOCK_STREAM;
241
58.2k
    dest->protocol = IPPROTO_TCP;
242
58.2k
    break;
243
0
  case TRNSPRT_UNIX:
244
0
    dest->socktype = SOCK_STREAM;
245
0
    dest->protocol = IPPROTO_IP;
246
0
    break;
247
467
  default: /* UDP and QUIC */
248
467
    dest->socktype = SOCK_DGRAM;
249
467
    dest->protocol = IPPROTO_UDP;
250
467
    break;
251
58.7k
  }
252
58.7k
  dest->addrlen = ai->ai_addrlen;
253
254
58.7k
  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
255
0
    dest->addrlen = sizeof(struct Curl_sockaddr_storage);
256
58.7k
  memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
257
58.7k
}
258
259
static CURLcode socket_open(struct Curl_easy *data,
260
                            struct Curl_sockaddr_ex *addr,
261
                            curl_socket_t *sockfd)
262
58.7k
{
263
58.7k
  DEBUGASSERT(data);
264
58.7k
  DEBUGASSERT(data->conn);
265
58.7k
  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
58.7k
    Curl_set_in_callback(data, true);
276
58.7k
    *sockfd = data->set.fopensocket(data->set.opensocket_client,
277
58.7k
                                    CURLSOCKTYPE_IPCXN,
278
58.7k
                                    (struct curl_sockaddr *)addr);
279
58.7k
    Curl_set_in_callback(data, false);
280
58.7k
  }
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
58.7k
  if(*sockfd == CURL_SOCKET_BAD)
287
    /* no socket, no connection */
288
540
    return CURLE_COULDNT_CONNECT;
289
290
58.2k
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
291
58.2k
  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
58.2k
#endif
296
58.2k
  return CURLE_OK;
297
58.7k
}
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
58.2k
{
327
58.2k
  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
58.2k
  if(conn)
337
    /* tell the multi-socket code about this */
338
58.2k
    Curl_multi_closed(data, sock);
339
340
58.2k
  sclose(sock);
341
342
58.2k
  return 0;
343
58.2k
}
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
58.2k
{
404
58.2k
  struct Curl_sockaddr_storage sa;
405
58.2k
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
406
58.2k
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
407
58.2k
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
408
58.2k
#ifdef USE_IPV6
409
58.2k
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
410
58.2k
#endif
411
412
58.2k
  struct Curl_dns_entry *h = NULL;
413
58.2k
  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
58.2k
  int portnum = data->set.localportrange;
417
58.2k
  const char *dev = data->set.str[STRING_DEVICE];
418
58.2k
  int error;
419
58.2k
#ifdef IP_BIND_ADDRESS_NO_PORT
420
58.2k
  int on = 1;
421
58.2k
#endif
422
#ifndef USE_IPV6
423
  (void)scope;
424
#endif
425
426
  /*************************************************************
427
   * Select device to bind socket to
428
   *************************************************************/
429
58.2k
  if(!dev && !port)
430
    /* no local kind of binding was requested */
431
58.2k
    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 USE_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 USE_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 USE_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 USE_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
      infof(data, "Local port: %hu", port);
620
0
      conn->bits.bound = TRUE;
621
0
      return CURLE_OK;
622
0
    }
623
624
0
    if(--portnum > 0) {
625
0
      port++; /* try next port */
626
0
      if(port == 0)
627
0
        break;
628
0
      infof(data, "Bind to local port %d failed, trying next", port - 1);
629
      /* We reuse/clobber the port variable here below */
630
0
      if(sock->sa_family == AF_INET)
631
0
        si4->sin_port = ntohs(port);
632
0
#ifdef USE_IPV6
633
0
      else
634
0
        si6->sin6_port = ntohs(port);
635
0
#endif
636
0
    }
637
0
    else
638
0
      break;
639
0
  }
640
0
  {
641
0
    char buffer[STRERROR_LEN];
642
0
    data->state.os_errno = error = SOCKERRNO;
643
0
    failf(data, "bind failed with errno %d: %s",
644
0
          error, Curl_strerror(error, buffer, sizeof(buffer)));
645
0
  }
646
647
0
  return CURLE_INTERFACE_FAILED;
648
0
}
649
#endif
650
651
/*
652
 * verifyconnect() returns TRUE if the connect really has happened.
653
 */
654
static bool verifyconnect(curl_socket_t sockfd, int *error)
655
0
{
656
0
  bool rc = TRUE;
657
0
#ifdef SO_ERROR
658
0
  int err = 0;
659
0
  curl_socklen_t errSize = sizeof(err);
660
661
#ifdef _WIN32
662
  /*
663
   * In October 2003 we effectively nullified this function on Windows due to
664
   * problems with it using all CPU in multi-threaded cases.
665
   *
666
   * In May 2004, we bring it back to offer more info back on connect failures.
667
   * Gisle Vanem could reproduce the former problems with this function, but
668
   * could avoid them by adding this SleepEx() call below:
669
   *
670
   *    "I don't have Rational Quantify, but the hint from his post was
671
   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
672
   *    just Sleep(0) would be enough?) would release whatever
673
   *    mutex/critical-section the ntdll call is waiting on.
674
   *
675
   *    Someone got to verify this on Win-NT 4.0, 2000."
676
   */
677
678
#ifdef _WIN32_WCE
679
  Sleep(0);
680
#else
681
  SleepEx(0, FALSE);
682
#endif
683
684
#endif
685
686
0
  if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
687
0
    err = SOCKERRNO;
688
#ifdef _WIN32_WCE
689
  /* Old WinCE versions don't support SO_ERROR */
690
  if(WSAENOPROTOOPT == err) {
691
    SET_SOCKERRNO(0);
692
    err = 0;
693
  }
694
#endif
695
#if defined(EBADIOCTL) && defined(__minix)
696
  /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
697
  if(EBADIOCTL == err) {
698
    SET_SOCKERRNO(0);
699
    err = 0;
700
  }
701
#endif
702
0
  if((0 == err) || (EISCONN == err))
703
    /* we are connected, awesome! */
704
0
    rc = TRUE;
705
0
  else
706
    /* This wasn't a successful connect */
707
0
    rc = FALSE;
708
0
  if(error)
709
0
    *error = err;
710
#else
711
  (void)sockfd;
712
  if(error)
713
    *error = SOCKERRNO;
714
#endif
715
0
  return rc;
716
0
}
717
718
/**
719
 * Determine the curl code for a socket connect() == -1 with errno.
720
 */
721
static CURLcode socket_connect_result(struct Curl_easy *data,
722
                                      const char *ipaddress, int error)
723
0
{
724
0
  switch(error) {
725
0
  case EINPROGRESS:
726
0
  case EWOULDBLOCK:
727
0
#if defined(EAGAIN)
728
#if (EAGAIN) != (EWOULDBLOCK)
729
    /* On some platforms EAGAIN and EWOULDBLOCK are the
730
     * same value, and on others they are different, hence
731
     * the odd #if
732
     */
733
  case EAGAIN:
734
#endif
735
0
#endif
736
0
    return CURLE_OK;
737
738
0
  default:
739
    /* unknown error, fallthrough and try another address! */
740
#ifdef CURL_DISABLE_VERBOSE_STRINGS
741
    (void)ipaddress;
742
#else
743
0
    {
744
0
      char buffer[STRERROR_LEN];
745
0
      infof(data, "Immediate connect fail for %s: %s",
746
0
            ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
747
0
    }
748
0
#endif
749
0
    data->state.os_errno = error;
750
    /* connect failed */
751
0
    return CURLE_COULDNT_CONNECT;
752
0
  }
753
0
}
754
755
/* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
756
 * This happens often on TLS connections where the TLS implementation
757
 * tries to read the head of a TLS record, determine the length of the
758
 * full record and then make a subsequent read for that.
759
 * On large reads, we will not fill the buffer to avoid the double copy. */
760
58.7k
#define NW_RECV_CHUNK_SIZE    (64 * 1024)
761
58.7k
#define NW_RECV_CHUNKS         1
762
0
#define NW_SMALL_READS        (1024)
763
764
struct cf_socket_ctx {
765
  int transport;
766
  struct Curl_sockaddr_ex addr;      /* address to connect to */
767
  curl_socket_t sock;                /* current attempt socket */
768
  struct bufq recvbuf;               /* used when `buffer_recv` is set */
769
  struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
770
  struct curltime started_at;        /* when socket was created */
771
  struct curltime connected_at;      /* when socket connected/got first byte */
772
  struct curltime first_byte_at;     /* when first byte was recvd */
773
  int error;                         /* errno of last failure or 0 */
774
#ifdef DEBUGBUILD
775
  int wblock_percent;                /* percent of writes doing EAGAIN */
776
  int wpartial_percent;              /* percent of bytes written in send */
777
  int rblock_percent;                /* percent of reads doing EAGAIN */
778
  size_t recv_max;                  /* max enforced read size */
779
#endif
780
  BIT(got_first_byte);               /* if first byte was received */
781
  BIT(accepted);                     /* socket was accepted, not connected */
782
  BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
783
  BIT(active);
784
  BIT(buffer_recv);
785
};
786
787
static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
788
                               const struct Curl_addrinfo *ai,
789
                               int transport)
790
58.7k
{
791
58.7k
  memset(ctx, 0, sizeof(*ctx));
792
58.7k
  ctx->sock = CURL_SOCKET_BAD;
793
58.7k
  ctx->transport = transport;
794
58.7k
  Curl_sock_assign_addr(&ctx->addr, ai, transport);
795
58.7k
  Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
796
58.7k
#ifdef DEBUGBUILD
797
58.7k
  {
798
58.7k
    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
799
58.7k
    if(p) {
800
0
      long l = strtol(p, NULL, 10);
801
0
      if(l >= 0 && l <= 100)
802
0
        ctx->wblock_percent = (int)l;
803
0
    }
804
58.7k
    p = getenv("CURL_DBG_SOCK_WPARTIAL");
805
58.7k
    if(p) {
806
0
      long l = strtol(p, NULL, 10);
807
0
      if(l >= 0 && l <= 100)
808
0
        ctx->wpartial_percent = (int)l;
809
0
    }
810
58.7k
    p = getenv("CURL_DBG_SOCK_RBLOCK");
811
58.7k
    if(p) {
812
0
      long l = strtol(p, NULL, 10);
813
0
      if(l >= 0 && l <= 100)
814
0
        ctx->rblock_percent = (int)l;
815
0
    }
816
58.7k
    p = getenv("CURL_DBG_SOCK_RMAX");
817
58.7k
    if(p) {
818
0
      long l = strtol(p, NULL, 10);
819
0
      if(l >= 0)
820
0
        ctx->recv_max = (size_t)l;
821
0
    }
822
58.7k
  }
823
58.7k
#endif
824
58.7k
}
825
826
struct reader_ctx {
827
  struct Curl_cfilter *cf;
828
  struct Curl_easy *data;
829
};
830
831
static ssize_t nw_in_read(void *reader_ctx,
832
                           unsigned char *buf, size_t len,
833
                           CURLcode *err)
834
30.9M
{
835
30.9M
  struct reader_ctx *rctx = reader_ctx;
836
30.9M
  struct cf_socket_ctx *ctx = rctx->cf->ctx;
837
30.9M
  ssize_t nread;
838
839
30.9M
  *err = CURLE_OK;
840
30.9M
  nread = sread(ctx->sock, buf, len);
841
842
30.9M
  if(-1 == nread) {
843
1.36M
    int sockerr = SOCKERRNO;
844
845
1.36M
    if(
846
#ifdef WSAEWOULDBLOCK
847
      /* This is how Windows does it */
848
      (WSAEWOULDBLOCK == sockerr)
849
#else
850
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
851
         due to its inability to send off data without blocking. We therefore
852
         treat both error codes the same here */
853
1.36M
      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
854
1.36M
#endif
855
1.36M
      ) {
856
      /* this is just a case of EWOULDBLOCK */
857
1.36M
      *err = CURLE_AGAIN;
858
1.36M
      nread = -1;
859
1.36M
    }
860
0
    else {
861
0
      char buffer[STRERROR_LEN];
862
863
0
      failf(rctx->data, "Recv failure: %s",
864
0
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
865
0
      rctx->data->state.os_errno = sockerr;
866
0
      *err = CURLE_RECV_ERROR;
867
0
      nread = -1;
868
0
    }
869
1.36M
  }
870
30.9M
  CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu, fd=%"
871
30.9M
              CURL_FORMAT_SOCKET_T ") -> %d, err=%d",
872
30.9M
              len, ctx->sock, (int)nread, *err);
873
30.9M
  return nread;
874
30.9M
}
875
876
static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
877
116k
{
878
116k
  struct cf_socket_ctx *ctx = cf->ctx;
879
880
116k
  if(ctx && CURL_SOCKET_BAD != ctx->sock) {
881
58.2k
    CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
882
58.2k
                ")", ctx->sock);
883
58.2k
    if(ctx->sock == cf->conn->sock[cf->sockindex])
884
58.2k
      cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
885
58.2k
    socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
886
58.2k
    ctx->sock = CURL_SOCKET_BAD;
887
58.2k
    if(ctx->active && cf->sockindex == FIRSTSOCKET)
888
55.6k
      cf->conn->remote_addr = NULL;
889
58.2k
    Curl_bufq_reset(&ctx->recvbuf);
890
58.2k
    ctx->active = FALSE;
891
58.2k
    ctx->buffer_recv = FALSE;
892
58.2k
    memset(&ctx->started_at, 0, sizeof(ctx->started_at));
893
58.2k
    memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
894
58.2k
  }
895
896
116k
  cf->connected = FALSE;
897
116k
}
898
899
static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
900
58.7k
{
901
58.7k
  struct cf_socket_ctx *ctx = cf->ctx;
902
903
58.7k
  cf_socket_close(cf, data);
904
58.7k
  CURL_TRC_CF(data, cf, "destroy");
905
58.7k
  Curl_bufq_free(&ctx->recvbuf);
906
58.7k
  free(ctx);
907
58.7k
  cf->ctx = NULL;
908
58.7k
}
909
910
static CURLcode set_local_ip(struct Curl_cfilter *cf,
911
                             struct Curl_easy *data)
912
175k
{
913
175k
  struct cf_socket_ctx *ctx = cf->ctx;
914
915
175k
#ifdef HAVE_GETSOCKNAME
916
175k
  if((ctx->sock != CURL_SOCKET_BAD) &&
917
175k
     !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
918
    /* TFTP does not connect, so it cannot get the IP like this */
919
920
174k
    char buffer[STRERROR_LEN];
921
174k
    struct Curl_sockaddr_storage ssloc;
922
174k
    curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
923
924
174k
    memset(&ssloc, 0, sizeof(ssloc));
925
174k
    if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
926
0
      int error = SOCKERRNO;
927
0
      failf(data, "getsockname() failed with errno %d: %s",
928
0
            error, Curl_strerror(error, buffer, sizeof(buffer)));
929
0
      return CURLE_FAILED_INIT;
930
0
    }
931
174k
    if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
932
174k
                         ctx->ip.local_ip, &ctx->ip.local_port)) {
933
0
      failf(data, "ssloc inet_ntop() failed with errno %d: %s",
934
0
            errno, Curl_strerror(errno, buffer, sizeof(buffer)));
935
0
      return CURLE_FAILED_INIT;
936
0
    }
937
174k
  }
938
#else
939
  (void)data;
940
  ctx->ip.local_ip[0] = 0;
941
  ctx->ip.local_port = -1;
942
#endif
943
175k
  return CURLE_OK;
944
175k
}
945
946
static CURLcode set_remote_ip(struct Curl_cfilter *cf,
947
                              struct Curl_easy *data)
948
58.2k
{
949
58.2k
  struct cf_socket_ctx *ctx = cf->ctx;
950
951
  /* store remote address and port used in this connection attempt */
952
58.2k
  if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
953
58.2k
                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
954
0
    char buffer[STRERROR_LEN];
955
956
0
    ctx->error = errno;
957
    /* malformed address or bug in inet_ntop, try next address */
958
0
    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
959
0
          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
960
0
    return CURLE_FAILED_INIT;
961
0
  }
962
58.2k
  return CURLE_OK;
963
58.2k
}
964
965
static CURLcode cf_socket_open(struct Curl_cfilter *cf,
966
                              struct Curl_easy *data)
967
58.7k
{
968
58.7k
  struct cf_socket_ctx *ctx = cf->ctx;
969
58.7k
  int error = 0;
970
58.7k
  bool isconnected = FALSE;
971
58.7k
  CURLcode result = CURLE_COULDNT_CONNECT;
972
58.7k
  bool is_tcp;
973
974
58.7k
  (void)data;
975
58.7k
  DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
976
58.7k
  ctx->started_at = Curl_now();
977
58.7k
  result = socket_open(data, &ctx->addr, &ctx->sock);
978
58.7k
  if(result)
979
540
    goto out;
980
981
58.2k
  result = set_remote_ip(cf, data);
982
58.2k
  if(result)
983
0
    goto out;
984
985
58.2k
#ifdef USE_IPV6
986
58.2k
  if(ctx->addr.family == AF_INET6) {
987
0
    set_ipv6_v6only(ctx->sock, 0);
988
0
    infof(data, "  Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
989
0
  }
990
58.2k
  else
991
58.2k
#endif
992
58.2k
    infof(data, "  Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
993
994
58.2k
#ifdef USE_IPV6
995
58.2k
  is_tcp = (ctx->addr.family == AF_INET
996
58.2k
            || ctx->addr.family == AF_INET6) &&
997
58.2k
           ctx->addr.socktype == SOCK_STREAM;
998
#else
999
  is_tcp = (ctx->addr.family == AF_INET) &&
1000
           ctx->addr.socktype == SOCK_STREAM;
1001
#endif
1002
58.2k
  if(is_tcp && data->set.tcp_nodelay)
1003
57.7k
    tcpnodelay(data, ctx->sock);
1004
1005
58.2k
  nosigpipe(data, ctx->sock);
1006
1007
58.2k
  Curl_sndbufset(ctx->sock);
1008
1009
58.2k
  if(is_tcp && data->set.tcp_keepalive)
1010
0
    tcpkeepalive(data, ctx->sock);
1011
1012
58.2k
  if(data->set.fsockopt) {
1013
    /* activate callback for setting socket options */
1014
58.2k
    Curl_set_in_callback(data, true);
1015
58.2k
    error = data->set.fsockopt(data->set.sockopt_client,
1016
58.2k
                               ctx->sock,
1017
58.2k
                               CURLSOCKTYPE_IPCXN);
1018
58.2k
    Curl_set_in_callback(data, false);
1019
1020
58.2k
    if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1021
58.2k
      isconnected = TRUE;
1022
0
    else if(error) {
1023
0
      result = CURLE_ABORTED_BY_CALLBACK;
1024
0
      goto out;
1025
0
    }
1026
58.2k
  }
1027
1028
58.2k
#ifndef CURL_DISABLE_BINDLOCAL
1029
  /* possibly bind the local end to an IP, interface or port */
1030
58.2k
  if(ctx->addr.family == AF_INET
1031
58.2k
#ifdef USE_IPV6
1032
58.2k
     || ctx->addr.family == AF_INET6
1033
58.2k
#endif
1034
58.2k
    ) {
1035
58.2k
    result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1036
58.2k
                       Curl_ipv6_scope(&ctx->addr.sa_addr));
1037
58.2k
    if(result) {
1038
0
      if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1039
        /* The address family is not supported on this interface.
1040
           We can continue trying addresses */
1041
0
        result = CURLE_COULDNT_CONNECT;
1042
0
      }
1043
0
      goto out;
1044
0
    }
1045
58.2k
  }
1046
58.2k
#endif
1047
1048
  /* set socket non-blocking */
1049
58.2k
  (void)curlx_nonblock(ctx->sock, TRUE);
1050
58.2k
  ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1051
58.7k
out:
1052
58.7k
  if(result) {
1053
540
    if(ctx->sock != CURL_SOCKET_BAD) {
1054
0
      socket_close(data, cf->conn, TRUE, ctx->sock);
1055
0
      ctx->sock = CURL_SOCKET_BAD;
1056
0
    }
1057
540
  }
1058
58.2k
  else if(isconnected) {
1059
58.2k
    set_local_ip(cf, data);
1060
58.2k
    ctx->connected_at = Curl_now();
1061
58.2k
    cf->connected = TRUE;
1062
58.2k
  }
1063
58.7k
  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
1064
58.7k
              result, ctx->sock);
1065
58.7k
  return result;
1066
58.2k
}
1067
1068
static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1069
                      bool is_tcp_fastopen)
1070
0
{
1071
0
  struct cf_socket_ctx *ctx = cf->ctx;
1072
0
#ifdef TCP_FASTOPEN_CONNECT
1073
0
  int optval = 1;
1074
0
#endif
1075
0
  int rc = -1;
1076
1077
0
  (void)data;
1078
0
  if(is_tcp_fastopen) {
1079
#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1080
#  if defined(HAVE_BUILTIN_AVAILABLE)
1081
    /* while connectx function is available since macOS 10.11 / iOS 9,
1082
       it did not have the interface declared correctly until
1083
       Xcode 9 / macOS SDK 10.13 */
1084
    if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1085
      sa_endpoints_t endpoints;
1086
      endpoints.sae_srcif = 0;
1087
      endpoints.sae_srcaddr = NULL;
1088
      endpoints.sae_srcaddrlen = 0;
1089
      endpoints.sae_dstaddr = &ctx->addr.sa_addr;
1090
      endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1091
1092
      rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1093
                    CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1094
                    NULL, 0, NULL, NULL);
1095
    }
1096
    else {
1097
      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1098
    }
1099
#  else
1100
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1101
#  endif /* HAVE_BUILTIN_AVAILABLE */
1102
#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1103
0
    if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1104
0
                  (void *)&optval, sizeof(optval)) < 0)
1105
0
      infof(data, "Failed to enable TCP Fast Open on fd %"
1106
0
            CURL_FORMAT_SOCKET_T, ctx->sock);
1107
1108
0
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1109
#elif defined(MSG_FASTOPEN) /* old Linux */
1110
    if(cf->conn->given->flags & PROTOPT_SSL)
1111
      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1112
    else
1113
      rc = 0; /* Do nothing */
1114
#endif
1115
0
  }
1116
0
  else {
1117
0
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1118
0
  }
1119
0
  return rc;
1120
0
}
1121
1122
static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1123
                               struct Curl_easy *data,
1124
                               bool blocking, bool *done)
1125
58.2k
{
1126
58.2k
  struct cf_socket_ctx *ctx = cf->ctx;
1127
58.2k
  CURLcode result = CURLE_COULDNT_CONNECT;
1128
58.2k
  int rc = 0;
1129
1130
58.2k
  (void)data;
1131
58.2k
  if(cf->connected) {
1132
0
    *done = TRUE;
1133
0
    return CURLE_OK;
1134
0
  }
1135
1136
  /* TODO: need to support blocking connect? */
1137
58.2k
  if(blocking)
1138
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1139
1140
58.2k
  *done = FALSE; /* a very negative world view is best */
1141
58.2k
  if(ctx->sock == CURL_SOCKET_BAD) {
1142
58.2k
    int error;
1143
1144
58.2k
    result = cf_socket_open(cf, data);
1145
58.2k
    if(result)
1146
538
      goto out;
1147
1148
57.7k
    if(cf->connected) {
1149
57.7k
      *done = TRUE;
1150
57.7k
      return CURLE_OK;
1151
57.7k
    }
1152
1153
    /* Connect TCP socket */
1154
0
    rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1155
0
    error = SOCKERRNO;
1156
0
    set_local_ip(cf, data);
1157
0
    CURL_TRC_CF(data, cf, "local address %s port %d...",
1158
0
                ctx->ip.local_ip, ctx->ip.local_port);
1159
0
    if(-1 == rc) {
1160
0
      result = socket_connect_result(data, ctx->ip.remote_ip, error);
1161
0
      goto out;
1162
0
    }
1163
0
  }
1164
1165
#ifdef mpeix
1166
  /* Call this function once now, and ignore the results. We do this to
1167
     "clear" the error state on the socket so that we can later read it
1168
     reliably. This is reported necessary on the MPE/iX operating
1169
     system. */
1170
  (void)verifyconnect(ctx->sock, NULL);
1171
#endif
1172
  /* check socket for connect */
1173
0
  rc = SOCKET_WRITABLE(ctx->sock, 0);
1174
1175
0
  if(rc == 0) { /* no connection yet */
1176
0
    CURL_TRC_CF(data, cf, "not connected yet");
1177
0
    return CURLE_OK;
1178
0
  }
1179
0
  else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1180
0
    if(verifyconnect(ctx->sock, &ctx->error)) {
1181
      /* we are connected with TCP, awesome! */
1182
0
      ctx->connected_at = Curl_now();
1183
0
      set_local_ip(cf, data);
1184
0
      *done = TRUE;
1185
0
      cf->connected = TRUE;
1186
0
      CURL_TRC_CF(data, cf, "connected");
1187
0
      return CURLE_OK;
1188
0
    }
1189
0
  }
1190
0
  else if(rc & CURL_CSELECT_ERR) {
1191
0
    (void)verifyconnect(ctx->sock, &ctx->error);
1192
0
    result = CURLE_COULDNT_CONNECT;
1193
0
  }
1194
1195
538
out:
1196
538
  if(result) {
1197
538
    if(ctx->error) {
1198
0
      set_local_ip(cf, data);
1199
0
      data->state.os_errno = ctx->error;
1200
0
      SET_SOCKERRNO(ctx->error);
1201
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1202
0
      {
1203
0
        char buffer[STRERROR_LEN];
1204
0
        infof(data, "connect to %s port %u from %s port %d failed: %s",
1205
0
              ctx->ip.remote_ip, ctx->ip.remote_port,
1206
0
              ctx->ip.local_ip, ctx->ip.local_port,
1207
0
              Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1208
0
      }
1209
0
#endif
1210
0
    }
1211
538
    if(ctx->sock != CURL_SOCKET_BAD) {
1212
0
      socket_close(data, cf->conn, TRUE, ctx->sock);
1213
0
      ctx->sock = CURL_SOCKET_BAD;
1214
0
    }
1215
538
    *done = FALSE;
1216
538
  }
1217
538
  return result;
1218
0
}
1219
1220
static void cf_socket_get_host(struct Curl_cfilter *cf,
1221
                               struct Curl_easy *data,
1222
                               const char **phost,
1223
                               const char **pdisplay_host,
1224
                               int *pport)
1225
2.30k
{
1226
2.30k
  struct cf_socket_ctx *ctx = cf->ctx;
1227
2.30k
  (void)data;
1228
2.30k
  *phost = cf->conn->host.name;
1229
2.30k
  *pdisplay_host = cf->conn->host.dispname;
1230
2.30k
  *pport = ctx->ip.remote_port;
1231
2.30k
}
1232
1233
static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1234
                                      struct Curl_easy *data,
1235
                                      struct easy_pollset *ps)
1236
36.7M
{
1237
36.7M
  struct cf_socket_ctx *ctx = cf->ctx;
1238
1239
36.7M
  if(ctx->sock != CURL_SOCKET_BAD) {
1240
36.7M
    if(!cf->connected) {
1241
0
      Curl_pollset_set_out_only(data, ps, ctx->sock);
1242
0
      CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1243
0
                  CURL_FORMAT_SOCKET_T, ctx->sock);
1244
0
    }
1245
36.7M
    else if(!ctx->active) {
1246
0
      Curl_pollset_add_in(data, ps, ctx->sock);
1247
0
      CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1248
0
                  CURL_FORMAT_SOCKET_T, ctx->sock);
1249
0
    }
1250
36.7M
  }
1251
36.7M
}
1252
1253
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1254
                                   const struct Curl_easy *data)
1255
176k
{
1256
176k
  struct cf_socket_ctx *ctx = cf->ctx;
1257
176k
  int readable;
1258
1259
176k
  (void)data;
1260
176k
  if(!Curl_bufq_is_empty(&ctx->recvbuf))
1261
0
    return TRUE;
1262
1263
176k
  readable = SOCKET_READABLE(ctx->sock, 0);
1264
176k
  return (readable > 0 && (readable & CURL_CSELECT_IN));
1265
176k
}
1266
1267
static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1268
                              const void *buf, size_t len, CURLcode *err)
1269
114k
{
1270
114k
  struct cf_socket_ctx *ctx = cf->ctx;
1271
114k
  curl_socket_t fdsave;
1272
114k
  ssize_t nwritten;
1273
114k
  size_t orig_len = len;
1274
1275
114k
  *err = CURLE_OK;
1276
114k
  fdsave = cf->conn->sock[cf->sockindex];
1277
114k
  cf->conn->sock[cf->sockindex] = ctx->sock;
1278
1279
114k
#ifdef DEBUGBUILD
1280
  /* simulate network blocking/partial writes */
1281
114k
  if(ctx->wblock_percent > 0) {
1282
0
    unsigned char c = 0;
1283
0
    Curl_rand(data, &c, 1);
1284
0
    if(c >= ((100-ctx->wblock_percent)*256/100)) {
1285
0
      CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1286
0
      *err = CURLE_AGAIN;
1287
0
      nwritten = -1;
1288
0
      cf->conn->sock[cf->sockindex] = fdsave;
1289
0
      return nwritten;
1290
0
    }
1291
0
  }
1292
114k
  if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1293
0
    len = len * ctx->wpartial_percent / 100;
1294
0
    if(!len)
1295
0
      len = 1;
1296
0
    CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1297
0
                orig_len, len);
1298
0
  }
1299
114k
#endif
1300
1301
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1302
  if(cf->conn->bits.tcp_fastopen) {
1303
    nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1304
                      &cf->conn->remote_addr->sa_addr,
1305
                      cf->conn->remote_addr->addrlen);
1306
    cf->conn->bits.tcp_fastopen = FALSE;
1307
  }
1308
  else
1309
#endif
1310
114k
    nwritten = swrite(ctx->sock, buf, len);
1311
1312
114k
  if(-1 == nwritten) {
1313
80
    int sockerr = SOCKERRNO;
1314
1315
80
    if(
1316
#ifdef WSAEWOULDBLOCK
1317
      /* This is how Windows does it */
1318
      (WSAEWOULDBLOCK == sockerr)
1319
#else
1320
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1321
         due to its inability to send off data without blocking. We therefore
1322
         treat both error codes the same here */
1323
80
      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1324
80
      (EINPROGRESS == sockerr)
1325
80
#endif
1326
80
      ) {
1327
      /* this is just a case of EWOULDBLOCK */
1328
80
      *err = CURLE_AGAIN;
1329
80
    }
1330
0
    else {
1331
0
      char buffer[STRERROR_LEN];
1332
0
      failf(data, "Send failure: %s",
1333
0
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
1334
0
      data->state.os_errno = sockerr;
1335
0
      *err = CURLE_SEND_ERROR;
1336
0
    }
1337
80
  }
1338
1339
114k
  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1340
114k
              orig_len, (int)nwritten, *err);
1341
114k
  cf->conn->sock[cf->sockindex] = fdsave;
1342
114k
  return nwritten;
1343
114k
}
1344
1345
static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1346
                              char *buf, size_t len, CURLcode *err)
1347
30.9M
{
1348
30.9M
  struct cf_socket_ctx *ctx = cf->ctx;
1349
30.9M
  curl_socket_t fdsave;
1350
30.9M
  ssize_t nread;
1351
1352
30.9M
  *err = CURLE_OK;
1353
1354
30.9M
  fdsave = cf->conn->sock[cf->sockindex];
1355
30.9M
  cf->conn->sock[cf->sockindex] = ctx->sock;
1356
1357
30.9M
#ifdef DEBUGBUILD
1358
  /* simulate network blocking/partial reads */
1359
30.9M
  if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1360
0
    unsigned char c = 0;
1361
0
    Curl_rand(data, &c, 1);
1362
0
    if(c >= ((100-ctx->rblock_percent)*256/100)) {
1363
0
      CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1364
0
      *err = CURLE_AGAIN;
1365
0
      nread = -1;
1366
0
      cf->conn->sock[cf->sockindex] = fdsave;
1367
0
      return nread;
1368
0
    }
1369
0
  }
1370
30.9M
  if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1371
0
    size_t orig_len = len;
1372
0
    len = ctx->recv_max;
1373
0
    CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1374
0
                orig_len, len);
1375
0
  }
1376
30.9M
#endif
1377
1378
30.9M
  if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1379
0
    CURL_TRC_CF(data, cf, "recv from buffer");
1380
0
    nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1381
0
  }
1382
30.9M
  else {
1383
30.9M
    struct reader_ctx rctx;
1384
1385
30.9M
    rctx.cf = cf;
1386
30.9M
    rctx.data = data;
1387
1388
    /* "small" reads may trigger filling our buffer, "large" reads
1389
     * are probably not worth the additional copy */
1390
30.9M
    if(ctx->buffer_recv && len < NW_SMALL_READS) {
1391
0
      ssize_t nwritten;
1392
0
      nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
1393
0
      if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1394
        /* we have a partial read with an error. need to deliver
1395
         * what we got, return the error later. */
1396
0
        CURL_TRC_CF(data, cf, "partial read: empty buffer first");
1397
0
        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1398
0
      }
1399
0
      else if(nwritten < 0) {
1400
0
        nread = -1;
1401
0
        goto out;
1402
0
      }
1403
0
      else if(nwritten == 0) {
1404
        /* eof */
1405
0
        *err = CURLE_OK;
1406
0
        nread = 0;
1407
0
      }
1408
0
      else {
1409
0
        CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
1410
0
        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1411
0
      }
1412
0
    }
1413
30.9M
    else {
1414
30.9M
      nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
1415
30.9M
    }
1416
30.9M
  }
1417
1418
30.9M
out:
1419
30.9M
  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1420
30.9M
              *err);
1421
30.9M
  if(nread > 0 && !ctx->got_first_byte) {
1422
39.0k
    ctx->first_byte_at = Curl_now();
1423
39.0k
    ctx->got_first_byte = TRUE;
1424
39.0k
  }
1425
30.9M
  cf->conn->sock[cf->sockindex] = fdsave;
1426
30.9M
  return nread;
1427
30.9M
}
1428
1429
static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1430
117k
{
1431
117k
  struct cf_socket_ctx *ctx = cf->ctx;
1432
1433
  /* use this socket from now on */
1434
117k
  cf->conn->sock[cf->sockindex] = ctx->sock;
1435
117k
  set_local_ip(cf, data);
1436
117k
  if(cf->sockindex == SECONDARYSOCKET)
1437
5.18k
    cf->conn->secondary = ctx->ip;
1438
112k
  else
1439
112k
    cf->conn->primary = ctx->ip;
1440
  /* the first socket info gets some specials */
1441
117k
  if(cf->sockindex == FIRSTSOCKET) {
1442
112k
    cf->conn->remote_addr = &ctx->addr;
1443
112k
  #ifdef USE_IPV6
1444
112k
    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
1445
112k
  #endif
1446
112k
    Curl_persistconninfo(data, cf->conn, &ctx->ip);
1447
    /* buffering is currently disabled by default because we have stalls
1448
     * in parallel transfers where not all buffered data is consumed and no
1449
     * socket events happen.
1450
     */
1451
112k
    ctx->buffer_recv = FALSE;
1452
112k
  }
1453
117k
  ctx->active = TRUE;
1454
117k
}
1455
1456
static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1457
                                struct Curl_easy *data,
1458
                                int event, int arg1, void *arg2)
1459
322k
{
1460
322k
  struct cf_socket_ctx *ctx = cf->ctx;
1461
1462
322k
  (void)arg1;
1463
322k
  (void)arg2;
1464
322k
  switch(event) {
1465
117k
  case CF_CTRL_CONN_INFO_UPDATE:
1466
117k
    cf_socket_active(cf, data);
1467
117k
    break;
1468
1.87k
  case CF_CTRL_DATA_SETUP:
1469
1.87k
    Curl_persistconninfo(data, cf->conn, &ctx->ip);
1470
1.87k
    break;
1471
0
  case CF_CTRL_FORGET_SOCKET:
1472
0
    ctx->sock = CURL_SOCKET_BAD;
1473
0
    break;
1474
322k
  }
1475
322k
  return CURLE_OK;
1476
322k
}
1477
1478
static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1479
                                    struct Curl_easy *data,
1480
                                    bool *input_pending)
1481
1.82k
{
1482
1.82k
  struct cf_socket_ctx *ctx = cf->ctx;
1483
1.82k
  struct pollfd pfd[1];
1484
1.82k
  int r;
1485
1486
1.82k
  *input_pending = FALSE;
1487
1.82k
  (void)data;
1488
1.82k
  if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1489
0
    return FALSE;
1490
1491
  /* Check with 0 timeout if there are any events pending on the socket */
1492
1.82k
  pfd[0].fd = ctx->sock;
1493
1.82k
  pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1494
1.82k
  pfd[0].revents = 0;
1495
1496
1.82k
  r = Curl_poll(pfd, 1, 0);
1497
1.82k
  if(r < 0) {
1498
0
    CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1499
0
    return FALSE;
1500
0
  }
1501
1.82k
  else if(r == 0) {
1502
411
    CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1503
411
    return TRUE;
1504
411
  }
1505
1.41k
  else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1506
0
    CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1507
0
    return FALSE;
1508
0
  }
1509
1510
1.41k
  CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1511
1.41k
  *input_pending = TRUE;
1512
1.41k
  return TRUE;
1513
1.82k
}
1514
1515
static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1516
                                struct Curl_easy *data,
1517
                                int query, int *pres1, void *pres2)
1518
5.83M
{
1519
5.83M
  struct cf_socket_ctx *ctx = cf->ctx;
1520
1521
5.83M
  switch(query) {
1522
5.72M
  case CF_QUERY_SOCKET:
1523
5.72M
    DEBUGASSERT(pres2);
1524
5.72M
    *((curl_socket_t *)pres2) = ctx->sock;
1525
5.72M
    return CURLE_OK;
1526
0
  case CF_QUERY_CONNECT_REPLY_MS:
1527
0
    if(ctx->got_first_byte) {
1528
0
      timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1529
0
      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
1530
0
    }
1531
0
    else
1532
0
      *pres1 = -1;
1533
0
    return CURLE_OK;
1534
58.7k
  case CF_QUERY_TIMER_CONNECT: {
1535
58.7k
    struct curltime *when = pres2;
1536
58.7k
    switch(ctx->transport) {
1537
467
    case TRNSPRT_UDP:
1538
467
    case TRNSPRT_QUIC:
1539
      /* Since UDP connected sockets work different from TCP, we use the
1540
       * time of the first byte from the peer as the "connect" time. */
1541
467
      if(ctx->got_first_byte) {
1542
0
        *when = ctx->first_byte_at;
1543
0
        break;
1544
0
      }
1545
467
      FALLTHROUGH();
1546
58.7k
    default:
1547
58.7k
      *when = ctx->connected_at;
1548
58.7k
      break;
1549
58.7k
    }
1550
58.7k
    return CURLE_OK;
1551
58.7k
  }
1552
57.3k
  default:
1553
57.3k
    break;
1554
5.83M
  }
1555
57.3k
  return cf->next?
1556
0
    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1557
57.3k
    CURLE_UNKNOWN_OPTION;
1558
5.83M
}
1559
1560
struct Curl_cftype Curl_cft_tcp = {
1561
  "TCP",
1562
  CF_TYPE_IP_CONNECT,
1563
  CURL_LOG_LVL_NONE,
1564
  cf_socket_destroy,
1565
  cf_tcp_connect,
1566
  cf_socket_close,
1567
  cf_socket_get_host,
1568
  cf_socket_adjust_pollset,
1569
  cf_socket_data_pending,
1570
  cf_socket_send,
1571
  cf_socket_recv,
1572
  cf_socket_cntrl,
1573
  cf_socket_conn_is_alive,
1574
  Curl_cf_def_conn_keep_alive,
1575
  cf_socket_query,
1576
};
1577
1578
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1579
                            struct Curl_easy *data,
1580
                            struct connectdata *conn,
1581
                            const struct Curl_addrinfo *ai,
1582
                            int transport)
1583
58.2k
{
1584
58.2k
  struct cf_socket_ctx *ctx = NULL;
1585
58.2k
  struct Curl_cfilter *cf = NULL;
1586
58.2k
  CURLcode result;
1587
1588
58.2k
  (void)data;
1589
58.2k
  (void)conn;
1590
58.2k
  DEBUGASSERT(transport == TRNSPRT_TCP);
1591
58.2k
  ctx = calloc(1, sizeof(*ctx));
1592
58.2k
  if(!ctx) {
1593
0
    result = CURLE_OUT_OF_MEMORY;
1594
0
    goto out;
1595
0
  }
1596
58.2k
  cf_socket_ctx_init(ctx, ai, transport);
1597
1598
58.2k
  result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1599
1600
58.2k
out:
1601
58.2k
  *pcf = (!result)? cf : NULL;
1602
58.2k
  if(result) {
1603
0
    Curl_safefree(cf);
1604
0
    Curl_safefree(ctx);
1605
0
  }
1606
1607
58.2k
  return result;
1608
58.2k
}
1609
1610
static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1611
                               struct Curl_easy *data)
1612
0
{
1613
0
  struct cf_socket_ctx *ctx = cf->ctx;
1614
0
  int rc;
1615
1616
  /* QUIC needs a connected socket, nonblocking */
1617
0
  DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1618
1619
#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
1620
  (void)rc;
1621
  /* On macOS OpenSSL QUIC fails on connected sockets.
1622
   * see: <https://github.com/openssl/openssl/issues/23251> */
1623
#else
1624
0
  rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1625
0
  if(-1 == rc) {
1626
0
    return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
1627
0
  }
1628
0
  ctx->sock_connected = TRUE;
1629
0
#endif
1630
0
  set_local_ip(cf, data);
1631
0
  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
1632
0
              " connected: [%s:%d] -> [%s:%d]",
1633
0
              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
1634
0
              ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
1635
0
              ctx->ip.remote_ip, ctx->ip.remote_port);
1636
1637
0
  (void)curlx_nonblock(ctx->sock, TRUE);
1638
0
  switch(ctx->addr.family) {
1639
0
#if defined(__linux__) && defined(IP_MTU_DISCOVER)
1640
0
  case AF_INET: {
1641
0
    int val = IP_PMTUDISC_DO;
1642
0
    (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1643
0
                     sizeof(val));
1644
0
    break;
1645
0
  }
1646
0
#endif
1647
0
#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1648
0
  case AF_INET6: {
1649
0
    int val = IPV6_PMTUDISC_DO;
1650
0
    (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1651
0
                     sizeof(val));
1652
0
    break;
1653
0
  }
1654
0
#endif
1655
0
  }
1656
0
  return CURLE_OK;
1657
0
}
1658
1659
static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1660
                               struct Curl_easy *data,
1661
                               bool blocking, bool *done)
1662
467
{
1663
467
  struct cf_socket_ctx *ctx = cf->ctx;
1664
467
  CURLcode result = CURLE_COULDNT_CONNECT;
1665
1666
467
  (void)blocking;
1667
467
  if(cf->connected) {
1668
0
    *done = TRUE;
1669
0
    return CURLE_OK;
1670
0
  }
1671
467
  *done = FALSE;
1672
467
  if(ctx->sock == CURL_SOCKET_BAD) {
1673
467
    result = cf_socket_open(cf, data);
1674
467
    if(result) {
1675
2
      CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1676
2
      goto out;
1677
2
    }
1678
1679
465
    if(ctx->transport == TRNSPRT_QUIC) {
1680
0
      result = cf_udp_setup_quic(cf, data);
1681
0
      if(result)
1682
0
        goto out;
1683
0
      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1684
0
                  CURL_FORMAT_SOCKET_T " (%s:%d)",
1685
0
                  ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
1686
0
    }
1687
465
    else {
1688
465
      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1689
465
                  CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
1690
465
    }
1691
465
    *done = TRUE;
1692
465
    cf->connected = TRUE;
1693
465
  }
1694
467
out:
1695
467
  return result;
1696
467
}
1697
1698
struct Curl_cftype Curl_cft_udp = {
1699
  "UDP",
1700
  CF_TYPE_IP_CONNECT,
1701
  CURL_LOG_LVL_NONE,
1702
  cf_socket_destroy,
1703
  cf_udp_connect,
1704
  cf_socket_close,
1705
  cf_socket_get_host,
1706
  cf_socket_adjust_pollset,
1707
  cf_socket_data_pending,
1708
  cf_socket_send,
1709
  cf_socket_recv,
1710
  cf_socket_cntrl,
1711
  cf_socket_conn_is_alive,
1712
  Curl_cf_def_conn_keep_alive,
1713
  cf_socket_query,
1714
};
1715
1716
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1717
                            struct Curl_easy *data,
1718
                            struct connectdata *conn,
1719
                            const struct Curl_addrinfo *ai,
1720
                            int transport)
1721
467
{
1722
467
  struct cf_socket_ctx *ctx = NULL;
1723
467
  struct Curl_cfilter *cf = NULL;
1724
467
  CURLcode result;
1725
1726
467
  (void)data;
1727
467
  (void)conn;
1728
467
  DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1729
467
  ctx = calloc(1, sizeof(*ctx));
1730
467
  if(!ctx) {
1731
0
    result = CURLE_OUT_OF_MEMORY;
1732
0
    goto out;
1733
0
  }
1734
467
  cf_socket_ctx_init(ctx, ai, transport);
1735
1736
467
  result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1737
1738
467
out:
1739
467
  *pcf = (!result)? cf : NULL;
1740
467
  if(result) {
1741
0
    Curl_safefree(cf);
1742
0
    Curl_safefree(ctx);
1743
0
  }
1744
1745
467
  return result;
1746
467
}
1747
1748
/* this is the TCP filter which can also handle this case */
1749
struct Curl_cftype Curl_cft_unix = {
1750
  "UNIX",
1751
  CF_TYPE_IP_CONNECT,
1752
  CURL_LOG_LVL_NONE,
1753
  cf_socket_destroy,
1754
  cf_tcp_connect,
1755
  cf_socket_close,
1756
  cf_socket_get_host,
1757
  cf_socket_adjust_pollset,
1758
  cf_socket_data_pending,
1759
  cf_socket_send,
1760
  cf_socket_recv,
1761
  cf_socket_cntrl,
1762
  cf_socket_conn_is_alive,
1763
  Curl_cf_def_conn_keep_alive,
1764
  cf_socket_query,
1765
};
1766
1767
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1768
                             struct Curl_easy *data,
1769
                             struct connectdata *conn,
1770
                             const struct Curl_addrinfo *ai,
1771
                             int transport)
1772
0
{
1773
0
  struct cf_socket_ctx *ctx = NULL;
1774
0
  struct Curl_cfilter *cf = NULL;
1775
0
  CURLcode result;
1776
1777
0
  (void)data;
1778
0
  (void)conn;
1779
0
  DEBUGASSERT(transport == TRNSPRT_UNIX);
1780
0
  ctx = calloc(1, sizeof(*ctx));
1781
0
  if(!ctx) {
1782
0
    result = CURLE_OUT_OF_MEMORY;
1783
0
    goto out;
1784
0
  }
1785
0
  cf_socket_ctx_init(ctx, ai, transport);
1786
1787
0
  result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
1788
1789
0
out:
1790
0
  *pcf = (!result)? cf : NULL;
1791
0
  if(result) {
1792
0
    Curl_safefree(cf);
1793
0
    Curl_safefree(ctx);
1794
0
  }
1795
1796
0
  return result;
1797
0
}
1798
1799
static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
1800
                                      struct Curl_easy *data,
1801
                                      bool blocking, bool *done)
1802
0
{
1803
  /* we start accepted, if we ever close, we cannot go on */
1804
0
  (void)data;
1805
0
  (void)blocking;
1806
0
  if(cf->connected) {
1807
0
    *done = TRUE;
1808
0
    return CURLE_OK;
1809
0
  }
1810
0
  return CURLE_FAILED_INIT;
1811
0
}
1812
1813
struct Curl_cftype Curl_cft_tcp_accept = {
1814
  "TCP-ACCEPT",
1815
  CF_TYPE_IP_CONNECT,
1816
  CURL_LOG_LVL_NONE,
1817
  cf_socket_destroy,
1818
  cf_tcp_accept_connect,
1819
  cf_socket_close,
1820
  cf_socket_get_host,              /* TODO: not accurate */
1821
  cf_socket_adjust_pollset,
1822
  cf_socket_data_pending,
1823
  cf_socket_send,
1824
  cf_socket_recv,
1825
  cf_socket_cntrl,
1826
  cf_socket_conn_is_alive,
1827
  Curl_cf_def_conn_keep_alive,
1828
  cf_socket_query,
1829
};
1830
1831
CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
1832
                                  struct connectdata *conn,
1833
                                  int sockindex, curl_socket_t *s)
1834
0
{
1835
0
  CURLcode result;
1836
0
  struct Curl_cfilter *cf = NULL;
1837
0
  struct cf_socket_ctx *ctx = NULL;
1838
1839
  /* replace any existing */
1840
0
  Curl_conn_cf_discard_all(data, conn, sockindex);
1841
0
  DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
1842
1843
0
  ctx = calloc(1, sizeof(*ctx));
1844
0
  if(!ctx) {
1845
0
    result = CURLE_OUT_OF_MEMORY;
1846
0
    goto out;
1847
0
  }
1848
0
  ctx->transport = conn->transport;
1849
0
  ctx->sock = *s;
1850
0
  ctx->accepted = FALSE;
1851
0
  result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
1852
0
  if(result)
1853
0
    goto out;
1854
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
1855
1856
0
  conn->sock[sockindex] = ctx->sock;
1857
0
  set_local_ip(cf, data);
1858
0
  ctx->active = TRUE;
1859
0
  ctx->connected_at = Curl_now();
1860
0
  cf->connected = TRUE;
1861
0
  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
1862
0
              CURL_FORMAT_SOCKET_T ")", ctx->sock);
1863
1864
0
out:
1865
0
  if(result) {
1866
0
    Curl_safefree(cf);
1867
0
    Curl_safefree(ctx);
1868
0
  }
1869
0
  return result;
1870
0
}
1871
1872
static void set_accepted_remote_ip(struct Curl_cfilter *cf,
1873
                                   struct Curl_easy *data)
1874
0
{
1875
0
  struct cf_socket_ctx *ctx = cf->ctx;
1876
0
#ifdef HAVE_GETPEERNAME
1877
0
  char buffer[STRERROR_LEN];
1878
0
  struct Curl_sockaddr_storage ssrem;
1879
0
  curl_socklen_t plen;
1880
1881
0
  ctx->ip.remote_ip[0] = 0;
1882
0
  ctx->ip.remote_port = 0;
1883
0
  plen = sizeof(ssrem);
1884
0
  memset(&ssrem, 0, plen);
1885
0
  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
1886
0
    int error = SOCKERRNO;
1887
0
    failf(data, "getpeername() failed with errno %d: %s",
1888
0
          error, Curl_strerror(error, buffer, sizeof(buffer)));
1889
0
    return;
1890
0
  }
1891
0
  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
1892
0
                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
1893
0
    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
1894
0
          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1895
0
    return;
1896
0
  }
1897
#else
1898
  ctx->ip.remote_ip[0] = 0;
1899
  ctx->ip.remote_port = 0;
1900
  (void)data;
1901
#endif
1902
0
}
1903
1904
CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
1905
                                    struct connectdata *conn,
1906
                                    int sockindex, curl_socket_t *s)
1907
0
{
1908
0
  struct Curl_cfilter *cf = NULL;
1909
0
  struct cf_socket_ctx *ctx = NULL;
1910
1911
0
  cf = conn->cfilter[sockindex];
1912
0
  if(!cf || cf->cft != &Curl_cft_tcp_accept)
1913
0
    return CURLE_FAILED_INIT;
1914
1915
0
  ctx = cf->ctx;
1916
  /* discard the listen socket */
1917
0
  socket_close(data, conn, TRUE, ctx->sock);
1918
0
  ctx->sock = *s;
1919
0
  conn->sock[sockindex] = ctx->sock;
1920
0
  set_accepted_remote_ip(cf, data);
1921
0
  set_local_ip(cf, data);
1922
0
  ctx->active = TRUE;
1923
0
  ctx->accepted = TRUE;
1924
0
  ctx->connected_at = Curl_now();
1925
0
  cf->connected = TRUE;
1926
0
  CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
1927
0
              ", remote=%s port=%d)",
1928
0
              ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
1929
1930
0
  return CURLE_OK;
1931
0
}
1932
1933
/**
1934
 * Return TRUE iff `cf` is a socket filter.
1935
 */
1936
static bool cf_is_socket(struct Curl_cfilter *cf)
1937
0
{
1938
0
  return cf && (cf->cft == &Curl_cft_tcp ||
1939
0
                cf->cft == &Curl_cft_udp ||
1940
0
                cf->cft == &Curl_cft_unix ||
1941
0
                cf->cft == &Curl_cft_tcp_accept);
1942
0
}
1943
1944
CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
1945
                             struct Curl_easy *data,
1946
                             curl_socket_t *psock,
1947
                             const struct Curl_sockaddr_ex **paddr,
1948
                             struct ip_quadruple *pip)
1949
0
{
1950
0
  (void)data;
1951
0
  if(cf_is_socket(cf) && cf->ctx) {
1952
0
    struct cf_socket_ctx *ctx = cf->ctx;
1953
1954
0
    if(psock)
1955
0
      *psock = ctx->sock;
1956
0
    if(paddr)
1957
0
      *paddr = &ctx->addr;
1958
0
    if(pip)
1959
0
      *pip = ctx->ip;
1960
0
    return CURLE_OK;
1961
0
  }
1962
0
  return CURLE_FAILED_INIT;
1963
0
}