Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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.haxx.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  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #ifdef HAVE_NETINET_IN_H
     26 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
     27 #endif
     28 #ifdef HAVE_SYS_UN_H
     29 #include <sys/un.h> /* for sockaddr_un */
     30 #endif
     31 #ifdef HAVE_LINUX_TCP_H
     32 #include <linux/tcp.h>
     33 #elif defined(HAVE_NETINET_TCP_H)
     34 #include <netinet/tcp.h>
     35 #endif
     36 #ifdef HAVE_SYS_IOCTL_H
     37 #include <sys/ioctl.h>
     38 #endif
     39 #ifdef HAVE_NETDB_H
     40 #include <netdb.h>
     41 #endif
     42 #ifdef HAVE_FCNTL_H
     43 #include <fcntl.h>
     44 #endif
     45 #ifdef HAVE_ARPA_INET_H
     46 #include <arpa/inet.h>
     47 #endif
     48 
     49 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
     50 #include <sys/filio.h>
     51 #endif
     52 #ifdef NETWARE
     53 #undef in_addr_t
     54 #define in_addr_t unsigned long
     55 #endif
     56 #ifdef __VMS
     57 #include <in.h>
     58 #include <inet.h>
     59 #endif
     60 
     61 #include "urldata.h"
     62 #include "sendf.h"
     63 #include "if2ip.h"
     64 #include "strerror.h"
     65 #include "connect.h"
     66 #include "select.h"
     67 #include "url.h" /* for Curl_safefree() */
     68 #include "multiif.h"
     69 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
     70 #include "inet_ntop.h"
     71 #include "inet_pton.h"
     72 #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */
     73 #include "progress.h"
     74 #include "warnless.h"
     75 #include "conncache.h"
     76 #include "multihandle.h"
     77 #include "system_win32.h"
     78 
     79 /* The last 3 #include files should be in this order */
     80 #include "curl_printf.h"
     81 #include "curl_memory.h"
     82 #include "memdebug.h"
     83 
     84 #ifdef __SYMBIAN32__
     85 /* This isn't actually supported under Symbian OS */
     86 #undef SO_NOSIGPIPE
     87 #endif
     88 
     89 static bool verifyconnect(curl_socket_t sockfd, int *error);
     90 
     91 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
     92 /* DragonFlyBSD and Windows use millisecond units */
     93 #define KEEPALIVE_FACTOR(x) (x *= 1000)
     94 #else
     95 #define KEEPALIVE_FACTOR(x)
     96 #endif
     97 
     98 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
     99 #define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
    100 
    101 struct tcp_keepalive {
    102   u_long onoff;
    103   u_long keepalivetime;
    104   u_long keepaliveinterval;
    105 };
    106 #endif
    107 
    108 static void
    109 tcpkeepalive(struct Curl_easy *data,
    110              curl_socket_t sockfd)
    111 {
    112   int optval = data->set.tcp_keepalive?1:0;
    113 
    114   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
    115   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
    116         (void *)&optval, sizeof(optval)) < 0) {
    117     infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
    118   }
    119   else {
    120 #if defined(SIO_KEEPALIVE_VALS)
    121     struct tcp_keepalive vals;
    122     DWORD dummy;
    123     vals.onoff = 1;
    124     optval = curlx_sltosi(data->set.tcp_keepidle);
    125     KEEPALIVE_FACTOR(optval);
    126     vals.keepalivetime = optval;
    127     optval = curlx_sltosi(data->set.tcp_keepintvl);
    128     KEEPALIVE_FACTOR(optval);
    129     vals.keepaliveinterval = optval;
    130     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
    131                 NULL, 0, &dummy, NULL, NULL) != 0) {
    132       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
    133             (int)sockfd, WSAGetLastError());
    134     }
    135 #else
    136 #ifdef TCP_KEEPIDLE
    137     optval = curlx_sltosi(data->set.tcp_keepidle);
    138     KEEPALIVE_FACTOR(optval);
    139     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
    140           (void *)&optval, sizeof(optval)) < 0) {
    141       infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
    142     }
    143 #endif
    144 #ifdef TCP_KEEPINTVL
    145     optval = curlx_sltosi(data->set.tcp_keepintvl);
    146     KEEPALIVE_FACTOR(optval);
    147     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
    148           (void *)&optval, sizeof(optval)) < 0) {
    149       infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
    150     }
    151 #endif
    152 #ifdef TCP_KEEPALIVE
    153     /* Mac OS X style */
    154     optval = curlx_sltosi(data->set.tcp_keepidle);
    155     KEEPALIVE_FACTOR(optval);
    156     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
    157           (void *)&optval, sizeof(optval)) < 0) {
    158       infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
    159     }
    160 #endif
    161 #endif
    162   }
    163 }
    164 
    165 static CURLcode
    166 singleipconnect(struct connectdata *conn,
    167                 const Curl_addrinfo *ai, /* start connecting to this */
    168                 curl_socket_t *sock);
    169 
    170 /*
    171  * Curl_timeleft() returns the amount of milliseconds left allowed for the
    172  * transfer/connection. If the value is negative, the timeout time has already
    173  * elapsed.
    174  *
    175  * The start time is stored in progress.t_startsingle - as set with
    176  * Curl_pgrsTime(..., TIMER_STARTSINGLE);
    177  *
    178  * If 'nowp' is non-NULL, it points to the current time.
    179  * 'duringconnect' is FALSE if not during a connect, as then of course the
    180  * connect timeout is not taken into account!
    181  *
    182  * @unittest: 1303
    183  */
    184 timediff_t Curl_timeleft(struct Curl_easy *data,
    185                          struct curltime *nowp,
    186                          bool duringconnect)
    187 {
    188   int timeout_set = 0;
    189   timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
    190   struct curltime now;
    191 
    192   /* if a timeout is set, use the most restrictive one */
    193 
    194   if(data->set.timeout > 0)
    195     timeout_set |= 1;
    196   if(duringconnect && (data->set.connecttimeout > 0))
    197     timeout_set |= 2;
    198 
    199   switch(timeout_set) {
    200   case 1:
    201     timeout_ms = data->set.timeout;
    202     break;
    203   case 2:
    204     timeout_ms = data->set.connecttimeout;
    205     break;
    206   case 3:
    207     if(data->set.timeout < data->set.connecttimeout)
    208       timeout_ms = data->set.timeout;
    209     else
    210       timeout_ms = data->set.connecttimeout;
    211     break;
    212   default:
    213     /* use the default */
    214     if(!duringconnect)
    215       /* if we're not during connect, there's no default timeout so if we're
    216          at zero we better just return zero and not make it a negative number
    217          by the math below */
    218       return 0;
    219     break;
    220   }
    221 
    222   if(!nowp) {
    223     now = Curl_now();
    224     nowp = &now;
    225   }
    226 
    227   /* subtract elapsed time */
    228   if(duringconnect)
    229     /* since this most recent connect started */
    230     timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
    231   else
    232     /* since the entire operation started */
    233     timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
    234   if(!timeout_ms)
    235     /* avoid returning 0 as that means no timeout! */
    236     return -1;
    237 
    238   return timeout_ms;
    239 }
    240 
    241 static CURLcode bindlocal(struct connectdata *conn,
    242                           curl_socket_t sockfd, int af, unsigned int scope)
    243 {
    244   struct Curl_easy *data = conn->data;
    245 
    246   struct Curl_sockaddr_storage sa;
    247   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
    248   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
    249   struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
    250 #ifdef ENABLE_IPV6
    251   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
    252 #endif
    253 
    254   struct Curl_dns_entry *h = NULL;
    255   unsigned short port = data->set.localport; /* use this port number, 0 for
    256                                                 "random" */
    257   /* how many port numbers to try to bind to, increasing one at a time */
    258   int portnum = data->set.localportrange;
    259   const char *dev = data->set.str[STRING_DEVICE];
    260   int error;
    261 
    262   /*************************************************************
    263    * Select device to bind socket to
    264    *************************************************************/
    265   if(!dev && !port)
    266     /* no local kind of binding was requested */
    267     return CURLE_OK;
    268 
    269   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
    270 
    271   if(dev && (strlen(dev)<255) ) {
    272     char myhost[256] = "";
    273     int done = 0; /* -1 for error, 1 for address found */
    274     bool is_interface = FALSE;
    275     bool is_host = FALSE;
    276     static const char *if_prefix = "if!";
    277     static const char *host_prefix = "host!";
    278 
    279     if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
    280       dev += strlen(if_prefix);
    281       is_interface = TRUE;
    282     }
    283     else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
    284       dev += strlen(host_prefix);
    285       is_host = TRUE;
    286     }
    287 
    288     /* interface */
    289     if(!is_host) {
    290 #ifdef SO_BINDTODEVICE
    291       /* I am not sure any other OSs than Linux that provide this feature,
    292        * and at the least I cannot test. --Ben
    293        *
    294        * This feature allows one to tightly bind the local socket to a
    295        * particular interface.  This will force even requests to other
    296        * local interfaces to go out the external interface.
    297        *
    298        *
    299        * Only bind to the interface when specified as interface, not just
    300        * as a hostname or ip address.
    301        *
    302        * interface might be a VRF, eg: vrf-blue, which means it cannot be
    303        * converted to an IP address and would fail Curl_if2ip. Simply try
    304        * to use it straight away.
    305        */
    306       if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
    307                     dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
    308         /* This is typically "errno 1, error: Operation not permitted" if
    309          * you're not running as root or another suitable privileged
    310          * user.
    311          * If it succeeds it means the parameter was a valid interface and
    312          * not an IP address. Return immediately.
    313          */
    314         return CURLE_OK;
    315       }
    316 #endif
    317 
    318       switch(Curl_if2ip(af, scope, conn->scope_id, dev,
    319                         myhost, sizeof(myhost))) {
    320         case IF2IP_NOT_FOUND:
    321           if(is_interface) {
    322             /* Do not fall back to treating it as a host name */
    323             failf(data, "Couldn't bind to interface '%s'", dev);
    324             return CURLE_INTERFACE_FAILED;
    325           }
    326           break;
    327         case IF2IP_AF_NOT_SUPPORTED:
    328           /* Signal the caller to try another address family if available */
    329           return CURLE_UNSUPPORTED_PROTOCOL;
    330         case IF2IP_FOUND:
    331           is_interface = TRUE;
    332           /*
    333            * We now have the numerical IP address in the 'myhost' buffer
    334            */
    335           infof(data, "Local Interface %s is ip %s using address family %i\n",
    336                 dev, myhost, af);
    337           done = 1;
    338           break;
    339       }
    340     }
    341     if(!is_interface) {
    342       /*
    343        * This was not an interface, resolve the name as a host name
    344        * or IP number
    345        *
    346        * Temporarily force name resolution to use only the address type
    347        * of the connection. The resolve functions should really be changed
    348        * to take a type parameter instead.
    349        */
    350       long ipver = conn->ip_version;
    351       int rc;
    352 
    353       if(af == AF_INET)
    354         conn->ip_version = CURL_IPRESOLVE_V4;
    355 #ifdef ENABLE_IPV6
    356       else if(af == AF_INET6)
    357         conn->ip_version = CURL_IPRESOLVE_V6;
    358 #endif
    359 
    360       rc = Curl_resolv(conn, dev, 0, &h);
    361       if(rc == CURLRESOLV_PENDING)
    362         (void)Curl_resolver_wait_resolv(conn, &h);
    363       conn->ip_version = ipver;
    364 
    365       if(h) {
    366         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
    367         Curl_printable_address(h->addr, myhost, sizeof(myhost));
    368         infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
    369               dev, af, myhost, h->addr->ai_family);
    370         Curl_resolv_unlock(data, h);
    371         done = 1;
    372       }
    373       else {
    374         /*
    375          * provided dev was no interface (or interfaces are not supported
    376          * e.g. solaris) no ip address and no domain we fail here
    377          */
    378         done = -1;
    379       }
    380     }
    381 
    382     if(done > 0) {
    383 #ifdef ENABLE_IPV6
    384       /* IPv6 address */
    385       if(af == AF_INET6) {
    386 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
    387         char *scope_ptr = strchr(myhost, '%');
    388         if(scope_ptr)
    389           *(scope_ptr++) = 0;
    390 #endif
    391         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
    392           si6->sin6_family = AF_INET6;
    393           si6->sin6_port = htons(port);
    394 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
    395           if(scope_ptr)
    396             /* The "myhost" string either comes from Curl_if2ip or from
    397                Curl_printable_address. The latter returns only numeric scope
    398                IDs and the former returns none at all.  So the scope ID, if
    399                present, is known to be numeric */
    400             si6->sin6_scope_id = atoi(scope_ptr);
    401 #endif
    402         }
    403         sizeof_sa = sizeof(struct sockaddr_in6);
    404       }
    405       else
    406 #endif
    407       /* IPv4 address */
    408       if((af == AF_INET) &&
    409          (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
    410         si4->sin_family = AF_INET;
    411         si4->sin_port = htons(port);
    412         sizeof_sa = sizeof(struct sockaddr_in);
    413       }
    414     }
    415 
    416     if(done < 1) {
    417       /* errorbuf is set false so failf will overwrite any message already in
    418          the error buffer, so the user receives this error message instead of a
    419          generic resolve error. */
    420       data->state.errorbuf = FALSE;
    421       failf(data, "Couldn't bind to '%s'", dev);
    422       return CURLE_INTERFACE_FAILED;
    423     }
    424   }
    425   else {
    426     /* no device was given, prepare sa to match af's needs */
    427 #ifdef ENABLE_IPV6
    428     if(af == AF_INET6) {
    429       si6->sin6_family = AF_INET6;
    430       si6->sin6_port = htons(port);
    431       sizeof_sa = sizeof(struct sockaddr_in6);
    432     }
    433     else
    434 #endif
    435     if(af == AF_INET) {
    436       si4->sin_family = AF_INET;
    437       si4->sin_port = htons(port);
    438       sizeof_sa = sizeof(struct sockaddr_in);
    439     }
    440   }
    441 
    442   for(;;) {
    443     if(bind(sockfd, sock, sizeof_sa) >= 0) {
    444       /* we succeeded to bind */
    445       struct Curl_sockaddr_storage add;
    446       curl_socklen_t size = sizeof(add);
    447       memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
    448       if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
    449         data->state.os_errno = error = SOCKERRNO;
    450         failf(data, "getsockname() failed with errno %d: %s",
    451               error, Curl_strerror(conn, error));
    452         return CURLE_INTERFACE_FAILED;
    453       }
    454       infof(data, "Local port: %hu\n", port);
    455       conn->bits.bound = TRUE;
    456       return CURLE_OK;
    457     }
    458 
    459     if(--portnum > 0) {
    460       infof(data, "Bind to local port %hu failed, trying next\n", port);
    461       port++; /* try next port */
    462       /* We re-use/clobber the port variable here below */
    463       if(sock->sa_family == AF_INET)
    464         si4->sin_port = ntohs(port);
    465 #ifdef ENABLE_IPV6
    466       else
    467         si6->sin6_port = ntohs(port);
    468 #endif
    469     }
    470     else
    471       break;
    472   }
    473 
    474   data->state.os_errno = error = SOCKERRNO;
    475   failf(data, "bind failed with errno %d: %s",
    476         error, Curl_strerror(conn, error));
    477 
    478   return CURLE_INTERFACE_FAILED;
    479 }
    480 
    481 /*
    482  * verifyconnect() returns TRUE if the connect really has happened.
    483  */
    484 static bool verifyconnect(curl_socket_t sockfd, int *error)
    485 {
    486   bool rc = TRUE;
    487 #ifdef SO_ERROR
    488   int err = 0;
    489   curl_socklen_t errSize = sizeof(err);
    490 
    491 #ifdef WIN32
    492   /*
    493    * In October 2003 we effectively nullified this function on Windows due to
    494    * problems with it using all CPU in multi-threaded cases.
    495    *
    496    * In May 2004, we bring it back to offer more info back on connect failures.
    497    * Gisle Vanem could reproduce the former problems with this function, but
    498    * could avoid them by adding this SleepEx() call below:
    499    *
    500    *    "I don't have Rational Quantify, but the hint from his post was
    501    *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
    502    *    just Sleep(0) would be enough?) would release whatever
    503    *    mutex/critical-section the ntdll call is waiting on.
    504    *
    505    *    Someone got to verify this on Win-NT 4.0, 2000."
    506    */
    507 
    508 #ifdef _WIN32_WCE
    509   Sleep(0);
    510 #else
    511   SleepEx(0, FALSE);
    512 #endif
    513 
    514 #endif
    515 
    516   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
    517     err = SOCKERRNO;
    518 #ifdef _WIN32_WCE
    519   /* Old WinCE versions don't support SO_ERROR */
    520   if(WSAENOPROTOOPT == err) {
    521     SET_SOCKERRNO(0);
    522     err = 0;
    523   }
    524 #endif
    525 #ifdef __minix
    526   /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
    527   if(EBADIOCTL == err) {
    528     SET_SOCKERRNO(0);
    529     err = 0;
    530   }
    531 #endif
    532   if((0 == err) || (EISCONN == err))
    533     /* we are connected, awesome! */
    534     rc = TRUE;
    535   else
    536     /* This wasn't a successful connect */
    537     rc = FALSE;
    538   if(error)
    539     *error = err;
    540 #else
    541   (void)sockfd;
    542   if(error)
    543     *error = SOCKERRNO;
    544 #endif
    545   return rc;
    546 }
    547 
    548 /* Used within the multi interface. Try next IP address, return TRUE if no
    549    more address exists or error */
    550 static CURLcode trynextip(struct connectdata *conn,
    551                           int sockindex,
    552                           int tempindex)
    553 {
    554   const int other = tempindex ^ 1;
    555   CURLcode result = CURLE_COULDNT_CONNECT;
    556 
    557   /* First clean up after the failed socket.
    558      Don't close it yet to ensure that the next IP's socket gets a different
    559      file descriptor, which can prevent bugs when the curl_multi_socket_action
    560      interface is used with certain select() replacements such as kqueue. */
    561   curl_socket_t fd_to_close = conn->tempsock[tempindex];
    562   conn->tempsock[tempindex] = CURL_SOCKET_BAD;
    563 
    564   if(sockindex == FIRSTSOCKET) {
    565     Curl_addrinfo *ai = NULL;
    566     int family = AF_UNSPEC;
    567 
    568     if(conn->tempaddr[tempindex]) {
    569       /* find next address in the same protocol family */
    570       family = conn->tempaddr[tempindex]->ai_family;
    571       ai = conn->tempaddr[tempindex]->ai_next;
    572     }
    573 #ifdef ENABLE_IPV6
    574     else if(conn->tempaddr[0]) {
    575       /* happy eyeballs - try the other protocol family */
    576       int firstfamily = conn->tempaddr[0]->ai_family;
    577       family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET;
    578       ai = conn->tempaddr[0]->ai_next;
    579     }
    580 #endif
    581 
    582     while(ai) {
    583       if(conn->tempaddr[other]) {
    584         /* we can safely skip addresses of the other protocol family */
    585         while(ai && ai->ai_family != family)
    586           ai = ai->ai_next;
    587       }
    588 
    589       if(ai) {
    590         result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
    591         if(result == CURLE_COULDNT_CONNECT) {
    592           ai = ai->ai_next;
    593           continue;
    594         }
    595 
    596         conn->tempaddr[tempindex] = ai;
    597       }
    598       break;
    599     }
    600   }
    601 
    602   if(fd_to_close != CURL_SOCKET_BAD)
    603     Curl_closesocket(conn, fd_to_close);
    604 
    605   return result;
    606 }
    607 
    608 /* Copies connection info into the session handle to make it available
    609    when the session handle is no longer associated with a connection. */
    610 void Curl_persistconninfo(struct connectdata *conn)
    611 {
    612   memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
    613   memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
    614   conn->data->info.conn_scheme = conn->handler->scheme;
    615   conn->data->info.conn_protocol = conn->handler->protocol;
    616   conn->data->info.conn_primary_port = conn->primary_port;
    617   conn->data->info.conn_local_port = conn->local_port;
    618 }
    619 
    620 /* retrieves ip address and port from a sockaddr structure.
    621    note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
    622 static bool getaddressinfo(struct sockaddr *sa, char *addr,
    623                            long *port)
    624 {
    625   unsigned short us_port;
    626   struct sockaddr_in *si = NULL;
    627 #ifdef ENABLE_IPV6
    628   struct sockaddr_in6 *si6 = NULL;
    629 #endif
    630 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
    631   struct sockaddr_un *su = NULL;
    632 #endif
    633 
    634   switch(sa->sa_family) {
    635     case AF_INET:
    636       si = (struct sockaddr_in *)(void *) sa;
    637       if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
    638                         addr, MAX_IPADR_LEN)) {
    639         us_port = ntohs(si->sin_port);
    640         *port = us_port;
    641         return TRUE;
    642       }
    643       break;
    644 #ifdef ENABLE_IPV6
    645     case AF_INET6:
    646       si6 = (struct sockaddr_in6 *)(void *) sa;
    647       if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
    648                         addr, MAX_IPADR_LEN)) {
    649         us_port = ntohs(si6->sin6_port);
    650         *port = us_port;
    651         return TRUE;
    652       }
    653       break;
    654 #endif
    655 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
    656     case AF_UNIX:
    657       su = (struct sockaddr_un*)sa;
    658       snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
    659       *port = 0;
    660       return TRUE;
    661 #endif
    662     default:
    663       break;
    664   }
    665 
    666   addr[0] = '\0';
    667   *port = 0;
    668   errno = EAFNOSUPPORT;
    669   return FALSE;
    670 }
    671 
    672 /* retrieves the start/end point information of a socket of an established
    673    connection */
    674 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
    675 {
    676   curl_socklen_t len;
    677   struct Curl_sockaddr_storage ssrem;
    678   struct Curl_sockaddr_storage ssloc;
    679   struct Curl_easy *data = conn->data;
    680 
    681   if(conn->socktype == SOCK_DGRAM)
    682     /* there's no connection! */
    683     return;
    684 
    685   if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
    686     len = sizeof(struct Curl_sockaddr_storage);
    687     if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
    688       int error = SOCKERRNO;
    689       failf(data, "getpeername() failed with errno %d: %s",
    690             error, Curl_strerror(conn, error));
    691       return;
    692     }
    693 
    694     len = sizeof(struct Curl_sockaddr_storage);
    695     memset(&ssloc, 0, sizeof(ssloc));
    696     if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
    697       int error = SOCKERRNO;
    698       failf(data, "getsockname() failed with errno %d: %s",
    699             error, Curl_strerror(conn, error));
    700       return;
    701     }
    702 
    703     if(!getaddressinfo((struct sockaddr*)&ssrem,
    704                         conn->primary_ip, &conn->primary_port)) {
    705       failf(data, "ssrem inet_ntop() failed with errno %d: %s",
    706             errno, Curl_strerror(conn, errno));
    707       return;
    708     }
    709     memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
    710 
    711     if(!getaddressinfo((struct sockaddr*)&ssloc,
    712                        conn->local_ip, &conn->local_port)) {
    713       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
    714             errno, Curl_strerror(conn, errno));
    715       return;
    716     }
    717 
    718   }
    719 
    720   /* persist connection info in session handle */
    721   Curl_persistconninfo(conn);
    722 }
    723 
    724 /*
    725  * Curl_is_connected() checks if the socket has connected.
    726  */
    727 
    728 CURLcode Curl_is_connected(struct connectdata *conn,
    729                            int sockindex,
    730                            bool *connected)
    731 {
    732   struct Curl_easy *data = conn->data;
    733   CURLcode result = CURLE_OK;
    734   timediff_t allow;
    735   int error = 0;
    736   struct curltime now;
    737   int rc;
    738   int i;
    739 
    740   DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
    741 
    742   *connected = FALSE; /* a very negative world view is best */
    743 
    744   if(conn->bits.tcpconnect[sockindex]) {
    745     /* we are connected already! */
    746     *connected = TRUE;
    747     return CURLE_OK;
    748   }
    749 
    750   now = Curl_now();
    751 
    752   /* figure out how long time we have left to connect */
    753   allow = Curl_timeleft(data, &now, TRUE);
    754 
    755   if(allow < 0) {
    756     /* time-out, bail out, go home */
    757     failf(data, "Connection time-out");
    758     return CURLE_OPERATION_TIMEDOUT;
    759   }
    760 
    761   for(i = 0; i<2; i++) {
    762     const int other = i ^ 1;
    763     if(conn->tempsock[i] == CURL_SOCKET_BAD)
    764       continue;
    765 
    766 #ifdef mpeix
    767     /* Call this function once now, and ignore the results. We do this to
    768        "clear" the error state on the socket so that we can later read it
    769        reliably. This is reported necessary on the MPE/iX operating system. */
    770     (void)verifyconnect(conn->tempsock[i], NULL);
    771 #endif
    772 
    773     /* check socket for connect */
    774     rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
    775 
    776     if(rc == 0) { /* no connection yet */
    777       error = 0;
    778       if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
    779         infof(data, "After %ldms connect time, move on!\n",
    780               conn->timeoutms_per_addr);
    781         error = ETIMEDOUT;
    782       }
    783 
    784       /* should we try another protocol family? */
    785       if(i == 0 && conn->tempaddr[1] == NULL &&
    786          Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
    787         trynextip(conn, sockindex, 1);
    788       }
    789     }
    790     else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
    791       if(verifyconnect(conn->tempsock[i], &error)) {
    792         /* we are connected with TCP, awesome! */
    793 
    794         /* use this socket from now on */
    795         conn->sock[sockindex] = conn->tempsock[i];
    796         conn->ip_addr = conn->tempaddr[i];
    797         conn->tempsock[i] = CURL_SOCKET_BAD;
    798 #ifdef ENABLE_IPV6
    799         conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE;
    800 #endif
    801 
    802         /* close the other socket, if open */
    803         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
    804           Curl_closesocket(conn, conn->tempsock[other]);
    805           conn->tempsock[other] = CURL_SOCKET_BAD;
    806         }
    807 
    808         /* see if we need to do any proxy magic first once we connected */
    809         result = Curl_connected_proxy(conn, sockindex);
    810         if(result)
    811           return result;
    812 
    813         conn->bits.tcpconnect[sockindex] = TRUE;
    814 
    815         *connected = TRUE;
    816         if(sockindex == FIRSTSOCKET)
    817           Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
    818         Curl_updateconninfo(conn, conn->sock[sockindex]);
    819         Curl_verboseconnect(conn);
    820 
    821         return CURLE_OK;
    822       }
    823       infof(data, "Connection failed\n");
    824     }
    825     else if(rc & CURL_CSELECT_ERR)
    826       (void)verifyconnect(conn->tempsock[i], &error);
    827 
    828     /*
    829      * The connection failed here, we should attempt to connect to the "next
    830      * address" for the given host. But first remember the latest error.
    831      */
    832     if(error) {
    833       data->state.os_errno = error;
    834       SET_SOCKERRNO(error);
    835       if(conn->tempaddr[i]) {
    836         CURLcode status;
    837         char ipaddress[MAX_IPADR_LEN];
    838         Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
    839         infof(data, "connect to %s port %ld failed: %s\n",
    840               ipaddress, conn->port, Curl_strerror(conn, error));
    841 
    842         conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
    843                                    allow : allow / 2;
    844 
    845         status = trynextip(conn, sockindex, i);
    846         if(status != CURLE_COULDNT_CONNECT
    847             || conn->tempsock[other] == CURL_SOCKET_BAD)
    848           /* the last attempt failed and no other sockets remain open */
    849           result = status;
    850       }
    851     }
    852   }
    853 
    854   if(result) {
    855     /* no more addresses to try */
    856 
    857     const char *hostname;
    858 
    859     /* if the first address family runs out of addresses to try before
    860        the happy eyeball timeout, go ahead and try the next family now */
    861     if(conn->tempaddr[1] == NULL) {
    862       result = trynextip(conn, sockindex, 1);
    863       if(!result)
    864         return result;
    865     }
    866 
    867     if(conn->bits.socksproxy)
    868       hostname = conn->socks_proxy.host.name;
    869     else if(conn->bits.httpproxy)
    870       hostname = conn->http_proxy.host.name;
    871     else if(conn->bits.conn_to_host)
    872       hostname = conn->conn_to_host.name;
    873     else
    874       hostname = conn->host.name;
    875 
    876     failf(data, "Failed to connect to %s port %ld: %s",
    877         hostname, conn->port, Curl_strerror(conn, error));
    878   }
    879 
    880   return result;
    881 }
    882 
    883 void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
    884 {
    885 #if defined(TCP_NODELAY)
    886 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
    887   struct Curl_easy *data = conn->data;
    888 #endif
    889   curl_socklen_t onoff = (curl_socklen_t) 1;
    890   int level = IPPROTO_TCP;
    891 
    892 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
    893   (void) conn;
    894 #endif
    895 
    896   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
    897                 sizeof(onoff)) < 0)
    898     infof(data, "Could not set TCP_NODELAY: %s\n",
    899           Curl_strerror(conn, SOCKERRNO));
    900   else
    901     infof(data, "TCP_NODELAY set\n");
    902 #else
    903   (void)conn;
    904   (void)sockfd;
    905 #endif
    906 }
    907 
    908 #ifdef SO_NOSIGPIPE
    909 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
    910    sending data to a dead peer (instead of relying on the 4th argument to send
    911    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
    912    systems? */
    913 static void nosigpipe(struct connectdata *conn,
    914                       curl_socket_t sockfd)
    915 {
    916   struct Curl_easy *data = conn->data;
    917   int onoff = 1;
    918   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
    919                 sizeof(onoff)) < 0)
    920     infof(data, "Could not set SO_NOSIGPIPE: %s\n",
    921           Curl_strerror(conn, SOCKERRNO));
    922 }
    923 #else
    924 #define nosigpipe(x,y) Curl_nop_stmt
    925 #endif
    926 
    927 #ifdef USE_WINSOCK
    928 /* When you run a program that uses the Windows Sockets API, you may
    929    experience slow performance when you copy data to a TCP server.
    930 
    931    https://support.microsoft.com/kb/823764
    932 
    933    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
    934    Buffer Size
    935 
    936    The problem described in this knowledge-base is applied only to pre-Vista
    937    Windows.  Following function trying to detect OS version and skips
    938    SO_SNDBUF adjustment for Windows Vista and above.
    939 */
    940 #define DETECT_OS_NONE 0
    941 #define DETECT_OS_PREVISTA 1
    942 #define DETECT_OS_VISTA_OR_LATER 2
    943 
    944 void Curl_sndbufset(curl_socket_t sockfd)
    945 {
    946   int val = CURL_MAX_WRITE_SIZE + 32;
    947   int curval = 0;
    948   int curlen = sizeof(curval);
    949 
    950   static int detectOsState = DETECT_OS_NONE;
    951 
    952   if(detectOsState == DETECT_OS_NONE) {
    953     if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
    954                                    VERSION_GREATER_THAN_EQUAL))
    955       detectOsState = DETECT_OS_VISTA_OR_LATER;
    956     else
    957       detectOsState = DETECT_OS_PREVISTA;
    958   }
    959 
    960   if(detectOsState == DETECT_OS_VISTA_OR_LATER)
    961     return;
    962 
    963   if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
    964     if(curval > val)
    965       return;
    966 
    967   setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
    968 }
    969 #endif
    970 
    971 /*
    972  * singleipconnect()
    973  *
    974  * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
    975  * CURL_SOCKET_BAD. Other errors will however return proper errors.
    976  *
    977  * singleipconnect() connects to the given IP only, and it may return without
    978  * having connected.
    979  */
    980 static CURLcode singleipconnect(struct connectdata *conn,
    981                                 const Curl_addrinfo *ai,
    982                                 curl_socket_t *sockp)
    983 {
    984   struct Curl_sockaddr_ex addr;
    985   int rc = -1;
    986   int error = 0;
    987   bool isconnected = FALSE;
    988   struct Curl_easy *data = conn->data;
    989   curl_socket_t sockfd;
    990   CURLcode result;
    991   char ipaddress[MAX_IPADR_LEN];
    992   long port;
    993   bool is_tcp;
    994 #ifdef TCP_FASTOPEN_CONNECT
    995   int optval = 1;
    996 #endif
    997 
    998   *sockp = CURL_SOCKET_BAD;
    999 
   1000   result = Curl_socket(conn, ai, &addr, &sockfd);
   1001   if(result)
   1002     /* Failed to create the socket, but still return OK since we signal the
   1003        lack of socket as well. This allows the parent function to keep looping
   1004        over alternative addresses/socket families etc. */
   1005     return CURLE_OK;
   1006 
   1007   /* store remote address and port used in this connection attempt */
   1008   if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
   1009                      ipaddress, &port)) {
   1010     /* malformed address or bug in inet_ntop, try next address */
   1011     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
   1012           errno, Curl_strerror(conn, errno));
   1013     Curl_closesocket(conn, sockfd);
   1014     return CURLE_OK;
   1015   }
   1016   infof(data, "  Trying %s...\n", ipaddress);
   1017 
   1018 #ifdef ENABLE_IPV6
   1019   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
   1020     addr.socktype == SOCK_STREAM;
   1021 #else
   1022   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
   1023 #endif
   1024   if(is_tcp && data->set.tcp_nodelay)
   1025     Curl_tcpnodelay(conn, sockfd);
   1026 
   1027   nosigpipe(conn, sockfd);
   1028 
   1029   Curl_sndbufset(sockfd);
   1030 
   1031   if(is_tcp && data->set.tcp_keepalive)
   1032     tcpkeepalive(data, sockfd);
   1033 
   1034   if(data->set.fsockopt) {
   1035     /* activate callback for setting socket options */
   1036     error = data->set.fsockopt(data->set.sockopt_client,
   1037                                sockfd,
   1038                                CURLSOCKTYPE_IPCXN);
   1039 
   1040     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
   1041       isconnected = TRUE;
   1042     else if(error) {
   1043       Curl_closesocket(conn, sockfd); /* close the socket and bail out */
   1044       return CURLE_ABORTED_BY_CALLBACK;
   1045     }
   1046   }
   1047 
   1048   /* possibly bind the local end to an IP, interface or port */
   1049   if(addr.family == AF_INET
   1050 #ifdef ENABLE_IPV6
   1051      || addr.family == AF_INET6
   1052 #endif
   1053     ) {
   1054     result = bindlocal(conn, sockfd, addr.family,
   1055                        Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
   1056     if(result) {
   1057       Curl_closesocket(conn, sockfd); /* close socket and bail out */
   1058       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
   1059         /* The address family is not supported on this interface.
   1060            We can continue trying addresses */
   1061         return CURLE_COULDNT_CONNECT;
   1062       }
   1063       return result;
   1064     }
   1065   }
   1066 
   1067   /* set socket non-blocking */
   1068   (void)curlx_nonblock(sockfd, TRUE);
   1069 
   1070   conn->connecttime = Curl_now();
   1071   if(conn->num_addr > 1)
   1072     Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
   1073 
   1074   /* Connect TCP sockets, bind UDP */
   1075   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
   1076     if(conn->bits.tcp_fastopen) {
   1077 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
   1078 #  if defined(HAVE_BUILTIN_AVAILABLE)
   1079       /* while connectx function is available since macOS 10.11 / iOS 9,
   1080          it did not have the interface declared correctly until
   1081          Xcode 9 / macOS SDK 10.13 */
   1082       if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
   1083         sa_endpoints_t endpoints;
   1084         endpoints.sae_srcif = 0;
   1085         endpoints.sae_srcaddr = NULL;
   1086         endpoints.sae_srcaddrlen = 0;
   1087         endpoints.sae_dstaddr = &addr.sa_addr;
   1088         endpoints.sae_dstaddrlen = addr.addrlen;
   1089 
   1090         rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
   1091                       CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
   1092                       NULL, 0, NULL, NULL);
   1093       }
   1094       else {
   1095         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
   1096       }
   1097 #  else
   1098       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
   1099 #  endif /* HAVE_BUILTIN_AVAILABLE */
   1100 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
   1101       if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
   1102                     (void *)&optval, sizeof(optval)) < 0)
   1103         infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
   1104       else
   1105         infof(data, "TCP_FASTOPEN_CONNECT set\n");
   1106 
   1107       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
   1108 #elif defined(MSG_FASTOPEN) /* old Linux */
   1109       if(conn->given->flags & PROTOPT_SSL)
   1110         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
   1111       else
   1112         rc = 0; /* Do nothing */
   1113 #endif
   1114     }
   1115     else {
   1116       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
   1117     }
   1118 
   1119     if(-1 == rc)
   1120       error = SOCKERRNO;
   1121   }
   1122   else {
   1123     *sockp = sockfd;
   1124     return CURLE_OK;
   1125   }
   1126 
   1127   if(-1 == rc) {
   1128     switch(error) {
   1129     case EINPROGRESS:
   1130     case EWOULDBLOCK:
   1131 #if defined(EAGAIN)
   1132 #if (EAGAIN) != (EWOULDBLOCK)
   1133       /* On some platforms EAGAIN and EWOULDBLOCK are the
   1134        * same value, and on others they are different, hence
   1135        * the odd #if
   1136        */
   1137     case EAGAIN:
   1138 #endif
   1139 #endif
   1140       result = CURLE_OK;
   1141       break;
   1142 
   1143     default:
   1144       /* unknown error, fallthrough and try another address! */
   1145       infof(data, "Immediate connect fail for %s: %s\n",
   1146             ipaddress, Curl_strerror(conn, error));
   1147       data->state.os_errno = error;
   1148 
   1149       /* connect failed */
   1150       Curl_closesocket(conn, sockfd);
   1151       result = CURLE_COULDNT_CONNECT;
   1152     }
   1153   }
   1154 
   1155   if(!result)
   1156     *sockp = sockfd;
   1157 
   1158   return result;
   1159 }
   1160 
   1161 /*
   1162  * TCP connect to the given host with timeout, proxy or remote doesn't matter.
   1163  * There might be more than one IP address to try out. Fill in the passed
   1164  * pointer with the connected socket.
   1165  */
   1166 
   1167 CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   1168                           const struct Curl_dns_entry *remotehost)
   1169 {
   1170   struct Curl_easy *data = conn->data;
   1171   struct curltime before = Curl_now();
   1172   CURLcode result = CURLE_COULDNT_CONNECT;
   1173 
   1174   timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE);
   1175 
   1176   if(timeout_ms < 0) {
   1177     /* a precaution, no need to continue if time already is up */
   1178     failf(data, "Connection time-out");
   1179     return CURLE_OPERATION_TIMEDOUT;
   1180   }
   1181 
   1182   conn->num_addr = Curl_num_addresses(remotehost->addr);
   1183   conn->tempaddr[0] = remotehost->addr;
   1184   conn->tempaddr[1] = NULL;
   1185   conn->tempsock[0] = CURL_SOCKET_BAD;
   1186   conn->tempsock[1] = CURL_SOCKET_BAD;
   1187 
   1188   /* Max time for the next connection attempt */
   1189   conn->timeoutms_per_addr =
   1190     conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
   1191 
   1192   /* start connecting to first IP */
   1193   while(conn->tempaddr[0]) {
   1194     result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
   1195     if(!result)
   1196       break;
   1197     conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
   1198   }
   1199 
   1200   if(conn->tempsock[0] == CURL_SOCKET_BAD) {
   1201     if(!result)
   1202       result = CURLE_COULDNT_CONNECT;
   1203     return result;
   1204   }
   1205 
   1206   data->info.numconnects++; /* to track the number of connections made */
   1207   Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
   1208 
   1209   return CURLE_OK;
   1210 }
   1211 
   1212 struct connfind {
   1213   struct connectdata *tofind;
   1214   bool found;
   1215 };
   1216 
   1217 static int conn_is_conn(struct connectdata *conn, void *param)
   1218 {
   1219   struct connfind *f = (struct connfind *)param;
   1220   if(conn == f->tofind) {
   1221     f->found = TRUE;
   1222     return 1;
   1223   }
   1224   return 0;
   1225 }
   1226 
   1227 /*
   1228  * Used to extract socket and connectdata struct for the most recent
   1229  * transfer on the given Curl_easy.
   1230  *
   1231  * The returned socket will be CURL_SOCKET_BAD in case of failure!
   1232  */
   1233 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
   1234                                   struct connectdata **connp)
   1235 {
   1236   curl_socket_t sockfd;
   1237 
   1238   DEBUGASSERT(data);
   1239 
   1240   /* this works for an easy handle:
   1241    * - that has been used for curl_easy_perform()
   1242    * - that is associated with a multi handle, and whose connection
   1243    *   was detached with CURLOPT_CONNECT_ONLY
   1244    */
   1245   if(data->state.lastconnect && (data->multi_easy || data->multi)) {
   1246     struct connectdata *c = data->state.lastconnect;
   1247     struct connfind find;
   1248     find.tofind = data->state.lastconnect;
   1249     find.found = FALSE;
   1250 
   1251     Curl_conncache_foreach(data, data->multi_easy?
   1252                            &data->multi_easy->conn_cache:
   1253                            &data->multi->conn_cache, &find, conn_is_conn);
   1254 
   1255     if(!find.found) {
   1256       data->state.lastconnect = NULL;
   1257       return CURL_SOCKET_BAD;
   1258     }
   1259 
   1260     if(connp)
   1261       /* only store this if the caller cares for it */
   1262       *connp = c;
   1263     sockfd = c->sock[FIRSTSOCKET];
   1264   }
   1265   else
   1266     return CURL_SOCKET_BAD;
   1267 
   1268   return sockfd;
   1269 }
   1270 
   1271 /*
   1272  * Check if a connection seems to be alive.
   1273  */
   1274 bool Curl_connalive(struct connectdata *conn)
   1275 {
   1276   /* First determine if ssl */
   1277   if(conn->ssl[FIRSTSOCKET].use) {
   1278     /* use the SSL context */
   1279     if(!Curl_ssl_check_cxn(conn))
   1280       return false;   /* FIN received */
   1281   }
   1282 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
   1283 #ifdef MSG_PEEK
   1284   else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD)
   1285     return false;
   1286   else {
   1287     /* use the socket */
   1288     char buf;
   1289     if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
   1290             (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
   1291       return false;   /* FIN received */
   1292     }
   1293   }
   1294 #endif
   1295   return true;
   1296 }
   1297 
   1298 /*
   1299  * Close a socket.
   1300  *
   1301  * 'conn' can be NULL, beware!
   1302  */
   1303 int Curl_closesocket(struct connectdata *conn,
   1304                       curl_socket_t sock)
   1305 {
   1306   if(conn && conn->fclosesocket) {
   1307     if((sock == conn->sock[SECONDARYSOCKET]) &&
   1308        conn->sock_accepted[SECONDARYSOCKET])
   1309       /* if this socket matches the second socket, and that was created with
   1310          accept, then we MUST NOT call the callback but clear the accepted
   1311          status */
   1312       conn->sock_accepted[SECONDARYSOCKET] = FALSE;
   1313     else {
   1314       Curl_multi_closed(conn, sock);
   1315       return conn->fclosesocket(conn->closesocket_client, sock);
   1316     }
   1317   }
   1318 
   1319   if(conn)
   1320     /* tell the multi-socket code about this */
   1321     Curl_multi_closed(conn, sock);
   1322 
   1323   sclose(sock);
   1324 
   1325   return 0;
   1326 }
   1327 
   1328 /*
   1329  * Create a socket based on info from 'conn' and 'ai'.
   1330  *
   1331  * 'addr' should be a pointer to the correct struct to get data back, or NULL.
   1332  * 'sockfd' must be a pointer to a socket descriptor.
   1333  *
   1334  * If the open socket callback is set, used that!
   1335  *
   1336  */
   1337 CURLcode Curl_socket(struct connectdata *conn,
   1338                      const Curl_addrinfo *ai,
   1339                      struct Curl_sockaddr_ex *addr,
   1340                      curl_socket_t *sockfd)
   1341 {
   1342   struct Curl_easy *data = conn->data;
   1343   struct Curl_sockaddr_ex dummy;
   1344 
   1345   if(!addr)
   1346     /* if the caller doesn't want info back, use a local temp copy */
   1347     addr = &dummy;
   1348 
   1349   /*
   1350    * The Curl_sockaddr_ex structure is basically libcurl's external API
   1351    * curl_sockaddr structure with enough space available to directly hold
   1352    * any protocol-specific address structures. The variable declared here
   1353    * will be used to pass / receive data to/from the fopensocket callback
   1354    * if this has been set, before that, it is initialized from parameters.
   1355    */
   1356 
   1357   addr->family = ai->ai_family;
   1358   addr->socktype = conn->socktype;
   1359   addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
   1360   addr->addrlen = ai->ai_addrlen;
   1361 
   1362   if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
   1363      addr->addrlen = sizeof(struct Curl_sockaddr_storage);
   1364   memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
   1365 
   1366   if(data->set.fopensocket)
   1367    /*
   1368     * If the opensocket callback is set, all the destination address
   1369     * information is passed to the callback. Depending on this information the
   1370     * callback may opt to abort the connection, this is indicated returning
   1371     * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
   1372     * the callback returns a valid socket the destination address information
   1373     * might have been changed and this 'new' address will actually be used
   1374     * here to connect.
   1375     */
   1376     *sockfd = data->set.fopensocket(data->set.opensocket_client,
   1377                                     CURLSOCKTYPE_IPCXN,
   1378                                     (struct curl_sockaddr *)addr);
   1379   else
   1380     /* opensocket callback not set, so simply create the socket now */
   1381     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
   1382 
   1383   if(*sockfd == CURL_SOCKET_BAD)
   1384     /* no socket, no connection */
   1385     return CURLE_COULDNT_CONNECT;
   1386 
   1387 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
   1388   if(conn->scope_id && (addr->family == AF_INET6)) {
   1389     struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
   1390     sa6->sin6_scope_id = conn->scope_id;
   1391   }
   1392 #endif
   1393 
   1394   return CURLE_OK;
   1395 
   1396 }
   1397 
   1398 /*
   1399  * Curl_conncontrol() marks streams or connection for closure.
   1400  */
   1401 void Curl_conncontrol(struct connectdata *conn,
   1402                       int ctrl /* see defines in header */
   1403 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   1404                       , const char *reason
   1405 #endif
   1406   )
   1407 {
   1408   /* close if a connection, or a stream that isn't multiplexed */
   1409   bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
   1410     ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
   1411   if((ctrl == CONNCTRL_STREAM) &&
   1412      (conn->handler->flags & PROTOPT_STREAM))
   1413     DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
   1414   else if(closeit != conn->bits.close) {
   1415     DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
   1416                  closeit?"closure":"keep alive", reason));
   1417     conn->bits.close = closeit; /* the only place in the source code that
   1418                                    should assign this bit */
   1419   }
   1420 }
   1421 
   1422 /* Data received can be cached at various levels, so check them all here. */
   1423 bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
   1424 {
   1425   int readable;
   1426 
   1427   if(Curl_ssl_data_pending(conn, sockindex) ||
   1428      Curl_recv_has_postponed_data(conn, sockindex))
   1429     return true;
   1430 
   1431   readable = SOCKET_READABLE(conn->sock[sockindex], 0);
   1432   return (readable > 0 && (readable & CURL_CSELECT_IN));
   1433 }
   1434