1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 #include "curl_setup.h"
26
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
29 #endif
30 #ifdef HAVE_SYS_UN_H
31 #include <sys/un.h> /* for sockaddr_un */
32 #endif
33 #ifdef HAVE_LINUX_TCP_H
34 #include <linux/tcp.h>
35 #elif defined(HAVE_NETINET_TCP_H)
36 #include <netinet/tcp.h>
37 #endif
38 #ifdef HAVE_SYS_IOCTL_H
39 #include <sys/ioctl.h>
40 #endif
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif
44 #ifdef HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
50
51 #ifdef __VMS
52 #include <in.h>
53 #include <inet.h>
54 #endif
55
56 #include "urldata.h"
57 #include "bufq.h"
58 #include "sendf.h"
59 #include "if2ip.h"
60 #include "strerror.h"
61 #include "cfilters.h"
62 #include "cf-socket.h"
63 #include "connect.h"
64 #include "select.h"
65 #include "url.h" /* for Curl_safefree() */
66 #include "multiif.h"
67 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
70 #include "progress.h"
71 #include "warnless.h"
72 #include "conncache.h"
73 #include "multihandle.h"
74 #include "rand.h"
75 #include "share.h"
76 #include "version_win32.h"
77
78 /* The last 3 #include files should be in this order */
79 #include "curl_printf.h"
80 #include "curl_memory.h"
81 #include "memdebug.h"
82
83
84 #if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
85 /* It makes support for IPv4-mapped IPv6 addresses.
86 * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
87 * Windows Vista and later: default is on;
88 * DragonFly BSD: acts like off, and dummy setting;
89 * OpenBSD and earlier Windows: unsupported.
90 * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
91 */
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(ENABLE_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 ENABLE_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 ENABLE_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 ENABLE_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 ENABLE_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 ENABLE_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 ENABLE_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 struct Curl_sockaddr_storage add;
620 curl_socklen_t size = sizeof(add);
621 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
622 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
623 char buffer[STRERROR_LEN];
624 data->state.os_errno = error = SOCKERRNO;
625 failf(data, "getsockname() failed with errno %d: %s",
626 error, Curl_strerror(error, buffer, sizeof(buffer)));
627 return CURLE_INTERFACE_FAILED;
628 }
629 infof(data, "Local port: %hu", port);
630 conn->bits.bound = TRUE;
631 return CURLE_OK;
632 }
633
634 if(--portnum > 0) {
635 port++; /* try next port */
636 if(port == 0)
637 break;
638 infof(data, "Bind to local port %d failed, trying next", port - 1);
639 /* We reuse/clobber the port variable here below */
640 if(sock->sa_family == AF_INET)
641 si4->sin_port = ntohs(port);
642 #ifdef ENABLE_IPV6
643 else
644 si6->sin6_port = ntohs(port);
645 #endif
646 }
647 else
648 break;
649 }
650 {
651 char buffer[STRERROR_LEN];
652 data->state.os_errno = error = SOCKERRNO;
653 failf(data, "bind failed with errno %d: %s",
654 error, Curl_strerror(error, buffer, sizeof(buffer)));
655 }
656
657 return CURLE_INTERFACE_FAILED;
658 }
659 #endif
660
661 /*
662 * verifyconnect() returns TRUE if the connect really has happened.
663 */
verifyconnect(curl_socket_t sockfd,int * error)664 static bool verifyconnect(curl_socket_t sockfd, int *error)
665 {
666 bool rc = TRUE;
667 #ifdef SO_ERROR
668 int err = 0;
669 curl_socklen_t errSize = sizeof(err);
670
671 #ifdef _WIN32
672 /*
673 * In October 2003 we effectively nullified this function on Windows due to
674 * problems with it using all CPU in multi-threaded cases.
675 *
676 * In May 2004, we bring it back to offer more info back on connect failures.
677 * Gisle Vanem could reproduce the former problems with this function, but
678 * could avoid them by adding this SleepEx() call below:
679 *
680 * "I don't have Rational Quantify, but the hint from his post was
681 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
682 * just Sleep(0) would be enough?) would release whatever
683 * mutex/critical-section the ntdll call is waiting on.
684 *
685 * Someone got to verify this on Win-NT 4.0, 2000."
686 */
687
688 #ifdef _WIN32_WCE
689 Sleep(0);
690 #else
691 SleepEx(0, FALSE);
692 #endif
693
694 #endif
695
696 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
697 err = SOCKERRNO;
698 #ifdef _WIN32_WCE
699 /* Old WinCE versions don't support SO_ERROR */
700 if(WSAENOPROTOOPT == err) {
701 SET_SOCKERRNO(0);
702 err = 0;
703 }
704 #endif
705 #if defined(EBADIOCTL) && defined(__minix)
706 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
707 if(EBADIOCTL == err) {
708 SET_SOCKERRNO(0);
709 err = 0;
710 }
711 #endif
712 if((0 == err) || (EISCONN == err))
713 /* we are connected, awesome! */
714 rc = TRUE;
715 else
716 /* This wasn't a successful connect */
717 rc = FALSE;
718 if(error)
719 *error = err;
720 #else
721 (void)sockfd;
722 if(error)
723 *error = SOCKERRNO;
724 #endif
725 return rc;
726 }
727
728 /**
729 * Determine the curl code for a socket connect() == -1 with errno.
730 */
socket_connect_result(struct Curl_easy * data,const char * ipaddress,int error)731 static CURLcode socket_connect_result(struct Curl_easy *data,
732 const char *ipaddress, int error)
733 {
734 switch(error) {
735 case EINPROGRESS:
736 case EWOULDBLOCK:
737 #if defined(EAGAIN)
738 #if (EAGAIN) != (EWOULDBLOCK)
739 /* On some platforms EAGAIN and EWOULDBLOCK are the
740 * same value, and on others they are different, hence
741 * the odd #if
742 */
743 case EAGAIN:
744 #endif
745 #endif
746 return CURLE_OK;
747
748 default:
749 /* unknown error, fallthrough and try another address! */
750 #ifdef CURL_DISABLE_VERBOSE_STRINGS
751 (void)ipaddress;
752 #else
753 {
754 char buffer[STRERROR_LEN];
755 infof(data, "Immediate connect fail for %s: %s",
756 ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
757 }
758 #endif
759 data->state.os_errno = error;
760 /* connect failed */
761 return CURLE_COULDNT_CONNECT;
762 }
763 }
764
765 /* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
766 * This happens often on TLS connections where the TLS implementation
767 * tries to read the head of a TLS record, determine the length of the
768 * full record and then make a subsequent read for that.
769 * On large reads, we will not fill the buffer to avoid the double copy. */
770 #define NW_RECV_CHUNK_SIZE (64 * 1024)
771 #define NW_RECV_CHUNKS 1
772 #define NW_SMALL_READS (1024)
773
774 struct cf_socket_ctx {
775 int transport;
776 struct Curl_sockaddr_ex addr; /* address to connect to */
777 curl_socket_t sock; /* current attempt socket */
778 struct bufq recvbuf; /* used when `buffer_recv` is set */
779 char r_ip[MAX_IPADR_LEN]; /* remote IP as string */
780 int r_port; /* remote port number */
781 char l_ip[MAX_IPADR_LEN]; /* local IP as string */
782 int l_port; /* local port number */
783 struct curltime started_at; /* when socket was created */
784 struct curltime connected_at; /* when socket connected/got first byte */
785 struct curltime first_byte_at; /* when first byte was recvd */
786 int error; /* errno of last failure or 0 */
787 #ifdef DEBUGBUILD
788 int wblock_percent; /* percent of writes doing EAGAIN */
789 int wpartial_percent; /* percent of bytes written in send */
790 int rblock_percent; /* percent of reads doing EAGAIN */
791 size_t recv_max; /* max enforced read size */
792 #endif
793 BIT(got_first_byte); /* if first byte was received */
794 BIT(accepted); /* socket was accepted, not connected */
795 BIT(sock_connected); /* socket is "connected", e.g. in UDP */
796 BIT(active);
797 BIT(buffer_recv);
798 };
799
cf_socket_ctx_init(struct cf_socket_ctx * ctx,const struct Curl_addrinfo * ai,int transport)800 static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
801 const struct Curl_addrinfo *ai,
802 int transport)
803 {
804 memset(ctx, 0, sizeof(*ctx));
805 ctx->sock = CURL_SOCKET_BAD;
806 ctx->transport = transport;
807 Curl_sock_assign_addr(&ctx->addr, ai, transport);
808 Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
809 #ifdef DEBUGBUILD
810 {
811 char *p = getenv("CURL_DBG_SOCK_WBLOCK");
812 if(p) {
813 long l = strtol(p, NULL, 10);
814 if(l >= 0 && l <= 100)
815 ctx->wblock_percent = (int)l;
816 }
817 p = getenv("CURL_DBG_SOCK_WPARTIAL");
818 if(p) {
819 long l = strtol(p, NULL, 10);
820 if(l >= 0 && l <= 100)
821 ctx->wpartial_percent = (int)l;
822 }
823 p = getenv("CURL_DBG_SOCK_RBLOCK");
824 if(p) {
825 long l = strtol(p, NULL, 10);
826 if(l >= 0 && l <= 100)
827 ctx->rblock_percent = (int)l;
828 }
829 p = getenv("CURL_DBG_SOCK_RMAX");
830 if(p) {
831 long l = strtol(p, NULL, 10);
832 if(l >= 0)
833 ctx->recv_max = (size_t)l;
834 }
835 }
836 #endif
837 }
838
839 struct reader_ctx {
840 struct Curl_cfilter *cf;
841 struct Curl_easy *data;
842 };
843
nw_in_read(void * reader_ctx,unsigned char * buf,size_t len,CURLcode * err)844 static ssize_t nw_in_read(void *reader_ctx,
845 unsigned char *buf, size_t len,
846 CURLcode *err)
847 {
848 struct reader_ctx *rctx = reader_ctx;
849 struct cf_socket_ctx *ctx = rctx->cf->ctx;
850 ssize_t nread;
851
852 *err = CURLE_OK;
853 nread = sread(ctx->sock, buf, len);
854
855 if(-1 == nread) {
856 int sockerr = SOCKERRNO;
857
858 if(
859 #ifdef WSAEWOULDBLOCK
860 /* This is how Windows does it */
861 (WSAEWOULDBLOCK == sockerr)
862 #else
863 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
864 due to its inability to send off data without blocking. We therefore
865 treat both error codes the same here */
866 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
867 #endif
868 ) {
869 /* this is just a case of EWOULDBLOCK */
870 *err = CURLE_AGAIN;
871 nread = -1;
872 }
873 else {
874 char buffer[STRERROR_LEN];
875
876 failf(rctx->data, "Recv failure: %s",
877 Curl_strerror(sockerr, buffer, sizeof(buffer)));
878 rctx->data->state.os_errno = sockerr;
879 *err = CURLE_RECV_ERROR;
880 nread = -1;
881 }
882 }
883 CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu) -> %d, err=%d",
884 len, (int)nread, *err);
885 return nread;
886 }
887
cf_socket_close(struct Curl_cfilter * cf,struct Curl_easy * data)888 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
889 {
890 struct cf_socket_ctx *ctx = cf->ctx;
891
892 if(ctx && CURL_SOCKET_BAD != ctx->sock) {
893 CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
894 ")", ctx->sock);
895 if(ctx->sock == cf->conn->sock[cf->sockindex])
896 cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
897 socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
898 ctx->sock = CURL_SOCKET_BAD;
899 if(ctx->active && cf->sockindex == FIRSTSOCKET)
900 cf->conn->remote_addr = NULL;
901 Curl_bufq_reset(&ctx->recvbuf);
902 ctx->active = FALSE;
903 ctx->buffer_recv = FALSE;
904 memset(&ctx->started_at, 0, sizeof(ctx->started_at));
905 memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
906 }
907
908 cf->connected = FALSE;
909 }
910
cf_socket_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)911 static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
912 {
913 struct cf_socket_ctx *ctx = cf->ctx;
914
915 cf_socket_close(cf, data);
916 CURL_TRC_CF(data, cf, "destroy");
917 Curl_bufq_free(&ctx->recvbuf);
918 free(ctx);
919 cf->ctx = NULL;
920 }
921
set_local_ip(struct Curl_cfilter * cf,struct Curl_easy * data)922 static CURLcode set_local_ip(struct Curl_cfilter *cf,
923 struct Curl_easy *data)
924 {
925 struct cf_socket_ctx *ctx = cf->ctx;
926
927 #ifdef HAVE_GETSOCKNAME
928 if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
929 /* TFTP does not connect, so it cannot get the IP like this */
930
931 char buffer[STRERROR_LEN];
932 struct Curl_sockaddr_storage ssloc;
933 curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
934
935 memset(&ssloc, 0, sizeof(ssloc));
936 if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
937 int error = SOCKERRNO;
938 failf(data, "getsockname() failed with errno %d: %s",
939 error, Curl_strerror(error, buffer, sizeof(buffer)));
940 return CURLE_FAILED_INIT;
941 }
942 if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
943 ctx->l_ip, &ctx->l_port)) {
944 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
945 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
946 return CURLE_FAILED_INIT;
947 }
948 }
949 #else
950 (void)data;
951 ctx->l_ip[0] = 0;
952 ctx->l_port = -1;
953 #endif
954 return CURLE_OK;
955 }
956
set_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)957 static CURLcode set_remote_ip(struct Curl_cfilter *cf,
958 struct Curl_easy *data)
959 {
960 struct cf_socket_ctx *ctx = cf->ctx;
961
962 /* store remote address and port used in this connection attempt */
963 if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
964 ctx->r_ip, &ctx->r_port)) {
965 char buffer[STRERROR_LEN];
966
967 ctx->error = errno;
968 /* malformed address or bug in inet_ntop, try next address */
969 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
970 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
971 return CURLE_FAILED_INIT;
972 }
973 return CURLE_OK;
974 }
975
cf_socket_open(struct Curl_cfilter * cf,struct Curl_easy * data)976 static CURLcode cf_socket_open(struct Curl_cfilter *cf,
977 struct Curl_easy *data)
978 {
979 struct cf_socket_ctx *ctx = cf->ctx;
980 int error = 0;
981 bool isconnected = FALSE;
982 CURLcode result = CURLE_COULDNT_CONNECT;
983 bool is_tcp;
984
985 (void)data;
986 DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
987 ctx->started_at = Curl_now();
988 result = socket_open(data, &ctx->addr, &ctx->sock);
989 if(result)
990 goto out;
991
992 result = set_remote_ip(cf, data);
993 if(result)
994 goto out;
995
996 #ifdef ENABLE_IPV6
997 if(ctx->addr.family == AF_INET6) {
998 set_ipv6_v6only(ctx->sock, 0);
999 infof(data, " Trying [%s]:%d...", ctx->r_ip, ctx->r_port);
1000 }
1001 else
1002 #endif
1003 infof(data, " Trying %s:%d...", ctx->r_ip, ctx->r_port);
1004
1005 #ifdef ENABLE_IPV6
1006 is_tcp = (ctx->addr.family == AF_INET
1007 || ctx->addr.family == AF_INET6) &&
1008 ctx->addr.socktype == SOCK_STREAM;
1009 #else
1010 is_tcp = (ctx->addr.family == AF_INET) &&
1011 ctx->addr.socktype == SOCK_STREAM;
1012 #endif
1013 if(is_tcp && data->set.tcp_nodelay)
1014 tcpnodelay(data, ctx->sock);
1015
1016 nosigpipe(data, ctx->sock);
1017
1018 Curl_sndbufset(ctx->sock);
1019
1020 if(is_tcp && data->set.tcp_keepalive)
1021 tcpkeepalive(data, ctx->sock);
1022
1023 if(data->set.fsockopt) {
1024 /* activate callback for setting socket options */
1025 Curl_set_in_callback(data, true);
1026 error = data->set.fsockopt(data->set.sockopt_client,
1027 ctx->sock,
1028 CURLSOCKTYPE_IPCXN);
1029 Curl_set_in_callback(data, false);
1030
1031 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1032 isconnected = TRUE;
1033 else if(error) {
1034 result = CURLE_ABORTED_BY_CALLBACK;
1035 goto out;
1036 }
1037 }
1038
1039 #ifndef CURL_DISABLE_BINDLOCAL
1040 /* possibly bind the local end to an IP, interface or port */
1041 if(ctx->addr.family == AF_INET
1042 #ifdef ENABLE_IPV6
1043 || ctx->addr.family == AF_INET6
1044 #endif
1045 ) {
1046 result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1047 Curl_ipv6_scope(&ctx->addr.sa_addr));
1048 if(result) {
1049 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1050 /* The address family is not supported on this interface.
1051 We can continue trying addresses */
1052 result = CURLE_COULDNT_CONNECT;
1053 }
1054 goto out;
1055 }
1056 }
1057 #endif
1058
1059 /* set socket non-blocking */
1060 (void)curlx_nonblock(ctx->sock, TRUE);
1061 ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1062 out:
1063 if(result) {
1064 if(ctx->sock != CURL_SOCKET_BAD) {
1065 socket_close(data, cf->conn, TRUE, ctx->sock);
1066 ctx->sock = CURL_SOCKET_BAD;
1067 }
1068 }
1069 else if(isconnected) {
1070 set_local_ip(cf, data);
1071 ctx->connected_at = Curl_now();
1072 cf->connected = TRUE;
1073 }
1074 CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
1075 result, ctx->sock);
1076 return result;
1077 }
1078
do_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool is_tcp_fastopen)1079 static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1080 bool is_tcp_fastopen)
1081 {
1082 struct cf_socket_ctx *ctx = cf->ctx;
1083 #ifdef TCP_FASTOPEN_CONNECT
1084 int optval = 1;
1085 #endif
1086 int rc = -1;
1087
1088 (void)data;
1089 if(is_tcp_fastopen) {
1090 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1091 # if defined(HAVE_BUILTIN_AVAILABLE)
1092 /* while connectx function is available since macOS 10.11 / iOS 9,
1093 it did not have the interface declared correctly until
1094 Xcode 9 / macOS SDK 10.13 */
1095 if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1096 sa_endpoints_t endpoints;
1097 endpoints.sae_srcif = 0;
1098 endpoints.sae_srcaddr = NULL;
1099 endpoints.sae_srcaddrlen = 0;
1100 endpoints.sae_dstaddr = &ctx->addr.sa_addr;
1101 endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1102
1103 rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1104 CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1105 NULL, 0, NULL, NULL);
1106 }
1107 else {
1108 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1109 }
1110 # else
1111 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1112 # endif /* HAVE_BUILTIN_AVAILABLE */
1113 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1114 if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1115 (void *)&optval, sizeof(optval)) < 0)
1116 infof(data, "Failed to enable TCP Fast Open on fd %"
1117 CURL_FORMAT_SOCKET_T, ctx->sock);
1118
1119 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1120 #elif defined(MSG_FASTOPEN) /* old Linux */
1121 if(cf->conn->given->flags & PROTOPT_SSL)
1122 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1123 else
1124 rc = 0; /* Do nothing */
1125 #endif
1126 }
1127 else {
1128 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1129 }
1130 return rc;
1131 }
1132
cf_tcp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1133 static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1134 struct Curl_easy *data,
1135 bool blocking, bool *done)
1136 {
1137 struct cf_socket_ctx *ctx = cf->ctx;
1138 CURLcode result = CURLE_COULDNT_CONNECT;
1139 int rc = 0;
1140
1141 (void)data;
1142 if(cf->connected) {
1143 *done = TRUE;
1144 return CURLE_OK;
1145 }
1146
1147 /* TODO: need to support blocking connect? */
1148 if(blocking)
1149 return CURLE_UNSUPPORTED_PROTOCOL;
1150
1151 *done = FALSE; /* a very negative world view is best */
1152 if(ctx->sock == CURL_SOCKET_BAD) {
1153 int error;
1154
1155 result = cf_socket_open(cf, data);
1156 if(result)
1157 goto out;
1158
1159 if(cf->connected) {
1160 *done = TRUE;
1161 return CURLE_OK;
1162 }
1163
1164 /* Connect TCP socket */
1165 rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1166 error = SOCKERRNO;
1167 set_local_ip(cf, data);
1168 CURL_TRC_CF(data, cf, "local address %s port %d...",
1169 ctx->l_ip, ctx->l_port);
1170 if(-1 == rc) {
1171 result = socket_connect_result(data, ctx->r_ip, error);
1172 goto out;
1173 }
1174 }
1175
1176 #ifdef mpeix
1177 /* Call this function once now, and ignore the results. We do this to
1178 "clear" the error state on the socket so that we can later read it
1179 reliably. This is reported necessary on the MPE/iX operating
1180 system. */
1181 (void)verifyconnect(ctx->sock, NULL);
1182 #endif
1183 /* check socket for connect */
1184 rc = SOCKET_WRITABLE(ctx->sock, 0);
1185
1186 if(rc == 0) { /* no connection yet */
1187 CURL_TRC_CF(data, cf, "not connected yet");
1188 return CURLE_OK;
1189 }
1190 else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1191 if(verifyconnect(ctx->sock, &ctx->error)) {
1192 /* we are connected with TCP, awesome! */
1193 ctx->connected_at = Curl_now();
1194 set_local_ip(cf, data);
1195 *done = TRUE;
1196 cf->connected = TRUE;
1197 CURL_TRC_CF(data, cf, "connected");
1198 return CURLE_OK;
1199 }
1200 }
1201 else if(rc & CURL_CSELECT_ERR) {
1202 (void)verifyconnect(ctx->sock, &ctx->error);
1203 result = CURLE_COULDNT_CONNECT;
1204 }
1205
1206 out:
1207 if(result) {
1208 if(ctx->error) {
1209 set_local_ip(cf, data);
1210 data->state.os_errno = ctx->error;
1211 SET_SOCKERRNO(ctx->error);
1212 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1213 {
1214 char buffer[STRERROR_LEN];
1215 infof(data, "connect to %s port %u from %s port %d failed: %s",
1216 ctx->r_ip, ctx->r_port, ctx->l_ip, ctx->l_port,
1217 Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1218 }
1219 #endif
1220 }
1221 if(ctx->sock != CURL_SOCKET_BAD) {
1222 socket_close(data, cf->conn, TRUE, ctx->sock);
1223 ctx->sock = CURL_SOCKET_BAD;
1224 }
1225 *done = FALSE;
1226 }
1227 return result;
1228 }
1229
cf_socket_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)1230 static void cf_socket_get_host(struct Curl_cfilter *cf,
1231 struct Curl_easy *data,
1232 const char **phost,
1233 const char **pdisplay_host,
1234 int *pport)
1235 {
1236 (void)data;
1237 *phost = cf->conn->host.name;
1238 *pdisplay_host = cf->conn->host.dispname;
1239 *pport = cf->conn->port;
1240 }
1241
cf_socket_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)1242 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1243 struct Curl_easy *data,
1244 struct easy_pollset *ps)
1245 {
1246 struct cf_socket_ctx *ctx = cf->ctx;
1247
1248 if(ctx->sock != CURL_SOCKET_BAD) {
1249 if(!cf->connected) {
1250 Curl_pollset_set_out_only(data, ps, ctx->sock);
1251 CURL_TRC_CF(data, cf, "adjust_pollset(!connected) -> %d socks", ps->num);
1252 }
1253 else if(!ctx->active) {
1254 Curl_pollset_add_in(data, ps, ctx->sock);
1255 CURL_TRC_CF(data, cf, "adjust_pollset(!active) -> %d socks", ps->num);
1256 }
1257 }
1258 }
1259
cf_socket_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1260 static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1261 const struct Curl_easy *data)
1262 {
1263 struct cf_socket_ctx *ctx = cf->ctx;
1264 int readable;
1265
1266 (void)data;
1267 if(!Curl_bufq_is_empty(&ctx->recvbuf))
1268 return TRUE;
1269
1270 readable = SOCKET_READABLE(ctx->sock, 0);
1271 return (readable > 0 && (readable & CURL_CSELECT_IN));
1272 }
1273
cf_socket_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1274 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1275 const void *buf, size_t len, CURLcode *err)
1276 {
1277 struct cf_socket_ctx *ctx = cf->ctx;
1278 curl_socket_t fdsave;
1279 ssize_t nwritten;
1280 size_t orig_len = len;
1281
1282 *err = CURLE_OK;
1283 fdsave = cf->conn->sock[cf->sockindex];
1284 cf->conn->sock[cf->sockindex] = ctx->sock;
1285
1286 #ifdef DEBUGBUILD
1287 /* simulate network blocking/partial writes */
1288 if(ctx->wblock_percent > 0) {
1289 unsigned char c;
1290 Curl_rand(data, &c, 1);
1291 if(c >= ((100-ctx->wblock_percent)*256/100)) {
1292 CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1293 *err = CURLE_AGAIN;
1294 nwritten = -1;
1295 cf->conn->sock[cf->sockindex] = fdsave;
1296 return nwritten;
1297 }
1298 }
1299 if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1300 len = len * ctx->wpartial_percent / 100;
1301 if(!len)
1302 len = 1;
1303 CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1304 orig_len, len);
1305 }
1306 #endif
1307
1308 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1309 if(cf->conn->bits.tcp_fastopen) {
1310 nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1311 &cf->conn->remote_addr->sa_addr,
1312 cf->conn->remote_addr->addrlen);
1313 cf->conn->bits.tcp_fastopen = FALSE;
1314 }
1315 else
1316 #endif
1317 nwritten = swrite(ctx->sock, buf, len);
1318
1319 if(-1 == nwritten) {
1320 int sockerr = SOCKERRNO;
1321
1322 if(
1323 #ifdef WSAEWOULDBLOCK
1324 /* This is how Windows does it */
1325 (WSAEWOULDBLOCK == sockerr)
1326 #else
1327 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1328 due to its inability to send off data without blocking. We therefore
1329 treat both error codes the same here */
1330 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1331 (EINPROGRESS == sockerr)
1332 #endif
1333 ) {
1334 /* this is just a case of EWOULDBLOCK */
1335 *err = CURLE_AGAIN;
1336 }
1337 else {
1338 char buffer[STRERROR_LEN];
1339 failf(data, "Send failure: %s",
1340 Curl_strerror(sockerr, buffer, sizeof(buffer)));
1341 data->state.os_errno = sockerr;
1342 *err = CURLE_SEND_ERROR;
1343 }
1344 }
1345
1346 CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1347 orig_len, (int)nwritten, *err);
1348 cf->conn->sock[cf->sockindex] = fdsave;
1349 return nwritten;
1350 }
1351
cf_socket_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)1352 static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1353 char *buf, size_t len, CURLcode *err)
1354 {
1355 struct cf_socket_ctx *ctx = cf->ctx;
1356 curl_socket_t fdsave;
1357 ssize_t nread;
1358
1359 *err = CURLE_OK;
1360
1361 fdsave = cf->conn->sock[cf->sockindex];
1362 cf->conn->sock[cf->sockindex] = ctx->sock;
1363
1364 #ifdef DEBUGBUILD
1365 /* simulate network blocking/partial reads */
1366 if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1367 unsigned char c;
1368 Curl_rand(data, &c, 1);
1369 if(c >= ((100-ctx->rblock_percent)*256/100)) {
1370 CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1371 *err = CURLE_AGAIN;
1372 nread = -1;
1373 cf->conn->sock[cf->sockindex] = fdsave;
1374 return nread;
1375 }
1376 }
1377 if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1378 size_t orig_len = len;
1379 len = ctx->recv_max;
1380 CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1381 orig_len, len);
1382 }
1383 #endif
1384
1385 if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1386 CURL_TRC_CF(data, cf, "recv from buffer");
1387 nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1388 }
1389 else {
1390 struct reader_ctx rctx;
1391
1392 rctx.cf = cf;
1393 rctx.data = data;
1394
1395 /* "small" reads may trigger filling our buffer, "large" reads
1396 * are probably not worth the additional copy */
1397 if(ctx->buffer_recv && len < NW_SMALL_READS) {
1398 ssize_t nwritten;
1399 nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
1400 if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1401 /* we have a partial read with an error. need to deliver
1402 * what we got, return the error later. */
1403 CURL_TRC_CF(data, cf, "partial read: empty buffer first");
1404 nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1405 }
1406 else if(nwritten < 0) {
1407 nread = -1;
1408 goto out;
1409 }
1410 else if(nwritten == 0) {
1411 /* eof */
1412 *err = CURLE_OK;
1413 nread = 0;
1414 }
1415 else {
1416 CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
1417 nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1418 }
1419 }
1420 else {
1421 nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
1422 }
1423 }
1424
1425 out:
1426 CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1427 *err);
1428 if(nread > 0 && !ctx->got_first_byte) {
1429 ctx->first_byte_at = Curl_now();
1430 ctx->got_first_byte = TRUE;
1431 }
1432 cf->conn->sock[cf->sockindex] = fdsave;
1433 return nread;
1434 }
1435
conn_set_primary_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1436 static void conn_set_primary_ip(struct Curl_cfilter *cf,
1437 struct Curl_easy *data)
1438 {
1439 struct cf_socket_ctx *ctx = cf->ctx;
1440
1441 (void)data;
1442 DEBUGASSERT(sizeof(ctx->r_ip) == sizeof(cf->conn->primary_ip));
1443 memcpy(cf->conn->primary_ip, ctx->r_ip, sizeof(cf->conn->primary_ip));
1444 }
1445
cf_socket_active(struct Curl_cfilter * cf,struct Curl_easy * data)1446 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1447 {
1448 struct cf_socket_ctx *ctx = cf->ctx;
1449
1450 /* use this socket from now on */
1451 cf->conn->sock[cf->sockindex] = ctx->sock;
1452 /* the first socket info gets set at conn and data */
1453 if(cf->sockindex == FIRSTSOCKET) {
1454 cf->conn->remote_addr = &ctx->addr;
1455 #ifdef ENABLE_IPV6
1456 cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
1457 #endif
1458 conn_set_primary_ip(cf, data);
1459 set_local_ip(cf, data);
1460 Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
1461 /* buffering is currently disabled by default because we have stalls
1462 * in parallel transfers where not all buffered data is consumed and no
1463 * socket events happen.
1464 */
1465 ctx->buffer_recv = FALSE;
1466 }
1467 ctx->active = TRUE;
1468 }
1469
cf_socket_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1470 static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1471 struct Curl_easy *data,
1472 int event, int arg1, void *arg2)
1473 {
1474 struct cf_socket_ctx *ctx = cf->ctx;
1475
1476 (void)arg1;
1477 (void)arg2;
1478 switch(event) {
1479 case CF_CTRL_CONN_INFO_UPDATE:
1480 cf_socket_active(cf, data);
1481 break;
1482 case CF_CTRL_DATA_SETUP:
1483 Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
1484 break;
1485 case CF_CTRL_FORGET_SOCKET:
1486 ctx->sock = CURL_SOCKET_BAD;
1487 break;
1488 }
1489 return CURLE_OK;
1490 }
1491
cf_socket_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)1492 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1493 struct Curl_easy *data,
1494 bool *input_pending)
1495 {
1496 struct cf_socket_ctx *ctx = cf->ctx;
1497 struct pollfd pfd[1];
1498 int r;
1499
1500 *input_pending = FALSE;
1501 (void)data;
1502 if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1503 return FALSE;
1504
1505 /* Check with 0 timeout if there are any events pending on the socket */
1506 pfd[0].fd = ctx->sock;
1507 pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1508 pfd[0].revents = 0;
1509
1510 r = Curl_poll(pfd, 1, 0);
1511 if(r < 0) {
1512 CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1513 return FALSE;
1514 }
1515 else if(r == 0) {
1516 CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1517 return TRUE;
1518 }
1519 else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1520 CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1521 return FALSE;
1522 }
1523
1524 CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1525 *input_pending = TRUE;
1526 return TRUE;
1527 }
1528
cf_socket_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)1529 static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1530 struct Curl_easy *data,
1531 int query, int *pres1, void *pres2)
1532 {
1533 struct cf_socket_ctx *ctx = cf->ctx;
1534
1535 switch(query) {
1536 case CF_QUERY_SOCKET:
1537 DEBUGASSERT(pres2);
1538 *((curl_socket_t *)pres2) = ctx->sock;
1539 return CURLE_OK;
1540 case CF_QUERY_CONNECT_REPLY_MS:
1541 if(ctx->got_first_byte) {
1542 timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1543 *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
1544 }
1545 else
1546 *pres1 = -1;
1547 return CURLE_OK;
1548 case CF_QUERY_TIMER_CONNECT: {
1549 struct curltime *when = pres2;
1550 switch(ctx->transport) {
1551 case TRNSPRT_UDP:
1552 case TRNSPRT_QUIC:
1553 /* Since UDP connected sockets work different from TCP, we use the
1554 * time of the first byte from the peer as the "connect" time. */
1555 if(ctx->got_first_byte) {
1556 *when = ctx->first_byte_at;
1557 break;
1558 }
1559 FALLTHROUGH();
1560 default:
1561 *when = ctx->connected_at;
1562 break;
1563 }
1564 return CURLE_OK;
1565 }
1566 default:
1567 break;
1568 }
1569 return cf->next?
1570 cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1571 CURLE_UNKNOWN_OPTION;
1572 }
1573
1574 struct Curl_cftype Curl_cft_tcp = {
1575 "TCP",
1576 CF_TYPE_IP_CONNECT,
1577 CURL_LOG_LVL_NONE,
1578 cf_socket_destroy,
1579 cf_tcp_connect,
1580 cf_socket_close,
1581 cf_socket_get_host,
1582 cf_socket_adjust_pollset,
1583 cf_socket_data_pending,
1584 cf_socket_send,
1585 cf_socket_recv,
1586 cf_socket_cntrl,
1587 cf_socket_conn_is_alive,
1588 Curl_cf_def_conn_keep_alive,
1589 cf_socket_query,
1590 };
1591
Curl_cf_tcp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1592 CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1593 struct Curl_easy *data,
1594 struct connectdata *conn,
1595 const struct Curl_addrinfo *ai,
1596 int transport)
1597 {
1598 struct cf_socket_ctx *ctx = NULL;
1599 struct Curl_cfilter *cf = NULL;
1600 CURLcode result;
1601
1602 (void)data;
1603 (void)conn;
1604 DEBUGASSERT(transport == TRNSPRT_TCP);
1605 ctx = calloc(1, sizeof(*ctx));
1606 if(!ctx) {
1607 result = CURLE_OUT_OF_MEMORY;
1608 goto out;
1609 }
1610 cf_socket_ctx_init(ctx, ai, transport);
1611
1612 result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1613
1614 out:
1615 *pcf = (!result)? cf : NULL;
1616 if(result) {
1617 Curl_safefree(cf);
1618 Curl_safefree(ctx);
1619 }
1620
1621 return result;
1622 }
1623
cf_udp_setup_quic(struct Curl_cfilter * cf,struct Curl_easy * data)1624 static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1625 struct Curl_easy *data)
1626 {
1627 struct cf_socket_ctx *ctx = cf->ctx;
1628 int rc;
1629
1630 /* QUIC needs a connected socket, nonblocking */
1631 DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1632
1633 #if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
1634 (void)rc;
1635 /* On macOS OpenSSL QUIC fails on connected sockets.
1636 * see: <https://github.com/openssl/openssl/issues/23251> */
1637 #else
1638 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1639 if(-1 == rc) {
1640 return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
1641 }
1642 ctx->sock_connected = TRUE;
1643 #endif
1644 set_local_ip(cf, data);
1645 CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
1646 " connected: [%s:%d] -> [%s:%d]",
1647 (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
1648 ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port);
1649
1650 (void)curlx_nonblock(ctx->sock, TRUE);
1651 switch(ctx->addr.family) {
1652 #if defined(__linux__) && defined(IP_MTU_DISCOVER)
1653 case AF_INET: {
1654 int val = IP_PMTUDISC_DO;
1655 (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1656 sizeof(val));
1657 break;
1658 }
1659 #endif
1660 #if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1661 case AF_INET6: {
1662 int val = IPV6_PMTUDISC_DO;
1663 (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1664 sizeof(val));
1665 break;
1666 }
1667 #endif
1668 }
1669 return CURLE_OK;
1670 }
1671
cf_udp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1672 static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1673 struct Curl_easy *data,
1674 bool blocking, bool *done)
1675 {
1676 struct cf_socket_ctx *ctx = cf->ctx;
1677 CURLcode result = CURLE_COULDNT_CONNECT;
1678
1679 (void)blocking;
1680 if(cf->connected) {
1681 *done = TRUE;
1682 return CURLE_OK;
1683 }
1684 *done = FALSE;
1685 if(ctx->sock == CURL_SOCKET_BAD) {
1686 result = cf_socket_open(cf, data);
1687 if(result) {
1688 CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1689 goto out;
1690 }
1691
1692 if(ctx->transport == TRNSPRT_QUIC) {
1693 result = cf_udp_setup_quic(cf, data);
1694 if(result)
1695 goto out;
1696 CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1697 CURL_FORMAT_SOCKET_T " (%s:%d)",
1698 ctx->sock, ctx->l_ip, ctx->l_port);
1699 }
1700 else {
1701 CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1702 CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
1703 }
1704 *done = TRUE;
1705 cf->connected = TRUE;
1706 }
1707 out:
1708 return result;
1709 }
1710
1711 struct Curl_cftype Curl_cft_udp = {
1712 "UDP",
1713 CF_TYPE_IP_CONNECT,
1714 CURL_LOG_LVL_NONE,
1715 cf_socket_destroy,
1716 cf_udp_connect,
1717 cf_socket_close,
1718 cf_socket_get_host,
1719 cf_socket_adjust_pollset,
1720 cf_socket_data_pending,
1721 cf_socket_send,
1722 cf_socket_recv,
1723 cf_socket_cntrl,
1724 cf_socket_conn_is_alive,
1725 Curl_cf_def_conn_keep_alive,
1726 cf_socket_query,
1727 };
1728
Curl_cf_udp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1729 CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1730 struct Curl_easy *data,
1731 struct connectdata *conn,
1732 const struct Curl_addrinfo *ai,
1733 int transport)
1734 {
1735 struct cf_socket_ctx *ctx = NULL;
1736 struct Curl_cfilter *cf = NULL;
1737 CURLcode result;
1738
1739 (void)data;
1740 (void)conn;
1741 DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1742 ctx = calloc(1, sizeof(*ctx));
1743 if(!ctx) {
1744 result = CURLE_OUT_OF_MEMORY;
1745 goto out;
1746 }
1747 cf_socket_ctx_init(ctx, ai, transport);
1748
1749 result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1750
1751 out:
1752 *pcf = (!result)? cf : NULL;
1753 if(result) {
1754 Curl_safefree(cf);
1755 Curl_safefree(ctx);
1756 }
1757
1758 return result;
1759 }
1760
1761 /* this is the TCP filter which can also handle this case */
1762 struct Curl_cftype Curl_cft_unix = {
1763 "UNIX",
1764 CF_TYPE_IP_CONNECT,
1765 CURL_LOG_LVL_NONE,
1766 cf_socket_destroy,
1767 cf_tcp_connect,
1768 cf_socket_close,
1769 cf_socket_get_host,
1770 cf_socket_adjust_pollset,
1771 cf_socket_data_pending,
1772 cf_socket_send,
1773 cf_socket_recv,
1774 cf_socket_cntrl,
1775 cf_socket_conn_is_alive,
1776 Curl_cf_def_conn_keep_alive,
1777 cf_socket_query,
1778 };
1779
Curl_cf_unix_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1780 CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1781 struct Curl_easy *data,
1782 struct connectdata *conn,
1783 const struct Curl_addrinfo *ai,
1784 int transport)
1785 {
1786 struct cf_socket_ctx *ctx = NULL;
1787 struct Curl_cfilter *cf = NULL;
1788 CURLcode result;
1789
1790 (void)data;
1791 (void)conn;
1792 DEBUGASSERT(transport == TRNSPRT_UNIX);
1793 ctx = calloc(1, sizeof(*ctx));
1794 if(!ctx) {
1795 result = CURLE_OUT_OF_MEMORY;
1796 goto out;
1797 }
1798 cf_socket_ctx_init(ctx, ai, transport);
1799
1800 result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
1801
1802 out:
1803 *pcf = (!result)? cf : NULL;
1804 if(result) {
1805 Curl_safefree(cf);
1806 Curl_safefree(ctx);
1807 }
1808
1809 return result;
1810 }
1811
cf_tcp_accept_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1812 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
1813 struct Curl_easy *data,
1814 bool blocking, bool *done)
1815 {
1816 /* we start accepted, if we ever close, we cannot go on */
1817 (void)data;
1818 (void)blocking;
1819 if(cf->connected) {
1820 *done = TRUE;
1821 return CURLE_OK;
1822 }
1823 return CURLE_FAILED_INIT;
1824 }
1825
1826 struct Curl_cftype Curl_cft_tcp_accept = {
1827 "TCP-ACCEPT",
1828 CF_TYPE_IP_CONNECT,
1829 CURL_LOG_LVL_NONE,
1830 cf_socket_destroy,
1831 cf_tcp_accept_connect,
1832 cf_socket_close,
1833 cf_socket_get_host, /* TODO: not accurate */
1834 cf_socket_adjust_pollset,
1835 cf_socket_data_pending,
1836 cf_socket_send,
1837 cf_socket_recv,
1838 cf_socket_cntrl,
1839 cf_socket_conn_is_alive,
1840 Curl_cf_def_conn_keep_alive,
1841 cf_socket_query,
1842 };
1843
Curl_conn_tcp_listen_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)1844 CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
1845 struct connectdata *conn,
1846 int sockindex, curl_socket_t *s)
1847 {
1848 CURLcode result;
1849 struct Curl_cfilter *cf = NULL;
1850 struct cf_socket_ctx *ctx = NULL;
1851
1852 /* replace any existing */
1853 Curl_conn_cf_discard_all(data, conn, sockindex);
1854 DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
1855
1856 ctx = calloc(1, sizeof(*ctx));
1857 if(!ctx) {
1858 result = CURLE_OUT_OF_MEMORY;
1859 goto out;
1860 }
1861 ctx->transport = conn->transport;
1862 ctx->sock = *s;
1863 ctx->accepted = FALSE;
1864 result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
1865 if(result)
1866 goto out;
1867 Curl_conn_cf_add(data, conn, sockindex, cf);
1868
1869 conn->sock[sockindex] = ctx->sock;
1870 set_local_ip(cf, data);
1871 ctx->active = TRUE;
1872 ctx->connected_at = Curl_now();
1873 cf->connected = TRUE;
1874 CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
1875 CURL_FORMAT_SOCKET_T ")", ctx->sock);
1876
1877 out:
1878 if(result) {
1879 Curl_safefree(cf);
1880 Curl_safefree(ctx);
1881 }
1882 return result;
1883 }
1884
set_accepted_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1885 static void set_accepted_remote_ip(struct Curl_cfilter *cf,
1886 struct Curl_easy *data)
1887 {
1888 struct cf_socket_ctx *ctx = cf->ctx;
1889 #ifdef HAVE_GETPEERNAME
1890 char buffer[STRERROR_LEN];
1891 struct Curl_sockaddr_storage ssrem;
1892 curl_socklen_t plen;
1893
1894 ctx->r_ip[0] = 0;
1895 ctx->r_port = 0;
1896 plen = sizeof(ssrem);
1897 memset(&ssrem, 0, plen);
1898 if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
1899 int error = SOCKERRNO;
1900 failf(data, "getpeername() failed with errno %d: %s",
1901 error, Curl_strerror(error, buffer, sizeof(buffer)));
1902 return;
1903 }
1904 if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
1905 ctx->r_ip, &ctx->r_port)) {
1906 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
1907 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1908 return;
1909 }
1910 #else
1911 ctx->r_ip[0] = 0;
1912 ctx->r_port = 0;
1913 (void)data;
1914 #endif
1915 }
1916
Curl_conn_tcp_accepted_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)1917 CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
1918 struct connectdata *conn,
1919 int sockindex, curl_socket_t *s)
1920 {
1921 struct Curl_cfilter *cf = NULL;
1922 struct cf_socket_ctx *ctx = NULL;
1923
1924 cf = conn->cfilter[sockindex];
1925 if(!cf || cf->cft != &Curl_cft_tcp_accept)
1926 return CURLE_FAILED_INIT;
1927
1928 ctx = cf->ctx;
1929 /* discard the listen socket */
1930 socket_close(data, conn, TRUE, ctx->sock);
1931 ctx->sock = *s;
1932 conn->sock[sockindex] = ctx->sock;
1933 set_accepted_remote_ip(cf, data);
1934 set_local_ip(cf, data);
1935 ctx->active = TRUE;
1936 ctx->accepted = TRUE;
1937 ctx->connected_at = Curl_now();
1938 cf->connected = TRUE;
1939 CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
1940 ", remote=%s port=%d)",
1941 ctx->sock, ctx->r_ip, ctx->r_port);
1942
1943 return CURLE_OK;
1944 }
1945
1946 /**
1947 * Return TRUE iff `cf` is a socket filter.
1948 */
cf_is_socket(struct Curl_cfilter * cf)1949 static bool cf_is_socket(struct Curl_cfilter *cf)
1950 {
1951 return cf && (cf->cft == &Curl_cft_tcp ||
1952 cf->cft == &Curl_cft_udp ||
1953 cf->cft == &Curl_cft_unix ||
1954 cf->cft == &Curl_cft_tcp_accept);
1955 }
1956
Curl_cf_socket_peek(struct Curl_cfilter * cf,struct Curl_easy * data,curl_socket_t * psock,const struct Curl_sockaddr_ex ** paddr,const char ** pr_ip_str,int * pr_port,const char ** pl_ip_str,int * pl_port)1957 CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
1958 struct Curl_easy *data,
1959 curl_socket_t *psock,
1960 const struct Curl_sockaddr_ex **paddr,
1961 const char **pr_ip_str, int *pr_port,
1962 const char **pl_ip_str, int *pl_port)
1963 {
1964 if(cf_is_socket(cf) && cf->ctx) {
1965 struct cf_socket_ctx *ctx = cf->ctx;
1966
1967 if(psock)
1968 *psock = ctx->sock;
1969 if(paddr)
1970 *paddr = &ctx->addr;
1971 if(pr_ip_str)
1972 *pr_ip_str = ctx->r_ip;
1973 if(pr_port)
1974 *pr_port = ctx->r_port;
1975 if(pl_port ||pl_ip_str) {
1976 set_local_ip(cf, data);
1977 if(pl_ip_str)
1978 *pl_ip_str = ctx->l_ip;
1979 if(pl_port)
1980 *pl_port = ctx->l_port;
1981 }
1982 return CURLE_OK;
1983 }
1984 return CURLE_FAILED_INIT;
1985 }
1986