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