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