• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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