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