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