Coverage Report

Created: 2025-11-11 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/cf-socket.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
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_NETINET_UDP_H
39
#include <netinet/udp.h>
40
#endif
41
#ifdef HAVE_SYS_IOCTL_H
42
#include <sys/ioctl.h>
43
#endif
44
#ifdef HAVE_NETDB_H
45
#include <netdb.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
#ifdef __DragonFly__
57
/* Required for __DragonFly_version */
58
#include <sys/param.h>
59
#endif
60
61
#include "urldata.h"
62
#include "bufq.h"
63
#include "sendf.h"
64
#include "if2ip.h"
65
#include "cfilters.h"
66
#include "cf-socket.h"
67
#include "connect.h"
68
#include "select.h"
69
#include "url.h" /* for Curl_safefree() */
70
#include "multiif.h"
71
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
72
#include "curlx/inet_pton.h"
73
#include "progress.h"
74
#include "curlx/warnless.h"
75
#include "conncache.h"
76
#include "multihandle.h"
77
#include "rand.h"
78
#include "share.h"
79
#include "strdup.h"
80
#include "system_win32.h"
81
#include "curlx/version_win32.h"
82
#include "curlx/strerr.h"
83
#include "curlx/strparse.h"
84
85
/* The last 2 #include files should be in this order */
86
#include "curl_memory.h"
87
#include "memdebug.h"
88
89
90
#if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
91
/* It makes support for IPv4-mapped IPv6 addresses.
92
 * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
93
 * Windows Vista and later: default is on;
94
 * DragonFly BSD: acts like off, and dummy setting;
95
 * OpenBSD and earlier Windows: unsupported.
96
 * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
97
 */
98
static void set_ipv6_v6only(curl_socket_t sockfd, int on)
99
{
100
  (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
101
}
102
#else
103
#define set_ipv6_v6only(x,y)
104
#endif
105
106
static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
107
97.1k
{
108
97.1k
#if defined(TCP_NODELAY) && defined(CURL_TCP_NODELAY_SUPPORTED)
109
97.1k
  curl_socklen_t onoff = (curl_socklen_t) 1;
110
97.1k
  int level = IPPROTO_TCP;
111
97.1k
  char buffer[STRERROR_LEN];
112
113
97.1k
  if(setsockopt(sockfd, level, TCP_NODELAY,
114
97.1k
                (void *)&onoff, sizeof(onoff)) < 0)
115
96.1k
    infof(data, "Could not set TCP_NODELAY: %s",
116
97.1k
          curlx_strerror(SOCKERRNO, buffer, sizeof(buffer)));
117
#else
118
  (void)data;
119
  (void)sockfd;
120
#endif
121
97.1k
}
122
123
#ifdef SO_NOSIGPIPE
124
/* The preferred method on macOS (10.2 and later) to prevent SIGPIPEs when
125
   sending data to a dead peer (instead of relying on the 4th argument to send
126
   being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
127
   systems? */
128
static void nosigpipe(struct Curl_easy *data,
129
                      curl_socket_t sockfd)
130
{
131
  int onoff = 1;
132
  (void)data;
133
  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE,
134
                (void *)&onoff, sizeof(onoff)) < 0) {
135
#ifndef CURL_DISABLE_VERBOSE_STRINGS
136
    char buffer[STRERROR_LEN];
137
    infof(data, "Could not set SO_NOSIGPIPE: %s",
138
          curlx_strerror(SOCKERRNO, buffer, sizeof(buffer)));
139
#endif
140
  }
141
}
142
#else
143
101k
#define nosigpipe(x,y) Curl_nop_stmt
144
#endif
145
146
#if defined(USE_WINSOCK) && \
147
    defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
148
/*  Win 10, v 1709 (10.0.16299) and later can use SetSockOpt TCP_KEEP____
149
 *  so should use seconds */
150
#define CURL_WINSOCK_KEEP_SSO
151
#define KEEPALIVE_FACTOR(x)
152
#elif defined(USE_WINSOCK) || \
153
   (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
154
   (defined(__DragonFly__) && __DragonFly_version < 500702) || \
155
   (defined(_WIN32) && !defined(TCP_KEEPIDLE))
156
/* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
157
 * use millisecond units. */
158
#define KEEPALIVE_FACTOR(x) (x *= 1000)
159
#else
160
#define KEEPALIVE_FACTOR(x)
161
#endif
162
163
/* Offered by mingw-w64 and MS SDK. Latter only when targeting Win7+. */
164
#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
165
#define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
166
167
struct tcp_keepalive {
168
  u_long onoff;
169
  u_long keepalivetime;
170
  u_long keepaliveinterval;
171
};
172
#endif
173
174
static void
175
tcpkeepalive(struct Curl_easy *data,
176
             curl_socket_t sockfd)
177
410
{
178
410
  int optval = data->set.tcp_keepalive ? 1 : 0;
179
180
  /* only set IDLE and INTVL if setting KEEPALIVE is successful */
181
410
  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
182
410
                (void *)&optval, sizeof(optval)) < 0) {
183
0
    infof(data, "Failed to set SO_KEEPALIVE on fd "
184
0
          "%" FMT_SOCKET_T ": errno %d",
185
0
          sockfd, SOCKERRNO);
186
0
  }
187
410
  else {
188
#ifdef SIO_KEEPALIVE_VALS /* Windows */
189
/* Windows 10, version 1709 (10.0.16299) and later versions */
190
#ifdef CURL_WINSOCK_KEEP_SSO
191
    optval = curlx_sltosi(data->set.tcp_keepidle);
192
    KEEPALIVE_FACTOR(optval);
193
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
194
                (const char *)&optval, sizeof(optval)) < 0) {
195
      infof(data, "Failed to set TCP_KEEPIDLE on fd "
196
            "%" FMT_SOCKET_T ": errno %d",
197
            sockfd, SOCKERRNO);
198
    }
199
    optval = curlx_sltosi(data->set.tcp_keepintvl);
200
    KEEPALIVE_FACTOR(optval);
201
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
202
                (const char *)&optval, sizeof(optval)) < 0) {
203
      infof(data, "Failed to set TCP_KEEPINTVL on fd "
204
            "%" FMT_SOCKET_T ": errno %d",
205
            sockfd, SOCKERRNO);
206
    }
207
    optval = curlx_sltosi(data->set.tcp_keepcnt);
208
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
209
                (const char *)&optval, sizeof(optval)) < 0) {
210
      infof(data, "Failed to set TCP_KEEPCNT on fd "
211
            "%" FMT_SOCKET_T ": errno %d",
212
            sockfd, SOCKERRNO);
213
    }
214
#else /* Windows < 10.0.16299 */
215
    struct tcp_keepalive vals;
216
    DWORD dummy;
217
    vals.onoff = 1;
218
    optval = curlx_sltosi(data->set.tcp_keepidle);
219
    KEEPALIVE_FACTOR(optval);
220
    vals.keepalivetime = (u_long)optval;
221
    optval = curlx_sltosi(data->set.tcp_keepintvl);
222
    KEEPALIVE_FACTOR(optval);
223
    vals.keepaliveinterval = (u_long)optval;
224
    if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
225
                NULL, 0, &dummy, NULL, NULL) != 0) {
226
      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
227
            "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
228
    }
229
#endif
230
#else /* !Windows */
231
410
#ifdef TCP_KEEPIDLE
232
410
    optval = curlx_sltosi(data->set.tcp_keepidle);
233
410
    KEEPALIVE_FACTOR(optval);
234
410
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
235
410
                  (void *)&optval, sizeof(optval)) < 0) {
236
410
      infof(data, "Failed to set TCP_KEEPIDLE on fd "
237
410
            "%" FMT_SOCKET_T ": errno %d",
238
410
            sockfd, SOCKERRNO);
239
410
    }
240
#elif defined(TCP_KEEPALIVE)
241
    /* macOS style */
242
    optval = curlx_sltosi(data->set.tcp_keepidle);
243
    KEEPALIVE_FACTOR(optval);
244
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
245
                  (void *)&optval, sizeof(optval)) < 0) {
246
      infof(data, "Failed to set TCP_KEEPALIVE on fd "
247
            "%" FMT_SOCKET_T ": errno %d",
248
            sockfd, SOCKERRNO);
249
    }
250
#elif defined(TCP_KEEPALIVE_THRESHOLD)
251
    /* Solaris <11.4 style */
252
    optval = curlx_sltosi(data->set.tcp_keepidle);
253
    KEEPALIVE_FACTOR(optval);
254
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
255
                  (void *)&optval, sizeof(optval)) < 0) {
256
      infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
257
            "%" FMT_SOCKET_T ": errno %d",
258
            sockfd, SOCKERRNO);
259
    }
260
#endif
261
410
#ifdef TCP_KEEPINTVL
262
410
    optval = curlx_sltosi(data->set.tcp_keepintvl);
263
410
    KEEPALIVE_FACTOR(optval);
264
410
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
265
410
                  (void *)&optval, sizeof(optval)) < 0) {
266
410
      infof(data, "Failed to set TCP_KEEPINTVL on fd "
267
410
            "%" FMT_SOCKET_T ": errno %d",
268
410
            sockfd, SOCKERRNO);
269
410
    }
270
#elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
271
    /* Solaris <11.4 style */
272
    /* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
273
     * TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
274
     * The default value of TCP_KEEPCNT is 9 on Linux,
275
     * 8 on *BSD/macOS, 5 or 10 on Windows. We use the
276
     * default config for Solaris <11.4 because there is
277
     * no default value for TCP_KEEPCNT on Solaris 11.4.
278
     *
279
     * Note that the consequent probes will not be sent
280
     * at equal intervals on Solaris, but will be sent
281
     * using the exponential backoff algorithm. */
282
    optval = curlx_sltosi(data->set.tcp_keepcnt) *
283
             curlx_sltosi(data->set.tcp_keepintvl);
284
    KEEPALIVE_FACTOR(optval);
285
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
286
                  (void *)&optval, sizeof(optval)) < 0) {
287
      infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
288
            "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
289
    }
290
#endif
291
410
#ifdef TCP_KEEPCNT
292
410
    optval = curlx_sltosi(data->set.tcp_keepcnt);
293
410
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
294
410
                  (void *)&optval, sizeof(optval)) < 0) {
295
410
      infof(data, "Failed to set TCP_KEEPCNT on fd "
296
410
            "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
297
410
    }
298
410
#endif
299
410
#endif
300
410
  }
301
410
}
302
303
/**
304
 * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
305
 * set the transport used.
306
 */
307
static CURLcode sock_assign_addr(struct Curl_sockaddr_ex *dest,
308
                                 const struct Curl_addrinfo *ai,
309
                                 int transport)
310
114k
{
311
  /*
312
   * The Curl_sockaddr_ex structure is basically libcurl's external API
313
   * curl_sockaddr structure with enough space available to directly hold
314
   * any protocol-specific address structures. The variable declared here
315
   * will be used to pass / receive data to/from the fopensocket callback
316
   * if this has been set, before that, it is initialized from parameters.
317
   */
318
114k
  dest->family = ai->ai_family;
319
114k
  switch(transport) {
320
108k
  case TRNSPRT_TCP:
321
108k
    dest->socktype = SOCK_STREAM;
322
108k
    dest->protocol = IPPROTO_TCP;
323
108k
    break;
324
2.63k
  case TRNSPRT_UNIX:
325
2.63k
    dest->socktype = SOCK_STREAM;
326
2.63k
    dest->protocol = IPPROTO_IP;
327
2.63k
    break;
328
3.48k
  default: /* UDP and QUIC */
329
3.48k
    dest->socktype = SOCK_DGRAM;
330
3.48k
    dest->protocol = IPPROTO_UDP;
331
3.48k
    break;
332
114k
  }
333
114k
  dest->addrlen = (unsigned int)ai->ai_addrlen;
334
335
114k
  DEBUGASSERT(dest->addrlen <= sizeof(dest->curl_sa_addrbuf));
336
114k
  if(dest->addrlen > sizeof(dest->curl_sa_addrbuf))
337
0
    return CURLE_TOO_LARGE;
338
339
114k
  memcpy(&dest->curl_sa_addrbuf, ai->ai_addr, dest->addrlen);
340
114k
  return CURLE_OK;
341
114k
}
342
343
static CURLcode socket_open(struct Curl_easy *data,
344
                            struct Curl_sockaddr_ex *addr,
345
                            curl_socket_t *sockfd)
346
114k
{
347
114k
  char errbuf[STRERROR_LEN];
348
349
114k
  DEBUGASSERT(data);
350
114k
  DEBUGASSERT(data->conn);
351
114k
  if(data->set.fopensocket) {
352
   /*
353
    * If the opensocket callback is set, all the destination address
354
    * information is passed to the callback. Depending on this information the
355
    * callback may opt to abort the connection, this is indicated returning
356
    * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
357
    * the callback returns a valid socket the destination address information
358
    * might have been changed and this 'new' address will actually be used
359
    * here to connect.
360
    */
361
113k
    Curl_set_in_callback(data, TRUE);
362
113k
    *sockfd = data->set.fopensocket(data->set.opensocket_client,
363
113k
                                    CURLSOCKTYPE_IPCXN,
364
113k
                                    (struct curl_sockaddr *)addr);
365
113k
    Curl_set_in_callback(data, FALSE);
366
113k
  }
367
992
  else {
368
    /* opensocket callback not set, so simply create the socket now */
369
992
    *sockfd = CURL_SOCKET(addr->family, addr->socktype, addr->protocol);
370
992
  }
371
372
114k
  if(*sockfd == CURL_SOCKET_BAD) {
373
    /* no socket, no connection */
374
12.7k
    failf(data, "failed to open socket: %s",
375
12.7k
          curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf)));
376
12.7k
    return CURLE_COULDNT_CONNECT;
377
12.7k
  }
378
379
102k
#ifdef HAVE_FCNTL
380
102k
  if(fcntl(*sockfd, F_SETFD, FD_CLOEXEC) < 0) {
381
0
    failf(data, "fcntl set CLOEXEC: %s",
382
0
          curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf)));
383
0
    close(*sockfd);
384
0
    *sockfd = CURL_SOCKET_BAD;
385
0
    return CURLE_COULDNT_CONNECT;
386
0
  }
387
102k
#endif
388
389
102k
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
390
102k
  if(data->conn->scope_id && (addr->family == AF_INET6)) {
391
116
    struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr;
392
116
    sa6->sin6_scope_id = data->conn->scope_id;
393
116
  }
394
102k
#endif
395
102k
  return CURLE_OK;
396
102k
}
397
398
/*
399
 * Create a socket based on info from 'conn' and 'ai'.
400
 *
401
 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
402
 * 'sockfd' must be a pointer to a socket descriptor.
403
 *
404
 * If the open socket callback is set, used that!
405
 *
406
 */
407
CURLcode Curl_socket_open(struct Curl_easy *data,
408
                          const struct Curl_addrinfo *ai,
409
                          struct Curl_sockaddr_ex *addr,
410
                          int transport,
411
                          curl_socket_t *sockfd)
412
12.6k
{
413
12.6k
  struct Curl_sockaddr_ex dummy;
414
12.6k
  CURLcode result;
415
416
12.6k
  if(!addr)
417
    /* if the caller does not want info back, use a local temp copy */
418
12.6k
    addr = &dummy;
419
420
12.6k
  result = sock_assign_addr(addr, ai, transport);
421
12.6k
  if(result)
422
0
    return result;
423
424
12.6k
  return socket_open(data, addr, sockfd);
425
12.6k
}
426
427
static int socket_close(struct Curl_easy *data, struct connectdata *conn,
428
                        int use_callback, curl_socket_t sock)
429
102k
{
430
102k
  if(CURL_SOCKET_BAD == sock)
431
0
    return 0;
432
433
102k
  if(use_callback && conn && conn->fclosesocket) {
434
0
    int rc;
435
0
    Curl_multi_will_close(data, sock);
436
0
    Curl_set_in_callback(data, TRUE);
437
0
    rc = conn->fclosesocket(conn->closesocket_client, sock);
438
0
    Curl_set_in_callback(data, FALSE);
439
0
    return rc;
440
0
  }
441
442
102k
  if(conn)
443
    /* tell the multi-socket code about this */
444
102k
    Curl_multi_will_close(data, sock);
445
446
102k
  sclose(sock);
447
448
102k
  return 0;
449
102k
}
450
451
/*
452
 * Close a socket.
453
 *
454
 * 'conn' can be NULL, beware!
455
 */
456
int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
457
                      curl_socket_t sock)
458
307
{
459
307
  return socket_close(data, conn, FALSE, sock);
460
307
}
461
462
#ifdef USE_WINSOCK
463
/* When you run a program that uses the Windows Sockets API, you may
464
   experience slow performance when you copy data to a TCP server.
465
466
   https://learn.microsoft.com/troubleshoot/windows-server/networking/slow-performance-copy-data-tcp-server-sockets-api
467
468
   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
469
   Buffer Size
470
471
   The problem described in this knowledge-base is applied only to pre-Vista
472
   Windows. Following function trying to detect OS version and skips
473
   SO_SNDBUF adjustment for Windows Vista and above.
474
*/
475
476
void Curl_sndbuf_init(curl_socket_t sockfd)
477
{
478
  int val = CURL_MAX_WRITE_SIZE + 32;
479
  int curval = 0;
480
  int curlen = sizeof(curval);
481
482
  if(Curl_isVistaOrGreater)
483
    return;
484
485
  if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
486
    if(curval > val)
487
      return;
488
489
  setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
490
}
491
#endif /* USE_WINSOCK */
492
493
/*
494
 * Curl_parse_interface()
495
 *
496
 * This is used to parse interface argument in the following formats.
497
 * In all the examples, `host` can be an IP address or a hostname.
498
 *
499
 *   <iface_or_host> - can be either an interface name or a host.
500
 *   if!<iface> - interface name.
501
 *   host!<host> - hostname.
502
 *   ifhost!<iface>!<host> - interface name and hostname.
503
 *
504
 * Parameters:
505
 *
506
 * input  [in]     - input string.
507
 * len    [in]     - length of the input string.
508
 * dev    [in/out] - address where a pointer to newly allocated memory
509
 *                   holding the interface-or-host will be stored upon
510
 *                   completion.
511
 * iface  [in/out] - address where a pointer to newly allocated memory
512
 *                   holding the interface will be stored upon completion.
513
 * host   [in/out] - address where a pointer to newly allocated memory
514
 *                   holding the host will be stored upon completion.
515
 *
516
 * Returns CURLE_OK on success.
517
 */
518
CURLcode Curl_parse_interface(const char *input,
519
                              char **dev, char **iface, char **host)
520
2.76k
{
521
2.76k
  static const char if_prefix[] = "if!";
522
2.76k
  static const char host_prefix[] = "host!";
523
2.76k
  static const char if_host_prefix[] = "ifhost!";
524
2.76k
  size_t len;
525
526
2.76k
  DEBUGASSERT(dev);
527
2.76k
  DEBUGASSERT(iface);
528
2.76k
  DEBUGASSERT(host);
529
530
2.76k
  len = strlen(input);
531
2.76k
  if(len > 512)
532
15
    return CURLE_BAD_FUNCTION_ARGUMENT;
533
534
2.75k
  if(!strncmp(if_prefix, input, strlen(if_prefix))) {
535
97
    input += strlen(if_prefix);
536
97
    if(!*input)
537
15
      return CURLE_BAD_FUNCTION_ARGUMENT;
538
82
    *iface = Curl_memdup0(input, len - strlen(if_prefix));
539
82
    return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
540
97
  }
541
2.65k
  else if(!strncmp(host_prefix, input, strlen(host_prefix))) {
542
90
    input += strlen(host_prefix);
543
90
    if(!*input)
544
15
      return CURLE_BAD_FUNCTION_ARGUMENT;
545
75
    *host = Curl_memdup0(input, len - strlen(host_prefix));
546
75
    return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
547
90
  }
548
2.56k
  else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) {
549
97
    const char *host_part;
550
97
    input += strlen(if_host_prefix);
551
97
    len -= strlen(if_host_prefix);
552
97
    host_part = memchr(input, '!', len);
553
97
    if(!host_part || !*(host_part + 1))
554
30
      return CURLE_BAD_FUNCTION_ARGUMENT;
555
67
    *iface = Curl_memdup0(input, host_part - input);
556
67
    if(!*iface)
557
0
      return CURLE_OUT_OF_MEMORY;
558
67
    ++host_part;
559
67
    *host = Curl_memdup0(host_part, len - (host_part - input));
560
67
    if(!*host) {
561
0
      free(*iface);
562
0
      *iface = NULL;
563
0
      return CURLE_OUT_OF_MEMORY;
564
0
    }
565
67
    return CURLE_OK;
566
67
  }
567
568
2.46k
  if(!*input)
569
17
    return CURLE_BAD_FUNCTION_ARGUMENT;
570
2.45k
  *dev = Curl_memdup0(input, len);
571
2.45k
  return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
572
2.46k
}
573
574
#ifndef CURL_DISABLE_BINDLOCAL
575
static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
576
                          curl_socket_t sockfd, int af, unsigned int scope)
577
100k
{
578
100k
  struct Curl_sockaddr_storage sa;
579
100k
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
580
100k
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
581
100k
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
582
100k
#ifdef USE_IPV6
583
100k
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
584
100k
#endif
585
586
100k
  struct Curl_dns_entry *h = NULL;
587
100k
  unsigned short port = data->set.localport; /* use this port number, 0 for
588
                                                "random" */
589
  /* how many port numbers to try to bind to, increasing one at a time */
590
100k
  int portnum = data->set.localportrange;
591
100k
  const char *dev = data->set.str[STRING_DEVICE];
592
100k
  const char *iface_input = data->set.str[STRING_INTERFACE];
593
100k
  const char *host_input = data->set.str[STRING_BINDHOST];
594
100k
  const char *iface = iface_input ? iface_input : dev;
595
100k
  const char *host = host_input ? host_input : dev;
596
100k
  int error;
597
100k
#ifdef IP_BIND_ADDRESS_NO_PORT
598
100k
  int on = 1;
599
100k
#endif
600
#ifndef USE_IPV6
601
  (void)scope;
602
#endif
603
604
  /*************************************************************
605
   * Select device to bind socket to
606
   *************************************************************/
607
100k
  if(!iface && !host && !port)
608
    /* no local kind of binding was requested */
609
99.1k
    return CURLE_OK;
610
1.50k
  else if(iface && (strlen(iface) >= 255) )
611
35
    return CURLE_BAD_FUNCTION_ARGUMENT;
612
613
1.47k
  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
614
615
1.47k
  if(iface || host) {
616
1.27k
    char myhost[256] = "";
617
1.27k
    int done = 0; /* -1 for error, 1 for address found */
618
1.27k
    if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
619
620
1.27k
#ifdef SO_BINDTODEVICE
621
1.27k
    if(iface) {
622
      /*
623
       * This binds the local socket to a particular interface. This will
624
       * force even requests to other local interfaces to go out the external
625
       * interface. Only bind to the interface when specified as interface,
626
       * not just as a hostname or ip address.
627
       *
628
       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
629
       * converted to an IP address and would fail Curl_if2ip. Simply try to
630
       * use it straight away.
631
       */
632
1.22k
      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
633
1.22k
                    iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
634
        /* This is often "errno 1, error: Operation not permitted" if you are
635
         * not running as root or another suitable privileged user. If it
636
         * succeeds it means the parameter was a valid interface and not an IP
637
         * address. Return immediately.
638
         */
639
51
        if(!host_input) {
640
19
          infof(data, "socket successfully bound to interface '%s'", iface);
641
19
          return CURLE_OK;
642
19
        }
643
51
      }
644
1.22k
    }
645
1.26k
#endif
646
1.26k
    if(!host_input) {
647
      /* Discover IP from input device, then bind to it */
648
1.16k
      if2ip_result = Curl_if2ip(af,
649
1.16k
#ifdef USE_IPV6
650
1.16k
                      scope, conn->scope_id,
651
1.16k
#endif
652
1.16k
                      iface, myhost, sizeof(myhost));
653
1.16k
    }
654
1.26k
    switch(if2ip_result) {
655
1.22k
      case IF2IP_NOT_FOUND:
656
1.22k
        if(iface_input && !host_input) {
657
          /* Do not fall back to treating it as a hostname */
658
35
          char buffer[STRERROR_LEN];
659
35
          data->state.os_errno = error = SOCKERRNO;
660
35
          failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
661
35
                iface, error, curlx_strerror(error, buffer, sizeof(buffer)));
662
35
          return CURLE_INTERFACE_FAILED;
663
35
        }
664
1.19k
        break;
665
1.19k
      case IF2IP_AF_NOT_SUPPORTED:
666
        /* Signal the caller to try another address family if available */
667
10
        return CURLE_UNSUPPORTED_PROTOCOL;
668
23
      case IF2IP_FOUND:
669
        /*
670
          * We now have the numerical IP address in the 'myhost' buffer
671
          */
672
23
        host = myhost;
673
23
        infof(data, "Local Interface %s is ip %s using address family %i",
674
23
              iface, host, af);
675
23
        done = 1;
676
23
        break;
677
1.26k
    }
678
1.21k
    if(!iface_input || host_input) {
679
      /*
680
       * This was not an interface, resolve the name as a hostname
681
       * or IP number
682
       *
683
       * Temporarily force name resolution to use only the address type
684
       * of the connection. The resolve functions should really be changed
685
       * to take a type parameter instead.
686
       */
687
1.21k
      int ip_version = (af == AF_INET) ?
688
882
                       CURL_IPRESOLVE_V4 : CURL_IPRESOLVE_WHATEVER;
689
1.21k
#ifdef USE_IPV6
690
1.21k
      if(af == AF_INET6)
691
331
        ip_version = CURL_IPRESOLVE_V6;
692
1.21k
#endif
693
694
1.21k
      (void)Curl_resolv_blocking(data, host, 80, ip_version, &h);
695
1.21k
      if(h) {
696
566
        int h_af = h->addr->ai_family;
697
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
698
566
        Curl_printable_address(h->addr, myhost, sizeof(myhost));
699
566
        infof(data, "Name '%s' family %i resolved to '%s' family %i",
700
566
              host, af, myhost, h_af);
701
566
        Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */
702
566
        if(af != h_af) {
703
          /* bad IP version combo, signal the caller to try another address
704
             family if available */
705
208
          return CURLE_UNSUPPORTED_PROTOCOL;
706
208
        }
707
358
        done = 1;
708
358
      }
709
647
      else {
710
        /*
711
         * provided dev was no interface (or interfaces are not supported
712
         * e.g. Solaris) no ip address and no domain we fail here
713
         */
714
647
        done = -1;
715
647
      }
716
1.21k
    }
717
718
1.00k
    if(done > 0) {
719
360
#ifdef USE_IPV6
720
      /* IPv6 address */
721
360
      if(af == AF_INET6) {
722
200
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
723
200
        char *scope_ptr = strchr(myhost, '%');
724
200
        if(scope_ptr)
725
0
          *(scope_ptr++) = '\0';
726
200
#endif
727
200
        if(curlx_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
728
200
          si6->sin6_family = AF_INET6;
729
200
          si6->sin6_port = htons(port);
730
200
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
731
200
          if(scope_ptr) {
732
            /* The "myhost" string either comes from Curl_if2ip or from
733
               Curl_printable_address. The latter returns only numeric scope
734
               IDs and the former returns none at all. So the scope ID, if
735
               present, is known to be numeric */
736
0
            curl_off_t scope_id;
737
0
            if(curlx_str_number((const char **)CURL_UNCONST(&scope_ptr),
738
0
                               &scope_id, UINT_MAX))
739
0
              return CURLE_UNSUPPORTED_PROTOCOL;
740
0
            si6->sin6_scope_id = (unsigned int)scope_id;
741
0
          }
742
200
#endif
743
200
        }
744
200
        sizeof_sa = sizeof(struct sockaddr_in6);
745
200
      }
746
160
      else
747
160
#endif
748
      /* IPv4 address */
749
160
      if((af == AF_INET) &&
750
160
         (curlx_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
751
160
        si4->sin_family = AF_INET;
752
160
        si4->sin_port = htons(port);
753
160
        sizeof_sa = sizeof(struct sockaddr_in);
754
160
      }
755
360
    }
756
757
1.00k
    if(done < 1) {
758
      /* errorbuf is set false so failf will overwrite any message already in
759
         the error buffer, so the user receives this error message instead of a
760
         generic resolve error. */
761
647
      char buffer[STRERROR_LEN];
762
647
      data->state.errorbuf = FALSE;
763
647
      data->state.os_errno = error = SOCKERRNO;
764
647
      failf(data, "Couldn't bind to '%s' with errno %d: %s", host,
765
647
            error, curlx_strerror(error, buffer, sizeof(buffer)));
766
647
      return CURLE_INTERFACE_FAILED;
767
647
    }
768
1.00k
  }
769
194
  else {
770
    /* no device was given, prepare sa to match af's needs */
771
194
#ifdef USE_IPV6
772
194
    if(af == AF_INET6) {
773
20
      si6->sin6_family = AF_INET6;
774
20
      si6->sin6_port = htons(port);
775
20
      sizeof_sa = sizeof(struct sockaddr_in6);
776
20
    }
777
174
    else
778
174
#endif
779
174
    if(af == AF_INET) {
780
174
      si4->sin_family = AF_INET;
781
174
      si4->sin_port = htons(port);
782
174
      sizeof_sa = sizeof(struct sockaddr_in);
783
174
    }
784
194
  }
785
554
#ifdef IP_BIND_ADDRESS_NO_PORT
786
554
  (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
787
554
#endif
788
1.01M
  for(;;) {
789
1.01M
    if(bind(sockfd, sock, sizeof_sa) >= 0) {
790
      /* we succeeded to bind */
791
0
      infof(data, "Local port: %hu", port);
792
0
      conn->bits.bound = TRUE;
793
0
      return CURLE_OK;
794
0
    }
795
796
1.01M
    if(--portnum > 0) {
797
1.01M
      port++; /* try next port */
798
1.01M
      if(port == 0)
799
81
        break;
800
1.01M
      infof(data, "Bind to local port %d failed, trying next", port - 1);
801
      /* We reuse/clobber the port variable here below */
802
1.01M
      if(sock->sa_family == AF_INET)
803
935k
        si4->sin_port = htons(port);
804
80.3k
#ifdef USE_IPV6
805
80.3k
      else
806
80.3k
        si6->sin6_port = htons(port);
807
1.01M
#endif
808
1.01M
    }
809
473
    else
810
473
      break;
811
1.01M
  }
812
554
  {
813
554
    char buffer[STRERROR_LEN];
814
554
    data->state.os_errno = error = SOCKERRNO;
815
554
    failf(data, "bind failed with errno %d: %s",
816
554
          error, curlx_strerror(error, buffer, sizeof(buffer)));
817
554
  }
818
819
554
  return CURLE_INTERFACE_FAILED;
820
554
}
821
#endif
822
823
/*
824
 * verifyconnect() returns TRUE if the connect really has happened.
825
 */
826
static bool verifyconnect(curl_socket_t sockfd, int *error)
827
298
{
828
298
  bool rc = TRUE;
829
298
#ifdef SO_ERROR
830
298
  int err = 0;
831
298
  curl_socklen_t errSize = sizeof(err);
832
833
#ifdef _WIN32
834
  /*
835
   * In October 2003 we effectively nullified this function on Windows due to
836
   * problems with it using all CPU in multi-threaded cases.
837
   *
838
   * In May 2004, we brought it back to offer more info back on connect
839
   * failures. We could reproduce the former problems with this function, but
840
   * could avoid them by adding this SleepEx() call below:
841
   *
842
   *    "I do not have Rational Quantify, but the hint from his post was
843
   *    ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
844
   *    just Sleep(0) would be enough?) would release whatever
845
   *    mutex/critical-section the ntdll call is waiting on.
846
   *
847
   *    Someone got to verify this on Win-NT 4.0, 2000."
848
   */
849
850
#ifdef UNDER_CE
851
  Sleep(0);
852
#else
853
  SleepEx(0, FALSE);
854
#endif
855
856
#endif
857
858
298
  if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
859
0
    err = SOCKERRNO;
860
#ifdef UNDER_CE
861
  /* Old Windows CE versions do not support SO_ERROR */
862
  if(WSAENOPROTOOPT == err) {
863
    SET_SOCKERRNO(0);
864
    err = 0;
865
  }
866
#endif
867
#if defined(EBADIOCTL) && defined(__minix)
868
  /* Minix 3.1.x does not support getsockopt on UDP sockets */
869
  if(EBADIOCTL == err) {
870
    SET_SOCKERRNO(0);
871
    err = 0;
872
  }
873
#endif
874
298
  if((err == 0) || (SOCKEISCONN == err))
875
    /* we are connected, awesome! */
876
16
    rc = TRUE;
877
282
  else
878
    /* This was not a successful connect */
879
282
    rc = FALSE;
880
298
  if(error)
881
298
    *error = err;
882
#else
883
  (void)sockfd;
884
  if(error)
885
    *error = SOCKERRNO;
886
#endif
887
298
  return rc;
888
298
}
889
890
/**
891
 * Determine the curl code for a socket connect() == -1 with errno.
892
 */
893
static CURLcode socket_connect_result(struct Curl_easy *data,
894
                                      const char *ipaddress, int error)
895
992
{
896
992
  switch(error) {
897
784
  case SOCKEINPROGRESS:
898
784
  case SOCKEWOULDBLOCK:
899
784
#ifdef EAGAIN
900
#if (EAGAIN) != (SOCKEWOULDBLOCK)
901
    /* On some platforms EAGAIN and EWOULDBLOCK are the
902
     * same value, and on others they are different, hence
903
     * the odd #if
904
     */
905
  case EAGAIN:
906
#endif
907
784
#endif
908
784
    return CURLE_OK;
909
910
208
  default:
911
    /* unknown error, fallthrough and try another address! */
912
#ifdef CURL_DISABLE_VERBOSE_STRINGS
913
    (void)ipaddress;
914
#else
915
208
    {
916
208
      char buffer[STRERROR_LEN];
917
208
      infof(data, "Immediate connect fail for %s: %s", ipaddress,
918
208
            curlx_strerror(error, buffer, sizeof(buffer)));
919
208
    }
920
208
#endif
921
208
    data->state.os_errno = error;
922
    /* connect failed */
923
208
    return CURLE_COULDNT_CONNECT;
924
992
  }
925
992
}
926
927
struct cf_socket_ctx {
928
  int transport;
929
  struct Curl_sockaddr_ex addr;      /* address to connect to */
930
  curl_socket_t sock;                /* current attempt socket */
931
  struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
932
  struct curltime started_at;        /* when socket was created */
933
  struct curltime connected_at;      /* when socket connected/got first byte */
934
  struct curltime first_byte_at;     /* when first byte was recvd */
935
#ifdef USE_WINSOCK
936
  struct curltime last_sndbuf_query_at;  /* when SO_SNDBUF last queried */
937
  ULONG sndbuf_size;                     /* the last set SO_SNDBUF size */
938
#endif
939
  int error;                         /* errno of last failure or 0 */
940
#ifdef DEBUGBUILD
941
  int wblock_percent;                /* percent of writes doing EAGAIN */
942
  int wpartial_percent;              /* percent of bytes written in send */
943
  int rblock_percent;                /* percent of reads doing EAGAIN */
944
  size_t recv_max;                  /* max enforced read size */
945
#endif
946
  BIT(got_first_byte);               /* if first byte was received */
947
  BIT(listening);                    /* socket is listening */
948
  BIT(accepted);                     /* socket was accepted, not connected */
949
  BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
950
  BIT(active);
951
};
952
953
static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
954
                                   const struct Curl_addrinfo *ai,
955
                                   int transport)
956
102k
{
957
102k
  CURLcode result;
958
959
102k
  memset(ctx, 0, sizeof(*ctx));
960
102k
  ctx->sock = CURL_SOCKET_BAD;
961
102k
  ctx->transport = transport;
962
963
102k
  result = sock_assign_addr(&ctx->addr, ai, transport);
964
102k
  if(result)
965
0
    return result;
966
967
102k
#ifdef DEBUGBUILD
968
102k
  {
969
102k
    const char *p = getenv("CURL_DBG_SOCK_WBLOCK");
970
102k
    if(p) {
971
0
      curl_off_t l;
972
0
      if(!curlx_str_number(&p, &l, 100))
973
0
        ctx->wblock_percent = (int)l;
974
0
    }
975
102k
    p = getenv("CURL_DBG_SOCK_WPARTIAL");
976
102k
    if(p) {
977
0
      curl_off_t l;
978
0
      if(!curlx_str_number(&p, &l, 100))
979
0
        ctx->wpartial_percent = (int)l;
980
0
    }
981
102k
    p = getenv("CURL_DBG_SOCK_RBLOCK");
982
102k
    if(p) {
983
0
      curl_off_t l;
984
0
      if(!curlx_str_number(&p, &l, 100))
985
0
        ctx->rblock_percent = (int)l;
986
0
    }
987
102k
    p = getenv("CURL_DBG_SOCK_RMAX");
988
102k
    if(p) {
989
0
      curl_off_t l;
990
0
      if(!curlx_str_number(&p, &l, CURL_OFF_T_MAX))
991
0
        ctx->recv_max = (size_t)l;
992
0
    }
993
102k
  }
994
102k
#endif
995
996
102k
  return result;
997
102k
}
998
999
static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1000
201k
{
1001
201k
  struct cf_socket_ctx *ctx = cf->ctx;
1002
1003
201k
  if(ctx && CURL_SOCKET_BAD != ctx->sock) {
1004
99.8k
    CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
1005
99.8k
    if(ctx->sock == cf->conn->sock[cf->sockindex])
1006
54.4k
      cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
1007
99.8k
    socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
1008
99.8k
    ctx->sock = CURL_SOCKET_BAD;
1009
99.8k
    ctx->active = FALSE;
1010
99.8k
    memset(&ctx->started_at, 0, sizeof(ctx->started_at));
1011
99.8k
    memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
1012
99.8k
  }
1013
1014
201k
  cf->connected = FALSE;
1015
201k
}
1016
1017
static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
1018
                                   struct Curl_easy *data,
1019
                                   bool *done)
1020
21.1k
{
1021
21.1k
  if(cf->connected) {
1022
21.1k
    struct cf_socket_ctx *ctx = cf->ctx;
1023
1024
21.1k
    CURL_TRC_CF(data, cf, "cf_socket_shutdown, fd=%" FMT_SOCKET_T, ctx->sock);
1025
    /* On TCP, and when the socket looks well and non-blocking mode
1026
     * can be enabled, receive dangling bytes before close to avoid
1027
     * entering RST states unnecessarily. */
1028
21.1k
    if(ctx->sock != CURL_SOCKET_BAD &&
1029
21.1k
       ctx->transport == TRNSPRT_TCP &&
1030
20.6k
       (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
1031
20.2k
      unsigned char buf[1024];
1032
20.2k
      (void)sread(ctx->sock, buf, sizeof(buf));
1033
20.2k
    }
1034
21.1k
  }
1035
21.1k
  *done = TRUE;
1036
21.1k
  return CURLE_OK;
1037
21.1k
}
1038
1039
static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1040
102k
{
1041
102k
  struct cf_socket_ctx *ctx = cf->ctx;
1042
1043
102k
  cf_socket_close(cf, data);
1044
102k
  CURL_TRC_CF(data, cf, "destroy");
1045
102k
  free(ctx);
1046
102k
  cf->ctx = NULL;
1047
102k
}
1048
1049
static void set_local_ip(struct Curl_cfilter *cf,
1050
                         struct Curl_easy *data)
1051
156k
{
1052
156k
  struct cf_socket_ctx *ctx = cf->ctx;
1053
156k
  ctx->ip.local_ip[0] = 0;
1054
156k
  ctx->ip.local_port = -1;
1055
1056
156k
#ifdef HAVE_GETSOCKNAME
1057
156k
  if((ctx->sock != CURL_SOCKET_BAD) &&
1058
156k
     !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
1059
    /* TFTP does not connect, so it cannot get the IP like this */
1060
1061
151k
    char buffer[STRERROR_LEN];
1062
151k
    struct Curl_sockaddr_storage ssloc;
1063
151k
    curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
1064
1065
151k
    memset(&ssloc, 0, sizeof(ssloc));
1066
151k
    if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
1067
0
      int error = SOCKERRNO;
1068
0
      infof(data, "getsockname() failed with errno %d: %s",
1069
0
            error, curlx_strerror(error, buffer, sizeof(buffer)));
1070
0
    }
1071
151k
    else if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
1072
151k
                              ctx->ip.local_ip, &ctx->ip.local_port)) {
1073
0
      infof(data, "ssloc inet_ntop() failed with errno %d: %s",
1074
0
            errno, curlx_strerror(errno, buffer, sizeof(buffer)));
1075
0
    }
1076
151k
  }
1077
#else
1078
  (void)data;
1079
#endif
1080
156k
}
1081
1082
static CURLcode set_remote_ip(struct Curl_cfilter *cf,
1083
                              struct Curl_easy *data)
1084
101k
{
1085
101k
  struct cf_socket_ctx *ctx = cf->ctx;
1086
1087
  /* store remote address and port used in this connection attempt */
1088
101k
  if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
1089
101k
                       (curl_socklen_t)ctx->addr.addrlen,
1090
101k
                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
1091
0
    char buffer[STRERROR_LEN];
1092
1093
0
    ctx->error = errno;
1094
    /* malformed address or bug in inet_ntop, try next address */
1095
0
    failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
1096
0
          errno, curlx_strerror(errno, buffer, sizeof(buffer)));
1097
0
    return CURLE_FAILED_INIT;
1098
0
  }
1099
101k
  return CURLE_OK;
1100
101k
}
1101
1102
static CURLcode cf_socket_open(struct Curl_cfilter *cf,
1103
                               struct Curl_easy *data)
1104
102k
{
1105
102k
  struct cf_socket_ctx *ctx = cf->ctx;
1106
102k
  int error = 0;
1107
102k
  bool isconnected = FALSE;
1108
102k
  CURLcode result = CURLE_COULDNT_CONNECT;
1109
102k
  bool is_tcp;
1110
1111
102k
  (void)data;
1112
102k
  DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
1113
102k
  ctx->started_at = curlx_now();
1114
102k
#ifdef SOCK_NONBLOCK
1115
  /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
1116
   * because we would not know how socketype is about to be used in the
1117
   * callback, SOCK_NONBLOCK might get factored out before calling socket().
1118
   */
1119
102k
  if(!data->set.fopensocket)
1120
992
    ctx->addr.socktype |= SOCK_NONBLOCK;
1121
102k
#endif
1122
102k
  result = socket_open(data, &ctx->addr, &ctx->sock);
1123
102k
#ifdef SOCK_NONBLOCK
1124
  /* Restore the socktype after the socket is created. */
1125
102k
  if(!data->set.fopensocket)
1126
992
    ctx->addr.socktype &= ~SOCK_NONBLOCK;
1127
102k
#endif
1128
102k
  if(result)
1129
410
    goto out;
1130
1131
101k
  result = set_remote_ip(cf, data);
1132
101k
  if(result)
1133
0
    goto out;
1134
1135
101k
#ifdef USE_IPV6
1136
101k
  if(ctx->addr.family == AF_INET6) {
1137
1.06k
    set_ipv6_v6only(ctx->sock, 0);
1138
1.06k
    infof(data, "  Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1139
1.06k
  }
1140
100k
  else
1141
100k
#endif
1142
100k
    infof(data, "  Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1143
1144
101k
#ifdef USE_IPV6
1145
101k
  is_tcp = (ctx->addr.family == AF_INET
1146
2.17k
            || ctx->addr.family == AF_INET6) &&
1147
100k
           ctx->addr.socktype == SOCK_STREAM;
1148
#else
1149
  is_tcp = (ctx->addr.family == AF_INET) &&
1150
           ctx->addr.socktype == SOCK_STREAM;
1151
#endif
1152
101k
  if(is_tcp && data->set.tcp_nodelay)
1153
97.1k
    tcpnodelay(data, ctx->sock);
1154
1155
101k
  nosigpipe(data, ctx->sock);
1156
1157
101k
  Curl_sndbuf_init(ctx->sock);
1158
1159
101k
  if(is_tcp && data->set.tcp_keepalive)
1160
410
    tcpkeepalive(data, ctx->sock);
1161
1162
101k
  if(data->set.fsockopt) {
1163
    /* activate callback for setting socket options */
1164
100k
    Curl_set_in_callback(data, TRUE);
1165
100k
    error = data->set.fsockopt(data->set.sockopt_client,
1166
100k
                               ctx->sock,
1167
100k
                               CURLSOCKTYPE_IPCXN);
1168
100k
    Curl_set_in_callback(data, FALSE);
1169
1170
100k
    if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1171
100k
      isconnected = TRUE;
1172
0
    else if(error) {
1173
0
      result = CURLE_ABORTED_BY_CALLBACK;
1174
0
      goto out;
1175
0
    }
1176
100k
  }
1177
1178
101k
#ifndef CURL_DISABLE_BINDLOCAL
1179
  /* possibly bind the local end to an IP, interface or port */
1180
101k
  if(ctx->addr.family == AF_INET
1181
2.17k
#ifdef USE_IPV6
1182
2.17k
     || ctx->addr.family == AF_INET6
1183
101k
#endif
1184
101k
    ) {
1185
100k
    result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1186
100k
                       Curl_ipv6_scope(&ctx->addr.curl_sa_addr));
1187
100k
    if(result) {
1188
1.48k
      if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1189
        /* The address family is not supported on this interface.
1190
           We can continue trying addresses */
1191
218
        result = CURLE_COULDNT_CONNECT;
1192
218
      }
1193
1.48k
      goto out;
1194
1.48k
    }
1195
100k
  }
1196
100k
#endif
1197
1198
#ifndef SOCK_NONBLOCK
1199
  /* Set socket non-blocking, must be a non-blocking socket for
1200
   * a non-blocking connect. */
1201
  error = curlx_nonblock(ctx->sock, TRUE);
1202
  if(error < 0) {
1203
    result = CURLE_UNSUPPORTED_PROTOCOL;
1204
    ctx->error = SOCKERRNO;
1205
    goto out;
1206
  }
1207
#else
1208
100k
  if(data->set.fopensocket) {
1209
    /* Set socket non-blocking, must be a non-blocking socket for
1210
     * a non-blocking connect. */
1211
99.2k
    error = curlx_nonblock(ctx->sock, TRUE);
1212
99.2k
    if(error < 0) {
1213
0
      result = CURLE_UNSUPPORTED_PROTOCOL;
1214
0
      ctx->error = SOCKERRNO;
1215
0
      goto out;
1216
0
    }
1217
99.2k
  }
1218
100k
#endif
1219
100k
  ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1220
102k
out:
1221
102k
  if(result) {
1222
1.89k
    if(ctx->sock != CURL_SOCKET_BAD) {
1223
1.48k
      socket_close(data, cf->conn, TRUE, ctx->sock);
1224
1.48k
      ctx->sock = CURL_SOCKET_BAD;
1225
1.48k
    }
1226
1.89k
  }
1227
100k
  else if(isconnected) {
1228
99.2k
    set_local_ip(cf, data);
1229
99.2k
    ctx->connected_at = curlx_now();
1230
99.2k
    cf->connected = TRUE;
1231
99.2k
  }
1232
102k
  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
1233
102k
              result, ctx->sock);
1234
102k
  return result;
1235
100k
}
1236
1237
static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1238
                      bool is_tcp_fastopen)
1239
992
{
1240
992
  struct cf_socket_ctx *ctx = cf->ctx;
1241
992
#ifdef TCP_FASTOPEN_CONNECT
1242
992
  int optval = 1;
1243
992
#endif
1244
992
  int rc = -1;
1245
1246
992
  (void)data;
1247
992
  if(is_tcp_fastopen) {
1248
#ifdef CONNECT_DATA_IDEMPOTENT /* Darwin */
1249
#  ifdef HAVE_BUILTIN_AVAILABLE
1250
    /* while connectx function is available since macOS 10.11 / iOS 9,
1251
       it did not have the interface declared correctly until
1252
       Xcode 9 / macOS SDK 10.13 */
1253
    if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1254
      sa_endpoints_t endpoints;
1255
      endpoints.sae_srcif = 0;
1256
      endpoints.sae_srcaddr = NULL;
1257
      endpoints.sae_srcaddrlen = 0;
1258
      endpoints.sae_dstaddr = &ctx->addr.curl_sa_addr;
1259
      endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1260
1261
      rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1262
                    CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1263
                    NULL, 0, NULL, NULL);
1264
    }
1265
    else {
1266
      rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1267
    }
1268
#  else
1269
    rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1270
#  endif /* HAVE_BUILTIN_AVAILABLE */
1271
#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1272
0
    if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1273
0
                  (void *)&optval, sizeof(optval)) < 0)
1274
0
      infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
1275
0
            ctx->sock);
1276
1277
0
    rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1278
#elif defined(MSG_FASTOPEN) /* old Linux */
1279
    if(Curl_conn_is_ssl(cf->conn, cf->sockindex))
1280
      rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1281
    else
1282
      rc = 0; /* Do nothing */
1283
#endif
1284
0
  }
1285
992
  else {
1286
992
    rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1287
992
                 (curl_socklen_t)ctx->addr.addrlen);
1288
992
  }
1289
992
  return rc;
1290
992
}
1291
1292
static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1293
                               struct Curl_easy *data,
1294
                               bool *done)
1295
1.27M
{
1296
1.27M
  struct cf_socket_ctx *ctx = cf->ctx;
1297
1.27M
  CURLcode result = CURLE_COULDNT_CONNECT;
1298
1.27M
  int rc = 0;
1299
1300
1.27M
  (void)data;
1301
1.27M
  if(cf->connected) {
1302
0
    *done = TRUE;
1303
0
    return CURLE_OK;
1304
0
  }
1305
1306
1.27M
  *done = FALSE; /* a negative world view is best */
1307
1.27M
  if(ctx->sock == CURL_SOCKET_BAD) {
1308
98.7k
    int error;
1309
1310
98.7k
    result = cf_socket_open(cf, data);
1311
98.7k
    if(result)
1312
1.75k
      goto out;
1313
1314
96.9k
    if(cf->connected) {
1315
95.9k
      *done = TRUE;
1316
95.9k
      return CURLE_OK;
1317
95.9k
    }
1318
1319
    /* Connect TCP socket */
1320
992
    rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1321
992
    error = SOCKERRNO;
1322
992
    set_local_ip(cf, data);
1323
992
    CURL_TRC_CF(data, cf, "local address %s port %d...",
1324
992
                ctx->ip.local_ip, ctx->ip.local_port);
1325
992
    if(-1 == rc) {
1326
992
      result = socket_connect_result(data, ctx->ip.remote_ip, error);
1327
992
      goto out;
1328
992
    }
1329
992
  }
1330
1331
#ifdef mpeix
1332
  /* Call this function once now, and ignore the results. We do this to
1333
     "clear" the error state on the socket so that we can later read it
1334
     reliably. This is reported necessary on the MPE/iX operating
1335
     system. */
1336
  (void)verifyconnect(ctx->sock, NULL);
1337
#endif
1338
  /* check socket for connect */
1339
1.17M
  rc = SOCKET_WRITABLE(ctx->sock, 0);
1340
1341
1.17M
  if(rc == 0) { /* no connection yet */
1342
1.17M
    CURL_TRC_CF(data, cf, "not connected yet on fd=%" FMT_SOCKET_T,
1343
1.17M
                ctx->sock);
1344
1.17M
    return CURLE_OK;
1345
1.17M
  }
1346
298
  else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1347
16
    if(verifyconnect(ctx->sock, &ctx->error)) {
1348
      /* we are connected with TCP, awesome! */
1349
16
      ctx->connected_at = curlx_now();
1350
16
      set_local_ip(cf, data);
1351
16
      *done = TRUE;
1352
16
      cf->connected = TRUE;
1353
16
      CURL_TRC_CF(data, cf, "connected on fd=%" FMT_SOCKET_T, ctx->sock);
1354
16
      return CURLE_OK;
1355
16
    }
1356
16
  }
1357
282
  else if(rc & CURL_CSELECT_ERR) {
1358
282
    (void)verifyconnect(ctx->sock, &ctx->error);
1359
282
    result = CURLE_COULDNT_CONNECT;
1360
282
  }
1361
1362
3.02k
out:
1363
3.02k
  if(result) {
1364
2.24k
    if(ctx->error) {
1365
282
      set_local_ip(cf, data);
1366
282
      data->state.os_errno = ctx->error;
1367
282
      SET_SOCKERRNO(ctx->error);
1368
282
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1369
282
      {
1370
282
        char buffer[STRERROR_LEN];
1371
282
        infof(data, "connect to %s port %u from %s port %d failed: %s",
1372
282
              ctx->ip.remote_ip, ctx->ip.remote_port,
1373
282
              ctx->ip.local_ip, ctx->ip.local_port,
1374
282
              curlx_strerror(ctx->error, buffer, sizeof(buffer)));
1375
282
      }
1376
282
#endif
1377
282
    }
1378
2.24k
    if(ctx->sock != CURL_SOCKET_BAD) {
1379
490
      socket_close(data, cf->conn, TRUE, ctx->sock);
1380
490
      ctx->sock = CURL_SOCKET_BAD;
1381
490
    }
1382
2.24k
    *done = FALSE;
1383
2.24k
  }
1384
3.02k
  return result;
1385
1.17M
}
1386
1387
static CURLcode cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1388
                                         struct Curl_easy *data,
1389
                                         struct easy_pollset *ps)
1390
34.9M
{
1391
34.9M
  struct cf_socket_ctx *ctx = cf->ctx;
1392
34.9M
  CURLcode result = CURLE_OK;
1393
1394
34.9M
  if(ctx->sock != CURL_SOCKET_BAD) {
1395
    /* A listening socket filter needs to be connected before the accept
1396
     * for some weird FTP interaction. This should be rewritten, so that
1397
     * FTP no longer does the socket checks and accept calls and delegates
1398
     * all that to the filter. */
1399
34.9M
    if(ctx->listening) {
1400
0
      result = Curl_pollset_set_in_only(data, ps, ctx->sock);
1401
0
      CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
1402
0
                  FMT_SOCKET_T, ctx->sock);
1403
0
    }
1404
34.9M
    else if(!cf->connected) {
1405
1.17M
      result = Curl_pollset_set_out_only(data, ps, ctx->sock);
1406
1.17M
      CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1407
1.17M
                  FMT_SOCKET_T, ctx->sock);
1408
1.17M
    }
1409
33.7M
    else if(!ctx->active) {
1410
1.81M
      result = Curl_pollset_add_in(data, ps, ctx->sock);
1411
1.81M
      CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1412
1.81M
                  FMT_SOCKET_T, ctx->sock);
1413
1.81M
    }
1414
34.9M
  }
1415
34.9M
  return result;
1416
34.9M
}
1417
1418
#ifdef USE_WINSOCK
1419
1420
/* Offered by mingw-w64 v13+. MS SDK 7.0A+. */
1421
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
1422
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
1423
#endif
1424
1425
static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
1426
{
1427
  ULONG ideal;
1428
  DWORD ideallen;
1429
  struct curltime n = curlx_now();
1430
1431
  if(curlx_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
1432
    if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
1433
                  &ideal, sizeof(ideal), &ideallen, 0, 0) &&
1434
       ideal != ctx->sndbuf_size &&
1435
       !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
1436
                   (const char *)&ideal, sizeof(ideal))) {
1437
      ctx->sndbuf_size = ideal;
1438
    }
1439
    ctx->last_sndbuf_query_at = n;
1440
  }
1441
}
1442
1443
#endif /* USE_WINSOCK */
1444
1445
static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1446
                               const void *buf, size_t len, bool eos,
1447
                               size_t *pnwritten)
1448
15.5M
{
1449
15.5M
  struct cf_socket_ctx *ctx = cf->ctx;
1450
15.5M
  curl_socket_t fdsave;
1451
15.5M
  ssize_t nwritten;
1452
15.5M
  size_t orig_len = len;
1453
15.5M
  CURLcode result = CURLE_OK;
1454
1455
15.5M
  (void)eos;
1456
15.5M
  *pnwritten = 0;
1457
15.5M
  fdsave = cf->conn->sock[cf->sockindex];
1458
15.5M
  cf->conn->sock[cf->sockindex] = ctx->sock;
1459
1460
15.5M
#ifdef DEBUGBUILD
1461
  /* simulate network blocking/partial writes */
1462
15.5M
  if(ctx->wblock_percent > 0) {
1463
0
    unsigned char c = 0;
1464
0
    Curl_rand_bytes(data, FALSE, &c, 1);
1465
0
    if(c >= ((100-ctx->wblock_percent)*256/100)) {
1466
0
      CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1467
0
      cf->conn->sock[cf->sockindex] = fdsave;
1468
0
      return CURLE_AGAIN;
1469
0
    }
1470
0
  }
1471
15.5M
  if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1472
0
    len = len * ctx->wpartial_percent / 100;
1473
0
    if(!len)
1474
0
      len = 1;
1475
0
    CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1476
0
                orig_len, len);
1477
0
  }
1478
15.5M
#endif
1479
1480
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1481
  if(cf->conn->bits.tcp_fastopen) {
1482
    nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1483
                      &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1484
    cf->conn->bits.tcp_fastopen = FALSE;
1485
  }
1486
  else
1487
#endif
1488
15.5M
    nwritten = swrite(ctx->sock, buf, len);
1489
1490
15.5M
  if(nwritten < 0) {
1491
15.3M
    int sockerr = SOCKERRNO;
1492
1493
15.3M
    if(
1494
#ifdef USE_WINSOCK
1495
      /* This is how Windows does it */
1496
      (SOCKEWOULDBLOCK == sockerr)
1497
#else
1498
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1499
         due to its inability to send off data without blocking. We therefore
1500
         treat both error codes the same here */
1501
15.3M
      (SOCKEWOULDBLOCK == sockerr) ||
1502
0
      (EAGAIN == sockerr) || (SOCKEINTR == sockerr) ||
1503
0
      (SOCKEINPROGRESS == sockerr)
1504
15.3M
#endif
1505
15.3M
      ) {
1506
      /* this is just a case of EWOULDBLOCK */
1507
15.3M
      result = CURLE_AGAIN;
1508
15.3M
    }
1509
0
    else {
1510
0
      char buffer[STRERROR_LEN];
1511
0
      failf(data, "Send failure: %s",
1512
0
            curlx_strerror(sockerr, buffer, sizeof(buffer)));
1513
0
      data->state.os_errno = sockerr;
1514
0
      result = CURLE_SEND_ERROR;
1515
0
    }
1516
15.3M
  }
1517
173k
  else
1518
173k
    *pnwritten = (size_t)nwritten;
1519
1520
#ifdef USE_WINSOCK
1521
  if(!result)
1522
    win_update_sndbuf_size(ctx);
1523
#endif
1524
1525
15.5M
  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, %zu",
1526
15.5M
              orig_len, result, *pnwritten);
1527
15.5M
  cf->conn->sock[cf->sockindex] = fdsave;
1528
15.5M
  return result;
1529
15.5M
}
1530
1531
static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1532
                               char *buf, size_t len, size_t *pnread)
1533
45.2M
{
1534
45.2M
  struct cf_socket_ctx *ctx = cf->ctx;
1535
45.2M
  CURLcode result = CURLE_OK;
1536
45.2M
  ssize_t nread;
1537
1538
45.2M
  *pnread = 0;
1539
45.2M
#ifdef DEBUGBUILD
1540
  /* simulate network blocking/partial reads */
1541
45.2M
  if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1542
0
    unsigned char c = 0;
1543
0
    Curl_rand(data, &c, 1);
1544
0
    if(c >= ((100-ctx->rblock_percent)*256/100)) {
1545
0
      CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1546
0
      return CURLE_AGAIN;
1547
0
    }
1548
0
  }
1549
45.2M
  if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1550
0
    size_t orig_len = len;
1551
0
    len = ctx->recv_max;
1552
0
    CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1553
0
                orig_len, len);
1554
0
  }
1555
45.2M
#endif
1556
1557
45.2M
  nread = sread(ctx->sock, buf, len);
1558
1559
45.2M
  if(nread < 0) {
1560
6.96M
    int sockerr = SOCKERRNO;
1561
1562
6.96M
    if(
1563
#ifdef USE_WINSOCK
1564
      /* This is how Windows does it */
1565
      (SOCKEWOULDBLOCK == sockerr)
1566
#else
1567
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1568
         due to its inability to send off data without blocking. We therefore
1569
         treat both error codes the same here */
1570
6.96M
      (SOCKEWOULDBLOCK == sockerr) ||
1571
0
      (EAGAIN == sockerr) || (SOCKEINTR == sockerr)
1572
6.96M
#endif
1573
6.96M
      ) {
1574
      /* this is just a case of EWOULDBLOCK */
1575
6.96M
      result = CURLE_AGAIN;
1576
6.96M
    }
1577
0
    else {
1578
0
      char buffer[STRERROR_LEN];
1579
0
      failf(data, "Recv failure: %s",
1580
0
            curlx_strerror(sockerr, buffer, sizeof(buffer)));
1581
0
      data->state.os_errno = sockerr;
1582
0
      result = CURLE_RECV_ERROR;
1583
0
    }
1584
6.96M
  }
1585
38.2M
  else
1586
38.2M
    *pnread = (size_t)nread;
1587
1588
45.2M
  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread);
1589
45.2M
  if(!result && !ctx->got_first_byte) {
1590
79.9k
    ctx->first_byte_at = curlx_now();
1591
79.9k
    ctx->got_first_byte = TRUE;
1592
79.9k
  }
1593
45.2M
  return result;
1594
45.2M
}
1595
1596
static void cf_socket_update_data(struct Curl_cfilter *cf,
1597
                                  struct Curl_easy *data)
1598
68.4k
{
1599
  /* Update the IP info held in the transfer, if we have that. */
1600
68.4k
  if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
1601
67.3k
    struct cf_socket_ctx *ctx = cf->ctx;
1602
67.3k
    data->info.primary = ctx->ip;
1603
    /* not sure if this is redundant... */
1604
67.3k
    data->info.conn_remote_port = cf->conn->remote_port;
1605
67.3k
  }
1606
68.4k
}
1607
1608
static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1609
55.5k
{
1610
55.5k
  struct cf_socket_ctx *ctx = cf->ctx;
1611
1612
  /* use this socket from now on */
1613
55.5k
  cf->conn->sock[cf->sockindex] = ctx->sock;
1614
55.5k
  set_local_ip(cf, data);
1615
55.5k
#ifdef USE_IPV6
1616
55.5k
  if(cf->sockindex == FIRSTSOCKET)
1617
54.4k
    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
1618
55.5k
#endif
1619
55.5k
  ctx->active = TRUE;
1620
55.5k
}
1621
1622
static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1623
                                struct Curl_easy *data,
1624
                                int event, int arg1, void *arg2)
1625
6.14M
{
1626
6.14M
  struct cf_socket_ctx *ctx = cf->ctx;
1627
1628
6.14M
  (void)arg1;
1629
6.14M
  (void)arg2;
1630
6.14M
  switch(event) {
1631
55.5k
  case CF_CTRL_CONN_INFO_UPDATE:
1632
55.5k
    cf_socket_active(cf, data);
1633
55.5k
    cf_socket_update_data(cf, data);
1634
55.5k
    break;
1635
12.8k
  case CF_CTRL_DATA_SETUP:
1636
12.8k
    cf_socket_update_data(cf, data);
1637
12.8k
    break;
1638
0
  case CF_CTRL_FORGET_SOCKET:
1639
0
    ctx->sock = CURL_SOCKET_BAD;
1640
0
    break;
1641
6.14M
  }
1642
6.14M
  return CURLE_OK;
1643
6.14M
}
1644
1645
static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1646
                                    struct Curl_easy *data,
1647
                                    bool *input_pending)
1648
9.44k
{
1649
9.44k
  struct cf_socket_ctx *ctx = cf->ctx;
1650
9.44k
  struct pollfd pfd[1];
1651
9.44k
  int r;
1652
1653
9.44k
  *input_pending = FALSE;
1654
9.44k
  (void)data;
1655
9.44k
  if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1656
0
    return FALSE;
1657
1658
  /* Check with 0 timeout if there are any events pending on the socket */
1659
9.44k
  pfd[0].fd = ctx->sock;
1660
9.44k
  pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1661
9.44k
  pfd[0].revents = 0;
1662
1663
9.44k
  r = Curl_poll(pfd, 1, 0);
1664
9.44k
  if(r < 0) {
1665
0
    CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1666
0
    return FALSE;
1667
0
  }
1668
9.44k
  else if(r == 0) {
1669
136
    CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1670
136
    return TRUE;
1671
136
  }
1672
9.30k
  else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1673
0
    CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1674
0
    return FALSE;
1675
0
  }
1676
1677
9.30k
  CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1678
9.30k
  *input_pending = TRUE;
1679
9.30k
  return TRUE;
1680
9.44k
}
1681
1682
static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1683
                                struct Curl_easy *data,
1684
                                int query, int *pres1, void *pres2)
1685
12.8M
{
1686
12.8M
  struct cf_socket_ctx *ctx = cf->ctx;
1687
1688
12.8M
  switch(query) {
1689
9.24M
  case CF_QUERY_SOCKET:
1690
9.24M
    DEBUGASSERT(pres2);
1691
9.24M
    *((curl_socket_t *)pres2) = ctx->sock;
1692
9.24M
    return CURLE_OK;
1693
18.0k
  case CF_QUERY_TRANSPORT:
1694
18.0k
    DEBUGASSERT(pres1);
1695
18.0k
    *pres1 = ctx->transport;
1696
18.0k
    return CURLE_OK;
1697
11.9k
  case CF_QUERY_REMOTE_ADDR:
1698
11.9k
    DEBUGASSERT(pres2);
1699
11.9k
    *((const struct Curl_sockaddr_ex **)pres2) = cf->connected ?
1700
11.9k
                                                 &ctx->addr : NULL;
1701
11.9k
    return CURLE_OK;
1702
0
  case CF_QUERY_CONNECT_REPLY_MS:
1703
0
    if(ctx->got_first_byte) {
1704
0
      timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at);
1705
0
      *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
1706
0
    }
1707
0
    else
1708
0
      *pres1 = -1;
1709
0
    return CURLE_OK;
1710
101k
  case CF_QUERY_TIMER_CONNECT: {
1711
101k
    struct curltime *when = pres2;
1712
101k
    switch(ctx->transport) {
1713
3.44k
    case TRNSPRT_UDP:
1714
3.44k
    case TRNSPRT_QUIC:
1715
      /* Since UDP connected sockets work different from TCP, we use the
1716
       * time of the first byte from the peer as the "connect" time. */
1717
3.44k
      if(ctx->got_first_byte) {
1718
1.59k
        *when = ctx->first_byte_at;
1719
1.59k
        break;
1720
1.59k
      }
1721
1.84k
      FALLTHROUGH();
1722
99.8k
    default:
1723
99.8k
      *when = ctx->connected_at;
1724
99.8k
      break;
1725
101k
    }
1726
101k
    return CURLE_OK;
1727
101k
  }
1728
1.72k
  case CF_QUERY_IP_INFO:
1729
1.72k
#ifdef USE_IPV6
1730
1.72k
    *pres1 = (ctx->addr.family == AF_INET6);
1731
#else
1732
    *pres1 = FALSE;
1733
#endif
1734
1.72k
    *(struct ip_quadruple *)pres2 = ctx->ip;
1735
1.72k
    return CURLE_OK;
1736
3.45M
  default:
1737
3.45M
    break;
1738
12.8M
  }
1739
3.45M
  return cf->next ?
1740
0
    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1741
3.45M
    CURLE_UNKNOWN_OPTION;
1742
12.8M
}
1743
1744
struct Curl_cftype Curl_cft_tcp = {
1745
  "TCP",
1746
  CF_TYPE_IP_CONNECT,
1747
  CURL_LOG_LVL_NONE,
1748
  cf_socket_destroy,
1749
  cf_tcp_connect,
1750
  cf_socket_close,
1751
  cf_socket_shutdown,
1752
  cf_socket_adjust_pollset,
1753
  Curl_cf_def_data_pending,
1754
  cf_socket_send,
1755
  cf_socket_recv,
1756
  cf_socket_cntrl,
1757
  cf_socket_conn_is_alive,
1758
  Curl_cf_def_conn_keep_alive,
1759
  cf_socket_query,
1760
};
1761
1762
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1763
                            struct Curl_easy *data,
1764
                            struct connectdata *conn,
1765
                            const struct Curl_addrinfo *ai,
1766
                            int transport)
1767
97.5k
{
1768
97.5k
  struct cf_socket_ctx *ctx = NULL;
1769
97.5k
  struct Curl_cfilter *cf = NULL;
1770
97.5k
  CURLcode result;
1771
1772
97.5k
  (void)data;
1773
97.5k
  (void)conn;
1774
97.5k
  DEBUGASSERT(transport == TRNSPRT_TCP);
1775
97.5k
  if(!ai) {
1776
0
    result = CURLE_BAD_FUNCTION_ARGUMENT;
1777
0
    goto out;
1778
0
  }
1779
1780
97.5k
  ctx = calloc(1, sizeof(*ctx));
1781
97.5k
  if(!ctx) {
1782
0
    result = CURLE_OUT_OF_MEMORY;
1783
0
    goto out;
1784
0
  }
1785
1786
97.5k
  result = cf_socket_ctx_init(ctx, ai, transport);
1787
97.5k
  if(result)
1788
0
    goto out;
1789
1790
97.5k
  result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1791
1792
97.5k
out:
1793
97.5k
  *pcf = (!result) ? cf : NULL;
1794
97.5k
  if(result) {
1795
0
    Curl_safefree(cf);
1796
0
    Curl_safefree(ctx);
1797
0
  }
1798
1799
97.5k
  return result;
1800
97.5k
}
1801
1802
static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1803
                                  struct Curl_easy *data)
1804
0
{
1805
0
  struct cf_socket_ctx *ctx = cf->ctx;
1806
0
  int rc;
1807
0
  int one = 1;
1808
1809
0
  (void)one;
1810
1811
  /* QUIC needs a connected socket, nonblocking */
1812
0
  DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1813
1814
  /* error: The 1st argument to 'connect' is -1 but should be >= 0
1815
     NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions) */
1816
0
  rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1817
0
               (curl_socklen_t)ctx->addr.addrlen);
1818
0
  if(-1 == rc) {
1819
0
    return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
1820
0
  }
1821
0
  ctx->sock_connected = TRUE;
1822
0
  set_local_ip(cf, data);
1823
0
  CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
1824
0
              " connected: [%s:%d] -> [%s:%d]",
1825
0
              (ctx->transport == TRNSPRT_QUIC) ? "QUIC" : "UDP",
1826
0
              ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
1827
0
              ctx->ip.remote_ip, ctx->ip.remote_port);
1828
1829
  /* Currently, cf->ctx->sock is always non-blocking because the only
1830
   * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
1831
   * non-blocking socket created by cf_socket_open() to it. Thus, we
1832
   * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
1833
   */
1834
0
#ifdef __linux__
1835
0
  switch(ctx->addr.family) {
1836
0
#ifdef IP_MTU_DISCOVER
1837
0
  case AF_INET: {
1838
0
    int val = IP_PMTUDISC_DO;
1839
0
    (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1840
0
                     sizeof(val));
1841
0
    break;
1842
0
  }
1843
0
#endif
1844
0
#ifdef IPV6_MTU_DISCOVER
1845
0
  case AF_INET6: {
1846
0
    int val = IPV6_PMTUDISC_DO;
1847
0
    (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1848
0
                     sizeof(val));
1849
0
    break;
1850
0
  }
1851
0
#endif
1852
0
  }
1853
1854
#if defined(UDP_GRO) &&                                                       \
1855
  (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) &&                        \
1856
  ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
1857
  (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
1858
                   (socklen_t)sizeof(one));
1859
#endif
1860
0
#endif
1861
1862
0
  return CURLE_OK;
1863
0
}
1864
1865
static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1866
                               struct Curl_easy *data,
1867
                               bool *done)
1868
3.48k
{
1869
3.48k
  struct cf_socket_ctx *ctx = cf->ctx;
1870
3.48k
  CURLcode result = CURLE_COULDNT_CONNECT;
1871
1872
3.48k
  if(cf->connected) {
1873
0
    *done = TRUE;
1874
0
    return CURLE_OK;
1875
0
  }
1876
1877
3.48k
  *done = FALSE;
1878
3.48k
  if(ctx->sock == CURL_SOCKET_BAD) {
1879
3.48k
    result = cf_socket_open(cf, data);
1880
3.48k
    if(result) {
1881
149
      CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1882
149
      goto out;
1883
149
    }
1884
1885
3.34k
    if(ctx->transport == TRNSPRT_QUIC) {
1886
0
      result = cf_udp_setup_quic(cf, data);
1887
0
      if(result)
1888
0
        goto out;
1889
0
      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1890
0
                  FMT_SOCKET_T " (%s:%d)",
1891
0
                  ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
1892
0
    }
1893
3.34k
    *done = TRUE;
1894
3.34k
    cf->connected = TRUE;
1895
3.34k
  }
1896
3.48k
out:
1897
3.48k
  return result;
1898
3.48k
}
1899
1900
struct Curl_cftype Curl_cft_udp = {
1901
  "UDP",
1902
  CF_TYPE_IP_CONNECT,
1903
  CURL_LOG_LVL_NONE,
1904
  cf_socket_destroy,
1905
  cf_udp_connect,
1906
  cf_socket_close,
1907
  cf_socket_shutdown,
1908
  cf_socket_adjust_pollset,
1909
  Curl_cf_def_data_pending,
1910
  cf_socket_send,
1911
  cf_socket_recv,
1912
  cf_socket_cntrl,
1913
  cf_socket_conn_is_alive,
1914
  Curl_cf_def_conn_keep_alive,
1915
  cf_socket_query,
1916
};
1917
1918
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1919
                            struct Curl_easy *data,
1920
                            struct connectdata *conn,
1921
                            const struct Curl_addrinfo *ai,
1922
                            int transport)
1923
3.48k
{
1924
3.48k
  struct cf_socket_ctx *ctx = NULL;
1925
3.48k
  struct Curl_cfilter *cf = NULL;
1926
3.48k
  CURLcode result;
1927
1928
3.48k
  (void)data;
1929
3.48k
  (void)conn;
1930
3.48k
  DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1931
3.48k
  ctx = calloc(1, sizeof(*ctx));
1932
3.48k
  if(!ctx) {
1933
0
    result = CURLE_OUT_OF_MEMORY;
1934
0
    goto out;
1935
0
  }
1936
1937
3.48k
  result = cf_socket_ctx_init(ctx, ai, transport);
1938
3.48k
  if(result)
1939
0
    goto out;
1940
1941
3.48k
  result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1942
1943
3.48k
out:
1944
3.48k
  *pcf = (!result) ? cf : NULL;
1945
3.48k
  if(result) {
1946
0
    Curl_safefree(cf);
1947
0
    Curl_safefree(ctx);
1948
0
  }
1949
1950
3.48k
  return result;
1951
3.48k
}
1952
1953
/* this is the TCP filter which can also handle this case */
1954
struct Curl_cftype Curl_cft_unix = {
1955
  "UNIX",
1956
  CF_TYPE_IP_CONNECT,
1957
  CURL_LOG_LVL_NONE,
1958
  cf_socket_destroy,
1959
  cf_tcp_connect,
1960
  cf_socket_close,
1961
  cf_socket_shutdown,
1962
  cf_socket_adjust_pollset,
1963
  Curl_cf_def_data_pending,
1964
  cf_socket_send,
1965
  cf_socket_recv,
1966
  cf_socket_cntrl,
1967
  cf_socket_conn_is_alive,
1968
  Curl_cf_def_conn_keep_alive,
1969
  cf_socket_query,
1970
};
1971
1972
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1973
                             struct Curl_easy *data,
1974
                             struct connectdata *conn,
1975
                             const struct Curl_addrinfo *ai,
1976
                             int transport)
1977
1.13k
{
1978
1.13k
  struct cf_socket_ctx *ctx = NULL;
1979
1.13k
  struct Curl_cfilter *cf = NULL;
1980
1.13k
  CURLcode result;
1981
1982
1.13k
  (void)data;
1983
1.13k
  (void)conn;
1984
1.13k
  DEBUGASSERT(transport == TRNSPRT_UNIX);
1985
1.13k
  ctx = calloc(1, sizeof(*ctx));
1986
1.13k
  if(!ctx) {
1987
0
    result = CURLE_OUT_OF_MEMORY;
1988
0
    goto out;
1989
0
  }
1990
1991
1.13k
  result = cf_socket_ctx_init(ctx, ai, transport);
1992
1.13k
  if(result)
1993
0
    goto out;
1994
1995
1.13k
  result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
1996
1997
1.13k
out:
1998
1.13k
  *pcf = (!result) ? cf : NULL;
1999
1.13k
  if(result) {
2000
0
    Curl_safefree(cf);
2001
0
    Curl_safefree(ctx);
2002
0
  }
2003
2004
1.13k
  return result;
2005
1.13k
}
2006
2007
static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
2008
                                         struct Curl_easy *data)
2009
0
{
2010
0
  struct cf_socket_ctx *ctx = cf->ctx;
2011
0
  timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
2012
0
  timediff_t other;
2013
0
  struct curltime now;
2014
2015
0
#ifndef CURL_DISABLE_FTP
2016
0
  if(data->set.accepttimeout > 0)
2017
0
    timeout_ms = data->set.accepttimeout;
2018
0
#endif
2019
2020
0
  now = curlx_now();
2021
  /* check if the generic timeout possibly is set shorter */
2022
0
  other = Curl_timeleft(data, &now, FALSE);
2023
0
  if(other && (other < timeout_ms))
2024
    /* note that this also works fine for when other happens to be negative
2025
       due to it already having elapsed */
2026
0
    timeout_ms = other;
2027
0
  else {
2028
    /* subtract elapsed time */
2029
0
    timeout_ms -= curlx_timediff(now, ctx->started_at);
2030
0
    if(!timeout_ms)
2031
      /* avoid returning 0 as that means no timeout! */
2032
0
      timeout_ms = -1;
2033
0
  }
2034
0
  return timeout_ms;
2035
0
}
2036
2037
static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
2038
                                          struct Curl_easy *data)
2039
0
{
2040
0
  struct cf_socket_ctx *ctx = cf->ctx;
2041
0
#ifdef HAVE_GETPEERNAME
2042
0
  char buffer[STRERROR_LEN];
2043
0
  struct Curl_sockaddr_storage ssrem;
2044
0
  curl_socklen_t plen;
2045
2046
0
  ctx->ip.remote_ip[0] = 0;
2047
0
  ctx->ip.remote_port = 0;
2048
0
  plen = sizeof(ssrem);
2049
0
  memset(&ssrem, 0, plen);
2050
0
  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
2051
0
    int error = SOCKERRNO;
2052
0
    failf(data, "getpeername() failed with errno %d: %s",
2053
0
          error, curlx_strerror(error, buffer, sizeof(buffer)));
2054
0
    return;
2055
0
  }
2056
0
  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
2057
0
                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
2058
0
    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
2059
0
          errno, curlx_strerror(errno, buffer, sizeof(buffer)));
2060
0
    return;
2061
0
  }
2062
#else
2063
  ctx->ip.remote_ip[0] = 0;
2064
  ctx->ip.remote_port = 0;
2065
  (void)data;
2066
#endif
2067
0
}
2068
2069
static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
2070
                                      struct Curl_easy *data,
2071
                                      bool *done)
2072
0
{
2073
0
  struct cf_socket_ctx *ctx = cf->ctx;
2074
0
  char errbuf[STRERROR_LEN];
2075
0
#ifdef USE_IPV6
2076
0
  struct Curl_sockaddr_storage add;
2077
#else
2078
  struct sockaddr_in add;
2079
#endif
2080
0
  curl_socklen_t size = (curl_socklen_t) sizeof(add);
2081
0
  curl_socket_t s_accepted = CURL_SOCKET_BAD;
2082
0
  timediff_t timeout_ms;
2083
0
  int socketstate = 0;
2084
0
  bool incoming = FALSE;
2085
2086
  /* we start accepted, if we ever close, we cannot go on */
2087
0
  (void)data;
2088
0
  if(cf->connected) {
2089
0
    *done = TRUE;
2090
0
    return CURLE_OK;
2091
0
  }
2092
2093
0
  *done = FALSE;
2094
0
  timeout_ms = cf_tcp_accept_timeleft(cf, data);
2095
0
  if(timeout_ms < 0) {
2096
    /* if a timeout was already reached, bail out */
2097
0
    failf(data, "Accept timeout occurred while waiting server connect");
2098
0
    return CURLE_FTP_ACCEPT_TIMEOUT;
2099
0
  }
2100
2101
0
  CURL_TRC_CF(data, cf, "Checking for incoming on fd=%" FMT_SOCKET_T
2102
0
              " ip=%s:%d", ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
2103
0
  socketstate = Curl_socket_check(ctx->sock, CURL_SOCKET_BAD,
2104
0
                                  CURL_SOCKET_BAD, 0);
2105
0
  CURL_TRC_CF(data, cf, "socket_check -> %x", socketstate);
2106
0
  switch(socketstate) {
2107
0
  case -1: /* error */
2108
    /* let's die here */
2109
0
    failf(data, "Error while waiting for server connect");
2110
0
    return CURLE_FTP_ACCEPT_FAILED;
2111
0
  default:
2112
0
    if(socketstate & CURL_CSELECT_IN) {
2113
0
      infof(data, "Ready to accept data connection from server");
2114
0
      incoming = TRUE;
2115
0
    }
2116
0
    break;
2117
0
  }
2118
2119
0
  if(!incoming) {
2120
0
    CURL_TRC_CF(data, cf, "nothing heard from the server yet");
2121
0
    return CURLE_OK;
2122
0
  }
2123
2124
0
  size = sizeof(add);
2125
0
#ifdef HAVE_ACCEPT4
2126
0
  s_accepted = CURL_ACCEPT4(ctx->sock, (struct sockaddr *) &add, &size,
2127
0
                            SOCK_NONBLOCK | SOCK_CLOEXEC);
2128
#else
2129
  s_accepted = CURL_ACCEPT(ctx->sock, (struct sockaddr *) &add, &size);
2130
#endif
2131
2132
0
  if(CURL_SOCKET_BAD == s_accepted) {
2133
0
    failf(data, "Error accept()ing server connect: %s",
2134
0
          curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf)));
2135
0
    return CURLE_FTP_ACCEPT_FAILED;
2136
0
  }
2137
#if !defined(HAVE_ACCEPT4) && defined(HAVE_FCNTL)
2138
  if((fcntl(s_accepted, F_SETFD, FD_CLOEXEC) < 0) ||
2139
     (curlx_nonblock(s_accepted, TRUE) < 0)) {
2140
    failf(data, "fcntl set CLOEXEC/NONBLOCK: %s",
2141
          curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf)));
2142
    Curl_socket_close(data, cf->conn, s_accepted);
2143
    return CURLE_FTP_ACCEPT_FAILED;
2144
  }
2145
#endif
2146
0
  infof(data, "Connection accepted from server");
2147
2148
  /* Replace any filter on SECONDARY with one listening on this socket */
2149
0
  ctx->listening = FALSE;
2150
0
  ctx->accepted = TRUE;
2151
0
  socket_close(data, cf->conn, TRUE, ctx->sock);
2152
0
  ctx->sock = s_accepted;
2153
2154
0
  cf->conn->sock[cf->sockindex] = ctx->sock;
2155
0
  cf_tcp_set_accepted_remote_ip(cf, data);
2156
0
  set_local_ip(cf, data);
2157
0
  ctx->active = TRUE;
2158
0
  ctx->connected_at = curlx_now();
2159
0
  cf->connected = TRUE;
2160
0
  CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
2161
0
              ", remote=%s port=%d)",
2162
0
              ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
2163
2164
0
  if(data->set.fsockopt) {
2165
0
    int error = 0;
2166
2167
    /* activate callback for setting socket options */
2168
0
    Curl_set_in_callback(data, true);
2169
0
    error = data->set.fsockopt(data->set.sockopt_client,
2170
0
                               ctx->sock, CURLSOCKTYPE_ACCEPT);
2171
0
    Curl_set_in_callback(data, false);
2172
2173
0
    if(error)
2174
0
      return CURLE_ABORTED_BY_CALLBACK;
2175
0
  }
2176
0
  *done = TRUE;
2177
0
  return CURLE_OK;
2178
0
}
2179
2180
struct Curl_cftype Curl_cft_tcp_accept = {
2181
  "TCP-ACCEPT",
2182
  CF_TYPE_IP_CONNECT,
2183
  CURL_LOG_LVL_NONE,
2184
  cf_socket_destroy,
2185
  cf_tcp_accept_connect,
2186
  cf_socket_close,
2187
  cf_socket_shutdown,
2188
  cf_socket_adjust_pollset,
2189
  Curl_cf_def_data_pending,
2190
  cf_socket_send,
2191
  cf_socket_recv,
2192
  cf_socket_cntrl,
2193
  cf_socket_conn_is_alive,
2194
  Curl_cf_def_conn_keep_alive,
2195
  cf_socket_query,
2196
};
2197
2198
CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
2199
                                  struct connectdata *conn,
2200
                                  int sockindex, curl_socket_t *s)
2201
0
{
2202
0
  CURLcode result;
2203
0
  struct Curl_cfilter *cf = NULL;
2204
0
  struct cf_socket_ctx *ctx = NULL;
2205
2206
  /* replace any existing */
2207
0
  Curl_conn_cf_discard_all(data, conn, sockindex);
2208
0
  DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
2209
2210
0
  ctx = calloc(1, sizeof(*ctx));
2211
0
  if(!ctx) {
2212
0
    result = CURLE_OUT_OF_MEMORY;
2213
0
    goto out;
2214
0
  }
2215
0
  ctx->transport = TRNSPRT_TCP;
2216
0
  ctx->sock = *s;
2217
0
  ctx->listening = TRUE;
2218
0
  ctx->accepted = FALSE;
2219
0
  result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
2220
0
  if(result)
2221
0
    goto out;
2222
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
2223
2224
0
  ctx->started_at = curlx_now();
2225
0
  conn->sock[sockindex] = ctx->sock;
2226
0
  set_local_ip(cf, data);
2227
0
  CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T
2228
0
              " ip=%s:%d", ctx->sock,
2229
0
              ctx->ip.local_ip, ctx->ip.local_port);
2230
2231
0
out:
2232
0
  if(result) {
2233
0
    Curl_safefree(cf);
2234
0
    Curl_safefree(ctx);
2235
0
  }
2236
0
  return result;
2237
0
}
2238
2239
bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
2240
                             int sockindex)
2241
3.37k
{
2242
3.37k
  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
2243
11.2k
  while(cf) {
2244
7.84k
    if(cf->cft == &Curl_cft_tcp_accept)
2245
0
      return TRUE;
2246
7.84k
    cf = cf->next;
2247
7.84k
  }
2248
3.37k
  return FALSE;
2249
3.37k
}
2250
2251
/**
2252
 * Return TRUE iff `cf` is a socket filter.
2253
 */
2254
static bool cf_is_socket(struct Curl_cfilter *cf)
2255
0
{
2256
0
  return cf && (cf->cft == &Curl_cft_tcp ||
2257
0
                cf->cft == &Curl_cft_udp ||
2258
0
                cf->cft == &Curl_cft_unix ||
2259
0
                cf->cft == &Curl_cft_tcp_accept);
2260
0
}
2261
2262
CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
2263
                             struct Curl_easy *data,
2264
                             curl_socket_t *psock,
2265
                             const struct Curl_sockaddr_ex **paddr,
2266
                             struct ip_quadruple *pip)
2267
0
{
2268
0
  (void)data;
2269
0
  if(cf_is_socket(cf) && cf->ctx) {
2270
0
    struct cf_socket_ctx *ctx = cf->ctx;
2271
2272
0
    if(psock)
2273
0
      *psock = ctx->sock;
2274
0
    if(paddr)
2275
0
      *paddr = &ctx->addr;
2276
0
    if(pip)
2277
0
      *pip = ctx->ip;
2278
0
    return CURLE_OK;
2279
0
  }
2280
0
  return CURLE_FAILED_INIT;
2281
0
}