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