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