Coverage Report

Created: 2024-05-04 12:45

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