connect.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #ifdef HAVE_NETINET_IN_H
00026 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
00027 #endif
00028 #ifdef HAVE_SYS_UN_H
00029 #include <sys/un.h> /* for sockaddr_un */
00030 #endif
00031 #ifdef HAVE_NETINET_TCP_H
00032 #include <netinet/tcp.h> /* for TCP_NODELAY */
00033 #endif
00034 #ifdef HAVE_SYS_IOCTL_H
00035 #include <sys/ioctl.h>
00036 #endif
00037 #ifdef HAVE_NETDB_H
00038 #include <netdb.h>
00039 #endif
00040 #ifdef HAVE_FCNTL_H
00041 #include <fcntl.h>
00042 #endif
00043 #ifdef HAVE_ARPA_INET_H
00044 #include <arpa/inet.h>
00045 #endif
00046 
00047 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
00048 #include <sys/filio.h>
00049 #endif
00050 #ifdef NETWARE
00051 #undef in_addr_t
00052 #define in_addr_t unsigned long
00053 #endif
00054 #ifdef __VMS
00055 #include <in.h>
00056 #include <inet.h>
00057 #endif
00058 
00059 #include "urldata.h"
00060 #include "sendf.h"
00061 #include "if2ip.h"
00062 #include "strerror.h"
00063 #include "connect.h"
00064 #include "select.h"
00065 #include "url.h" /* for Curl_safefree() */
00066 #include "multiif.h"
00067 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
00068 #include "inet_ntop.h"
00069 #include "inet_pton.h"
00070 #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */
00071 #include "progress.h"
00072 #include "warnless.h"
00073 #include "conncache.h"
00074 #include "multihandle.h"
00075 #include "system_win32.h"
00076 
00077 /* The last 3 #include files should be in this order */
00078 #include "curl_printf.h"
00079 #include "curl_memory.h"
00080 #include "memdebug.h"
00081 
00082 #ifdef __SYMBIAN32__
00083 /* This isn't actually supported under Symbian OS */
00084 #undef SO_NOSIGPIPE
00085 #endif
00086 
00087 static bool verifyconnect(curl_socket_t sockfd, int *error);
00088 
00089 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
00090 /* DragonFlyBSD and Windows use millisecond units */
00091 #define KEEPALIVE_FACTOR(x) (x *= 1000)
00092 #else
00093 #define KEEPALIVE_FACTOR(x)
00094 #endif
00095 
00096 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
00097 #define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
00098 
00099 struct tcp_keepalive {
00100   u_long onoff;
00101   u_long keepalivetime;
00102   u_long keepaliveinterval;
00103 };
00104 #endif
00105 
00106 static void
00107 tcpkeepalive(struct Curl_easy *data,
00108              curl_socket_t sockfd)
00109 {
00110   int optval = data->set.tcp_keepalive?1:0;
00111 
00112   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
00113   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
00114         (void *)&optval, sizeof(optval)) < 0) {
00115     infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
00116   }
00117   else {
00118 #if defined(SIO_KEEPALIVE_VALS)
00119     struct tcp_keepalive vals;
00120     DWORD dummy;
00121     vals.onoff = 1;
00122     optval = curlx_sltosi(data->set.tcp_keepidle);
00123     KEEPALIVE_FACTOR(optval);
00124     vals.keepalivetime = optval;
00125     optval = curlx_sltosi(data->set.tcp_keepintvl);
00126     KEEPALIVE_FACTOR(optval);
00127     vals.keepaliveinterval = optval;
00128     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
00129                 NULL, 0, &dummy, NULL, NULL) != 0) {
00130       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
00131             (int)sockfd, WSAGetLastError());
00132     }
00133 #else
00134 #ifdef TCP_KEEPIDLE
00135     optval = curlx_sltosi(data->set.tcp_keepidle);
00136     KEEPALIVE_FACTOR(optval);
00137     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
00138           (void *)&optval, sizeof(optval)) < 0) {
00139       infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
00140     }
00141 #endif
00142 #ifdef TCP_KEEPINTVL
00143     optval = curlx_sltosi(data->set.tcp_keepintvl);
00144     KEEPALIVE_FACTOR(optval);
00145     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
00146           (void *)&optval, sizeof(optval)) < 0) {
00147       infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
00148     }
00149 #endif
00150 #ifdef TCP_KEEPALIVE
00151     /* Mac OS X style */
00152     optval = curlx_sltosi(data->set.tcp_keepidle);
00153     KEEPALIVE_FACTOR(optval);
00154     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
00155           (void *)&optval, sizeof(optval)) < 0) {
00156       infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
00157     }
00158 #endif
00159 #endif
00160   }
00161 }
00162 
00163 static CURLcode
00164 singleipconnect(struct connectdata *conn,
00165                 const Curl_addrinfo *ai, /* start connecting to this */
00166                 curl_socket_t *sock);
00167 
00168 /*
00169  * Curl_timeleft() returns the amount of milliseconds left allowed for the
00170  * transfer/connection. If the value is negative, the timeout time has already
00171  * elapsed.
00172  *
00173  * The start time is stored in progress.t_startsingle - as set with
00174  * Curl_pgrsTime(..., TIMER_STARTSINGLE);
00175  *
00176  * If 'nowp' is non-NULL, it points to the current time.
00177  * 'duringconnect' is FALSE if not during a connect, as then of course the
00178  * connect timeout is not taken into account!
00179  *
00180  * @unittest: 1303
00181  */
00182 time_t Curl_timeleft(struct Curl_easy *data,
00183                      struct timeval *nowp,
00184                      bool duringconnect)
00185 {
00186   int timeout_set = 0;
00187   time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
00188   struct timeval now;
00189 
00190   /* if a timeout is set, use the most restrictive one */
00191 
00192   if(data->set.timeout > 0)
00193     timeout_set |= 1;
00194   if(duringconnect && (data->set.connecttimeout > 0))
00195     timeout_set |= 2;
00196 
00197   switch(timeout_set) {
00198   case 1:
00199     timeout_ms = data->set.timeout;
00200     break;
00201   case 2:
00202     timeout_ms = data->set.connecttimeout;
00203     break;
00204   case 3:
00205     if(data->set.timeout < data->set.connecttimeout)
00206       timeout_ms = data->set.timeout;
00207     else
00208       timeout_ms = data->set.connecttimeout;
00209     break;
00210   default:
00211     /* use the default */
00212     if(!duringconnect)
00213       /* if we're not during connect, there's no default timeout so if we're
00214          at zero we better just return zero and not make it a negative number
00215          by the math below */
00216       return 0;
00217     break;
00218   }
00219 
00220   if(!nowp) {
00221     now = Curl_tvnow();
00222     nowp = &now;
00223   }
00224 
00225   /* subtract elapsed time */
00226   if(duringconnect)
00227     /* since this most recent connect started */
00228     timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
00229   else
00230     /* since the entire operation started */
00231     timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop);
00232   if(!timeout_ms)
00233     /* avoid returning 0 as that means no timeout! */
00234     return -1;
00235 
00236   return timeout_ms;
00237 }
00238 
00239 static CURLcode bindlocal(struct connectdata *conn,
00240                           curl_socket_t sockfd, int af, unsigned int scope)
00241 {
00242   struct Curl_easy *data = conn->data;
00243 
00244   struct Curl_sockaddr_storage sa;
00245   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
00246   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
00247   struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
00248 #ifdef ENABLE_IPV6
00249   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
00250 #endif
00251 
00252   struct Curl_dns_entry *h=NULL;
00253   unsigned short port = data->set.localport; /* use this port number, 0 for
00254                                                 "random" */
00255   /* how many port numbers to try to bind to, increasing one at a time */
00256   int portnum = data->set.localportrange;
00257   const char *dev = data->set.str[STRING_DEVICE];
00258   int error;
00259 
00260   /*************************************************************
00261    * Select device to bind socket to
00262    *************************************************************/
00263   if(!dev && !port)
00264     /* no local kind of binding was requested */
00265     return CURLE_OK;
00266 
00267   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
00268 
00269   if(dev && (strlen(dev)<255) ) {
00270     char myhost[256] = "";
00271     int done = 0; /* -1 for error, 1 for address found */
00272     bool is_interface = FALSE;
00273     bool is_host = FALSE;
00274     static const char *if_prefix = "if!";
00275     static const char *host_prefix = "host!";
00276 
00277     if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
00278       dev += strlen(if_prefix);
00279       is_interface = TRUE;
00280     }
00281     else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
00282       dev += strlen(host_prefix);
00283       is_host = TRUE;
00284     }
00285 
00286     /* interface */
00287     if(!is_host) {
00288       switch(Curl_if2ip(af, scope, conn->scope_id, dev,
00289                         myhost, sizeof(myhost))) {
00290         case IF2IP_NOT_FOUND:
00291           if(is_interface) {
00292             /* Do not fall back to treating it as a host name */
00293             failf(data, "Couldn't bind to interface '%s'", dev);
00294             return CURLE_INTERFACE_FAILED;
00295           }
00296           break;
00297         case IF2IP_AF_NOT_SUPPORTED:
00298           /* Signal the caller to try another address family if available */
00299           return CURLE_UNSUPPORTED_PROTOCOL;
00300         case IF2IP_FOUND:
00301           is_interface = TRUE;
00302           /*
00303            * We now have the numerical IP address in the 'myhost' buffer
00304            */
00305           infof(data, "Local Interface %s is ip %s using address family %i\n",
00306                 dev, myhost, af);
00307           done = 1;
00308 
00309 #ifdef SO_BINDTODEVICE
00310           /* I am not sure any other OSs than Linux that provide this feature,
00311            * and at the least I cannot test. --Ben
00312            *
00313            * This feature allows one to tightly bind the local socket to a
00314            * particular interface.  This will force even requests to other
00315            * local interfaces to go out the external interface.
00316            *
00317            *
00318            * Only bind to the interface when specified as interface, not just
00319            * as a hostname or ip address.
00320            */
00321           if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
00322                         dev, (curl_socklen_t)strlen(dev)+1) != 0) {
00323             error = SOCKERRNO;
00324             infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
00325                   " will do regular bind\n",
00326                   dev, error, Curl_strerror(conn, error));
00327             /* This is typically "errno 1, error: Operation not permitted" if
00328                you're not running as root or another suitable privileged
00329                user */
00330           }
00331 #endif
00332           break;
00333       }
00334     }
00335     if(!is_interface) {
00336       /*
00337        * This was not an interface, resolve the name as a host name
00338        * or IP number
00339        *
00340        * Temporarily force name resolution to use only the address type
00341        * of the connection. The resolve functions should really be changed
00342        * to take a type parameter instead.
00343        */
00344       long ipver = conn->ip_version;
00345       int rc;
00346 
00347       if(af == AF_INET)
00348         conn->ip_version = CURL_IPRESOLVE_V4;
00349 #ifdef ENABLE_IPV6
00350       else if(af == AF_INET6)
00351         conn->ip_version = CURL_IPRESOLVE_V6;
00352 #endif
00353 
00354       rc = Curl_resolv(conn, dev, 0, &h);
00355       if(rc == CURLRESOLV_PENDING)
00356         (void)Curl_resolver_wait_resolv(conn, &h);
00357       conn->ip_version = ipver;
00358 
00359       if(h) {
00360         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
00361         Curl_printable_address(h->addr, myhost, sizeof(myhost));
00362         infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
00363               dev, af, myhost, h->addr->ai_family);
00364         Curl_resolv_unlock(data, h);
00365         done = 1;
00366       }
00367       else {
00368         /*
00369          * provided dev was no interface (or interfaces are not supported
00370          * e.g. solaris) no ip address and no domain we fail here
00371          */
00372         done = -1;
00373       }
00374     }
00375 
00376     if(done > 0) {
00377 #ifdef ENABLE_IPV6
00378       /* IPv6 address */
00379       if(af == AF_INET6) {
00380 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
00381         char *scope_ptr = strchr(myhost, '%');
00382         if(scope_ptr)
00383           *(scope_ptr++) = 0;
00384 #endif
00385         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
00386           si6->sin6_family = AF_INET6;
00387           si6->sin6_port = htons(port);
00388 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
00389           if(scope_ptr)
00390             /* The "myhost" string either comes from Curl_if2ip or from
00391                Curl_printable_address. The latter returns only numeric scope
00392                IDs and the former returns none at all.  So the scope ID, if
00393                present, is known to be numeric */
00394             si6->sin6_scope_id = atoi(scope_ptr);
00395 #endif
00396         }
00397         sizeof_sa = sizeof(struct sockaddr_in6);
00398       }
00399       else
00400 #endif
00401       /* IPv4 address */
00402       if((af == AF_INET) &&
00403          (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
00404         si4->sin_family = AF_INET;
00405         si4->sin_port = htons(port);
00406         sizeof_sa = sizeof(struct sockaddr_in);
00407       }
00408     }
00409 
00410     if(done < 1) {
00411       failf(data, "Couldn't bind to '%s'", dev);
00412       return CURLE_INTERFACE_FAILED;
00413     }
00414   }
00415   else {
00416     /* no device was given, prepare sa to match af's needs */
00417 #ifdef ENABLE_IPV6
00418     if(af == AF_INET6) {
00419       si6->sin6_family = AF_INET6;
00420       si6->sin6_port = htons(port);
00421       sizeof_sa = sizeof(struct sockaddr_in6);
00422     }
00423     else
00424 #endif
00425     if(af == AF_INET) {
00426       si4->sin_family = AF_INET;
00427       si4->sin_port = htons(port);
00428       sizeof_sa = sizeof(struct sockaddr_in);
00429     }
00430   }
00431 
00432   for(;;) {
00433     if(bind(sockfd, sock, sizeof_sa) >= 0) {
00434       /* we succeeded to bind */
00435       struct Curl_sockaddr_storage add;
00436       curl_socklen_t size = sizeof(add);
00437       memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
00438       if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
00439         data->state.os_errno = error = SOCKERRNO;
00440         failf(data, "getsockname() failed with errno %d: %s",
00441               error, Curl_strerror(conn, error));
00442         return CURLE_INTERFACE_FAILED;
00443       }
00444       infof(data, "Local port: %hu\n", port);
00445       conn->bits.bound = TRUE;
00446       return CURLE_OK;
00447     }
00448 
00449     if(--portnum > 0) {
00450       infof(data, "Bind to local port %hu failed, trying next\n", port);
00451       port++; /* try next port */
00452       /* We re-use/clobber the port variable here below */
00453       if(sock->sa_family == AF_INET)
00454         si4->sin_port = ntohs(port);
00455 #ifdef ENABLE_IPV6
00456       else
00457         si6->sin6_port = ntohs(port);
00458 #endif
00459     }
00460     else
00461       break;
00462   }
00463 
00464   data->state.os_errno = error = SOCKERRNO;
00465   failf(data, "bind failed with errno %d: %s",
00466         error, Curl_strerror(conn, error));
00467 
00468   return CURLE_INTERFACE_FAILED;
00469 }
00470 
00471 /*
00472  * verifyconnect() returns TRUE if the connect really has happened.
00473  */
00474 static bool verifyconnect(curl_socket_t sockfd, int *error)
00475 {
00476   bool rc = TRUE;
00477 #ifdef SO_ERROR
00478   int err = 0;
00479   curl_socklen_t errSize = sizeof(err);
00480 
00481 #ifdef WIN32
00482   /*
00483    * In October 2003 we effectively nullified this function on Windows due to
00484    * problems with it using all CPU in multi-threaded cases.
00485    *
00486    * In May 2004, we bring it back to offer more info back on connect failures.
00487    * Gisle Vanem could reproduce the former problems with this function, but
00488    * could avoid them by adding this SleepEx() call below:
00489    *
00490    *    "I don't have Rational Quantify, but the hint from his post was
00491    *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
00492    *    just Sleep(0) would be enough?) would release whatever
00493    *    mutex/critical-section the ntdll call is waiting on.
00494    *
00495    *    Someone got to verify this on Win-NT 4.0, 2000."
00496    */
00497 
00498 #ifdef _WIN32_WCE
00499   Sleep(0);
00500 #else
00501   SleepEx(0, FALSE);
00502 #endif
00503 
00504 #endif
00505 
00506   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
00507     err = SOCKERRNO;
00508 #ifdef _WIN32_WCE
00509   /* Old WinCE versions don't support SO_ERROR */
00510   if(WSAENOPROTOOPT == err) {
00511     SET_SOCKERRNO(0);
00512     err = 0;
00513   }
00514 #endif
00515 #ifdef __minix
00516   /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
00517   if(EBADIOCTL == err) {
00518     SET_SOCKERRNO(0);
00519     err = 0;
00520   }
00521 #endif
00522   if((0 == err) || (EISCONN == err))
00523     /* we are connected, awesome! */
00524     rc = TRUE;
00525   else
00526     /* This wasn't a successful connect */
00527     rc = FALSE;
00528   if(error)
00529     *error = err;
00530 #else
00531   (void)sockfd;
00532   if(error)
00533     *error = SOCKERRNO;
00534 #endif
00535   return rc;
00536 }
00537 
00538 /* Used within the multi interface. Try next IP address, return TRUE if no
00539    more address exists or error */
00540 static CURLcode trynextip(struct connectdata *conn,
00541                           int sockindex,
00542                           int tempindex)
00543 {
00544   const int other = tempindex ^ 1;
00545   CURLcode result = CURLE_COULDNT_CONNECT;
00546 
00547   /* First clean up after the failed socket.
00548      Don't close it yet to ensure that the next IP's socket gets a different
00549      file descriptor, which can prevent bugs when the curl_multi_socket_action
00550      interface is used with certain select() replacements such as kqueue. */
00551   curl_socket_t fd_to_close = conn->tempsock[tempindex];
00552   conn->tempsock[tempindex] = CURL_SOCKET_BAD;
00553 
00554   if(sockindex == FIRSTSOCKET) {
00555     Curl_addrinfo *ai = NULL;
00556     int family = AF_UNSPEC;
00557 
00558     if(conn->tempaddr[tempindex]) {
00559       /* find next address in the same protocol family */
00560       family = conn->tempaddr[tempindex]->ai_family;
00561       ai = conn->tempaddr[tempindex]->ai_next;
00562     }
00563 #ifdef ENABLE_IPV6
00564     else if(conn->tempaddr[0]) {
00565       /* happy eyeballs - try the other protocol family */
00566       int firstfamily = conn->tempaddr[0]->ai_family;
00567       family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET;
00568       ai = conn->tempaddr[0]->ai_next;
00569     }
00570 #endif
00571 
00572     while(ai) {
00573       if(conn->tempaddr[other]) {
00574         /* we can safely skip addresses of the other protocol family */
00575         while(ai && ai->ai_family != family)
00576           ai = ai->ai_next;
00577       }
00578 
00579       if(ai) {
00580         result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
00581         if(result == CURLE_COULDNT_CONNECT) {
00582           ai = ai->ai_next;
00583           continue;
00584         }
00585 
00586         conn->tempaddr[tempindex] = ai;
00587       }
00588       break;
00589     }
00590   }
00591 
00592   if(fd_to_close != CURL_SOCKET_BAD)
00593     Curl_closesocket(conn, fd_to_close);
00594 
00595   return result;
00596 }
00597 
00598 /* Copies connection info into the session handle to make it available
00599    when the session handle is no longer associated with a connection. */
00600 void Curl_persistconninfo(struct connectdata *conn)
00601 {
00602   memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
00603   memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
00604   conn->data->info.conn_scheme = conn->handler->scheme;
00605   conn->data->info.conn_protocol = conn->handler->protocol;
00606   conn->data->info.conn_primary_port = conn->primary_port;
00607   conn->data->info.conn_local_port = conn->local_port;
00608 }
00609 
00610 /* retrieves ip address and port from a sockaddr structure */
00611 static bool getaddressinfo(struct sockaddr *sa, char *addr,
00612                            long *port)
00613 {
00614   unsigned short us_port;
00615   struct sockaddr_in *si = NULL;
00616 #ifdef ENABLE_IPV6
00617   struct sockaddr_in6 *si6 = NULL;
00618 #endif
00619 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
00620   struct sockaddr_un *su = NULL;
00621 #endif
00622 
00623   switch(sa->sa_family) {
00624     case AF_INET:
00625       si = (struct sockaddr_in *)(void *) sa;
00626       if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
00627                         addr, MAX_IPADR_LEN)) {
00628         us_port = ntohs(si->sin_port);
00629         *port = us_port;
00630         return TRUE;
00631       }
00632       break;
00633 #ifdef ENABLE_IPV6
00634     case AF_INET6:
00635       si6 = (struct sockaddr_in6 *)(void *) sa;
00636       if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
00637                         addr, MAX_IPADR_LEN)) {
00638         us_port = ntohs(si6->sin6_port);
00639         *port = us_port;
00640         return TRUE;
00641       }
00642       break;
00643 #endif
00644 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
00645     case AF_UNIX:
00646       su = (struct sockaddr_un*)sa;
00647       snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
00648       *port = 0;
00649       return TRUE;
00650 #endif
00651     default:
00652       break;
00653   }
00654 
00655   addr[0] = '\0';
00656   *port = 0;
00657 
00658   return FALSE;
00659 }
00660 
00661 /* retrieves the start/end point information of a socket of an established
00662    connection */
00663 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
00664 {
00665   curl_socklen_t len;
00666   struct Curl_sockaddr_storage ssrem;
00667   struct Curl_sockaddr_storage ssloc;
00668   struct Curl_easy *data = conn->data;
00669 
00670   if(conn->socktype == SOCK_DGRAM)
00671     /* there's no connection! */
00672     return;
00673 
00674   if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
00675     int error;
00676 
00677     len = sizeof(struct Curl_sockaddr_storage);
00678     if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
00679       error = SOCKERRNO;
00680       failf(data, "getpeername() failed with errno %d: %s",
00681             error, Curl_strerror(conn, error));
00682       return;
00683     }
00684 
00685     len = sizeof(struct Curl_sockaddr_storage);
00686     memset(&ssloc, 0, sizeof(ssloc));
00687     if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
00688       error = SOCKERRNO;
00689       failf(data, "getsockname() failed with errno %d: %s",
00690             error, Curl_strerror(conn, error));
00691       return;
00692     }
00693 
00694     if(!getaddressinfo((struct sockaddr*)&ssrem,
00695                         conn->primary_ip, &conn->primary_port)) {
00696       error = ERRNO;
00697       failf(data, "ssrem inet_ntop() failed with errno %d: %s",
00698             error, Curl_strerror(conn, error));
00699       return;
00700     }
00701     memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
00702 
00703     if(!getaddressinfo((struct sockaddr*)&ssloc,
00704                        conn->local_ip, &conn->local_port)) {
00705       error = ERRNO;
00706       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
00707             error, Curl_strerror(conn, error));
00708       return;
00709     }
00710 
00711   }
00712 
00713   /* persist connection info in session handle */
00714   Curl_persistconninfo(conn);
00715 }
00716 
00717 /*
00718  * Curl_is_connected() checks if the socket has connected.
00719  */
00720 
00721 CURLcode Curl_is_connected(struct connectdata *conn,
00722                            int sockindex,
00723                            bool *connected)
00724 {
00725   struct Curl_easy *data = conn->data;
00726   CURLcode result = CURLE_OK;
00727   time_t allow;
00728   int error = 0;
00729   struct timeval now;
00730   int rc;
00731   int i;
00732 
00733   DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
00734 
00735   *connected = FALSE; /* a very negative world view is best */
00736 
00737   if(conn->bits.tcpconnect[sockindex]) {
00738     /* we are connected already! */
00739     *connected = TRUE;
00740     return CURLE_OK;
00741   }
00742 
00743   now = Curl_tvnow();
00744 
00745   /* figure out how long time we have left to connect */
00746   allow = Curl_timeleft(data, &now, TRUE);
00747 
00748   if(allow < 0) {
00749     /* time-out, bail out, go home */
00750     failf(data, "Connection time-out");
00751     return CURLE_OPERATION_TIMEDOUT;
00752   }
00753 
00754   for(i=0; i<2; i++) {
00755     const int other = i ^ 1;
00756     if(conn->tempsock[i] == CURL_SOCKET_BAD)
00757       continue;
00758 
00759 #ifdef mpeix
00760     /* Call this function once now, and ignore the results. We do this to
00761        "clear" the error state on the socket so that we can later read it
00762        reliably. This is reported necessary on the MPE/iX operating system. */
00763     (void)verifyconnect(conn->tempsock[i], NULL);
00764 #endif
00765 
00766     /* check socket for connect */
00767     rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
00768 
00769     if(rc == 0) { /* no connection yet */
00770       error = 0;
00771       if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
00772         infof(data, "After %ldms connect time, move on!\n",
00773               conn->timeoutms_per_addr);
00774         error = ETIMEDOUT;
00775       }
00776 
00777       /* should we try another protocol family? */
00778       if(i == 0 && conn->tempaddr[1] == NULL &&
00779          curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
00780         trynextip(conn, sockindex, 1);
00781       }
00782     }
00783     else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
00784       if(verifyconnect(conn->tempsock[i], &error)) {
00785         /* we are connected with TCP, awesome! */
00786 
00787         /* use this socket from now on */
00788         conn->sock[sockindex] = conn->tempsock[i];
00789         conn->ip_addr = conn->tempaddr[i];
00790         conn->tempsock[i] = CURL_SOCKET_BAD;
00791 
00792         /* close the other socket, if open */
00793         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
00794           Curl_closesocket(conn, conn->tempsock[other]);
00795           conn->tempsock[other] = CURL_SOCKET_BAD;
00796         }
00797 
00798         /* see if we need to do any proxy magic first once we connected */
00799         result = Curl_connected_proxy(conn, sockindex);
00800         if(result)
00801           return result;
00802 
00803         conn->bits.tcpconnect[sockindex] = TRUE;
00804 
00805         *connected = TRUE;
00806         if(sockindex == FIRSTSOCKET)
00807           Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
00808         Curl_updateconninfo(conn, conn->sock[sockindex]);
00809         Curl_verboseconnect(conn);
00810 
00811         return CURLE_OK;
00812       }
00813       else
00814         infof(data, "Connection failed\n");
00815     }
00816     else if(rc & CURL_CSELECT_ERR)
00817       (void)verifyconnect(conn->tempsock[i], &error);
00818 
00819     /*
00820      * The connection failed here, we should attempt to connect to the "next
00821      * address" for the given host. But first remember the latest error.
00822      */
00823     if(error) {
00824       data->state.os_errno = error;
00825       SET_SOCKERRNO(error);
00826       if(conn->tempaddr[i]) {
00827         CURLcode status;
00828         char ipaddress[MAX_IPADR_LEN];
00829         Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
00830         infof(data, "connect to %s port %ld failed: %s\n",
00831               ipaddress, conn->port, Curl_strerror(conn, error));
00832 
00833         conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
00834                                    allow : allow / 2;
00835 
00836         status = trynextip(conn, sockindex, i);
00837         if(status != CURLE_COULDNT_CONNECT
00838             || conn->tempsock[other] == CURL_SOCKET_BAD)
00839           /* the last attempt failed and no other sockets remain open */
00840           result = status;
00841       }
00842     }
00843   }
00844 
00845   if(result) {
00846     /* no more addresses to try */
00847 
00848     const char *hostname;
00849 
00850     /* if the first address family runs out of addresses to try before
00851        the happy eyeball timeout, go ahead and try the next family now */
00852     if(conn->tempaddr[1] == NULL) {
00853       result = trynextip(conn, sockindex, 1);
00854       if(!result)
00855         return result;
00856     }
00857 
00858     if(conn->bits.socksproxy)
00859       hostname = conn->socks_proxy.host.name;
00860     else if(conn->bits.httpproxy)
00861       hostname = conn->http_proxy.host.name;
00862     else if(conn->bits.conn_to_host)
00863       hostname = conn->conn_to_host.name;
00864     else
00865       hostname = conn->host.name;
00866 
00867     failf(data, "Failed to connect to %s port %ld: %s",
00868         hostname, conn->port, Curl_strerror(conn, error));
00869   }
00870 
00871   return result;
00872 }
00873 
00874 void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
00875 {
00876 #if defined(TCP_NODELAY)
00877 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
00878   struct Curl_easy *data = conn->data;
00879 #endif
00880   curl_socklen_t onoff = (curl_socklen_t) 1;
00881   int level = IPPROTO_TCP;
00882 
00883 #if 0
00884   /* The use of getprotobyname() is disabled since it isn't thread-safe on
00885      numerous systems. On these getprotobyname_r() should be used instead, but
00886      that exists in at least one 4 arg version and one 5 arg version, and
00887      since the proto number rarely changes anyway we now just use the hard
00888      coded number. The "proper" fix would need a configure check for the
00889      correct function much in the same style the gethostbyname_r versions are
00890      detected. */
00891   struct protoent *pe = getprotobyname("tcp");
00892   if(pe)
00893     level = pe->p_proto;
00894 #endif
00895 
00896 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
00897   (void) conn;
00898 #endif
00899 
00900   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
00901                 sizeof(onoff)) < 0)
00902     infof(data, "Could not set TCP_NODELAY: %s\n",
00903           Curl_strerror(conn, SOCKERRNO));
00904   else
00905     infof(data, "TCP_NODELAY set\n");
00906 #else
00907   (void)conn;
00908   (void)sockfd;
00909 #endif
00910 }
00911 
00912 #ifdef SO_NOSIGPIPE
00913 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
00914    sending data to a dead peer (instead of relying on the 4th argument to send
00915    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
00916    systems? */
00917 static void nosigpipe(struct connectdata *conn,
00918                       curl_socket_t sockfd)
00919 {
00920   struct Curl_easy *data= conn->data;
00921   int onoff = 1;
00922   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
00923                 sizeof(onoff)) < 0)
00924     infof(data, "Could not set SO_NOSIGPIPE: %s\n",
00925           Curl_strerror(conn, SOCKERRNO));
00926 }
00927 #else
00928 #define nosigpipe(x,y) Curl_nop_stmt
00929 #endif
00930 
00931 #ifdef USE_WINSOCK
00932 /* When you run a program that uses the Windows Sockets API, you may
00933    experience slow performance when you copy data to a TCP server.
00934 
00935    https://support.microsoft.com/kb/823764
00936 
00937    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
00938    Buffer Size
00939 
00940    The problem described in this knowledge-base is applied only to pre-Vista
00941    Windows.  Following function trying to detect OS version and skips
00942    SO_SNDBUF adjustment for Windows Vista and above.
00943 */
00944 #define DETECT_OS_NONE 0
00945 #define DETECT_OS_PREVISTA 1
00946 #define DETECT_OS_VISTA_OR_LATER 2
00947 
00948 void Curl_sndbufset(curl_socket_t sockfd)
00949 {
00950   int val = CURL_MAX_WRITE_SIZE + 32;
00951   int curval = 0;
00952   int curlen = sizeof(curval);
00953 
00954   static int detectOsState = DETECT_OS_NONE;
00955 
00956   if(detectOsState == DETECT_OS_NONE) {
00957     if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
00958                                    VERSION_GREATER_THAN_EQUAL))
00959       detectOsState = DETECT_OS_VISTA_OR_LATER;
00960     else
00961       detectOsState = DETECT_OS_PREVISTA;
00962   }
00963 
00964   if(detectOsState == DETECT_OS_VISTA_OR_LATER)
00965     return;
00966 
00967   if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
00968     if(curval > val)
00969       return;
00970 
00971   setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
00972 }
00973 #endif
00974 
00975 /*
00976  * singleipconnect()
00977  *
00978  * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
00979  * CURL_SOCKET_BAD. Other errors will however return proper errors.
00980  *
00981  * singleipconnect() connects to the given IP only, and it may return without
00982  * having connected.
00983  */
00984 static CURLcode singleipconnect(struct connectdata *conn,
00985                                 const Curl_addrinfo *ai,
00986                                 curl_socket_t *sockp)
00987 {
00988   struct Curl_sockaddr_ex addr;
00989   int rc = -1;
00990   int error = 0;
00991   bool isconnected = FALSE;
00992   struct Curl_easy *data = conn->data;
00993   curl_socket_t sockfd;
00994   CURLcode result;
00995   char ipaddress[MAX_IPADR_LEN];
00996   long port;
00997   bool is_tcp;
00998 
00999   *sockp = CURL_SOCKET_BAD;
01000 
01001   result = Curl_socket(conn, ai, &addr, &sockfd);
01002   if(result)
01003     /* Failed to create the socket, but still return OK since we signal the
01004        lack of socket as well. This allows the parent function to keep looping
01005        over alternative addresses/socket families etc. */
01006     return CURLE_OK;
01007 
01008   /* store remote address and port used in this connection attempt */
01009   if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
01010                      ipaddress, &port)) {
01011     /* malformed address or bug in inet_ntop, try next address */
01012     error = ERRNO;
01013     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
01014           error, Curl_strerror(conn, error));
01015     Curl_closesocket(conn, sockfd);
01016     return CURLE_OK;
01017   }
01018   infof(data, "  Trying %s...\n", ipaddress);
01019 
01020 #ifdef ENABLE_IPV6
01021   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
01022     addr.socktype == SOCK_STREAM;
01023 #else
01024   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
01025 #endif
01026   if(is_tcp && data->set.tcp_nodelay)
01027     Curl_tcpnodelay(conn, sockfd);
01028 
01029   nosigpipe(conn, sockfd);
01030 
01031   Curl_sndbufset(sockfd);
01032 
01033   if(is_tcp && data->set.tcp_keepalive)
01034     tcpkeepalive(data, sockfd);
01035 
01036   if(data->set.fsockopt) {
01037     /* activate callback for setting socket options */
01038     error = data->set.fsockopt(data->set.sockopt_client,
01039                                sockfd,
01040                                CURLSOCKTYPE_IPCXN);
01041 
01042     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
01043       isconnected = TRUE;
01044     else if(error) {
01045       Curl_closesocket(conn, sockfd); /* close the socket and bail out */
01046       return CURLE_ABORTED_BY_CALLBACK;
01047     }
01048   }
01049 
01050   /* possibly bind the local end to an IP, interface or port */
01051   if(addr.family == AF_INET
01052 #ifdef ENABLE_IPV6
01053      || addr.family == AF_INET6
01054 #endif
01055     ) {
01056     result = bindlocal(conn, sockfd, addr.family,
01057                        Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
01058     if(result) {
01059       Curl_closesocket(conn, sockfd); /* close socket and bail out */
01060       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
01061         /* The address family is not supported on this interface.
01062            We can continue trying addresses */
01063         return CURLE_COULDNT_CONNECT;
01064       }
01065       return result;
01066     }
01067   }
01068 
01069   /* set socket non-blocking */
01070   (void)curlx_nonblock(sockfd, TRUE);
01071 
01072   conn->connecttime = Curl_tvnow();
01073   if(conn->num_addr > 1)
01074     Curl_expire_latest(data, conn->timeoutms_per_addr);
01075 
01076   /* Connect TCP sockets, bind UDP */
01077   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
01078     if(conn->bits.tcp_fastopen) {
01079 #if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
01080       sa_endpoints_t endpoints;
01081       endpoints.sae_srcif = 0;
01082       endpoints.sae_srcaddr = NULL;
01083       endpoints.sae_srcaddrlen = 0;
01084       endpoints.sae_dstaddr = &addr.sa_addr;
01085       endpoints.sae_dstaddrlen = addr.addrlen;
01086 
01087       rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
01088                     CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
01089                     NULL, 0, NULL, NULL);
01090 #elif defined(MSG_FASTOPEN) /* Linux */
01091       if(conn->given->flags & PROTOPT_SSL)
01092         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
01093       else
01094         rc = 0; /* Do nothing */
01095 #endif
01096     }
01097     else {
01098       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
01099     }
01100 
01101     if(-1 == rc)
01102       error = SOCKERRNO;
01103   }
01104   else {
01105     *sockp = sockfd;
01106     return CURLE_OK;
01107   }
01108 
01109 #ifdef ENABLE_IPV6
01110   conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
01111 #endif
01112 
01113   if(-1 == rc) {
01114     switch(error) {
01115     case EINPROGRESS:
01116     case EWOULDBLOCK:
01117 #if defined(EAGAIN)
01118 #if (EAGAIN) != (EWOULDBLOCK)
01119       /* On some platforms EAGAIN and EWOULDBLOCK are the
01120        * same value, and on others they are different, hence
01121        * the odd #if
01122        */
01123     case EAGAIN:
01124 #endif
01125 #endif
01126       result = CURLE_OK;
01127       break;
01128 
01129     default:
01130       /* unknown error, fallthrough and try another address! */
01131       infof(data, "Immediate connect fail for %s: %s\n",
01132             ipaddress, Curl_strerror(conn, error));
01133       data->state.os_errno = error;
01134 
01135       /* connect failed */
01136       Curl_closesocket(conn, sockfd);
01137       result = CURLE_COULDNT_CONNECT;
01138     }
01139   }
01140 
01141   if(!result)
01142     *sockp = sockfd;
01143 
01144   return result;
01145 }
01146 
01147 /*
01148  * TCP connect to the given host with timeout, proxy or remote doesn't matter.
01149  * There might be more than one IP address to try out. Fill in the passed
01150  * pointer with the connected socket.
01151  */
01152 
01153 CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
01154                           const struct Curl_dns_entry *remotehost)
01155 {
01156   struct Curl_easy *data = conn->data;
01157   struct timeval before = Curl_tvnow();
01158   CURLcode result = CURLE_COULDNT_CONNECT;
01159 
01160   time_t timeout_ms = Curl_timeleft(data, &before, TRUE);
01161 
01162   if(timeout_ms < 0) {
01163     /* a precaution, no need to continue if time already is up */
01164     failf(data, "Connection time-out");
01165     return CURLE_OPERATION_TIMEDOUT;
01166   }
01167 
01168   conn->num_addr = Curl_num_addresses(remotehost->addr);
01169   conn->tempaddr[0] = remotehost->addr;
01170   conn->tempaddr[1] = NULL;
01171   conn->tempsock[0] = CURL_SOCKET_BAD;
01172   conn->tempsock[1] = CURL_SOCKET_BAD;
01173   Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT);
01174 
01175   /* Max time for the next connection attempt */
01176   conn->timeoutms_per_addr =
01177     conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
01178 
01179   /* start connecting to first IP */
01180   while(conn->tempaddr[0]) {
01181     result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
01182     if(!result)
01183       break;
01184     conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
01185   }
01186 
01187   if(conn->tempsock[0] == CURL_SOCKET_BAD) {
01188     if(!result)
01189       result = CURLE_COULDNT_CONNECT;
01190     return result;
01191   }
01192 
01193   data->info.numconnects++; /* to track the number of connections made */
01194 
01195   return CURLE_OK;
01196 }
01197 
01198 struct connfind {
01199   struct connectdata *tofind;
01200   bool found;
01201 };
01202 
01203 static int conn_is_conn(struct connectdata *conn, void *param)
01204 {
01205   struct connfind *f = (struct connfind *)param;
01206   if(conn == f->tofind) {
01207     f->found = TRUE;
01208     return 1;
01209   }
01210   return 0;
01211 }
01212 
01213 /*
01214  * Used to extract socket and connectdata struct for the most recent
01215  * transfer on the given Curl_easy.
01216  *
01217  * The returned socket will be CURL_SOCKET_BAD in case of failure!
01218  */
01219 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
01220                                   struct connectdata **connp)
01221 {
01222   curl_socket_t sockfd;
01223 
01224   DEBUGASSERT(data);
01225 
01226   /* this works for an easy handle:
01227    * - that has been used for curl_easy_perform()
01228    * - that is associated with a multi handle, and whose connection
01229    *   was detached with CURLOPT_CONNECT_ONLY
01230    */
01231   if(data->state.lastconnect && (data->multi_easy || data->multi)) {
01232     struct connectdata *c = data->state.lastconnect;
01233     struct connfind find;
01234     find.tofind = data->state.lastconnect;
01235     find.found = FALSE;
01236 
01237     Curl_conncache_foreach(data->multi_easy?
01238                            &data->multi_easy->conn_cache:
01239                            &data->multi->conn_cache, &find, conn_is_conn);
01240 
01241     if(!find.found) {
01242       data->state.lastconnect = NULL;
01243       return CURL_SOCKET_BAD;
01244     }
01245 
01246     if(connp)
01247       /* only store this if the caller cares for it */
01248       *connp = c;
01249     sockfd = c->sock[FIRSTSOCKET];
01250   }
01251   else
01252     return CURL_SOCKET_BAD;
01253 
01254   return sockfd;
01255 }
01256 
01257 /*
01258  * Check if a connection seems to be alive.
01259  */
01260 bool Curl_connalive(struct connectdata *conn)
01261 {
01262   /* First determine if ssl */
01263   if(conn->ssl[FIRSTSOCKET].use) {
01264     /* use the SSL context */
01265     if(!Curl_ssl_check_cxn(conn))
01266       return false;   /* FIN received */
01267   }
01268 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
01269 #ifdef MSG_PEEK
01270   else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD)
01271     return false;
01272   else {
01273     /* use the socket */
01274     char buf;
01275     if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
01276             (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
01277       return false;   /* FIN received */
01278     }
01279   }
01280 #endif
01281   return true;
01282 }
01283 
01284 /*
01285  * Close a socket.
01286  *
01287  * 'conn' can be NULL, beware!
01288  */
01289 int Curl_closesocket(struct connectdata *conn,
01290                       curl_socket_t sock)
01291 {
01292   if(conn && conn->fclosesocket) {
01293     if((sock == conn->sock[SECONDARYSOCKET]) &&
01294        conn->sock_accepted[SECONDARYSOCKET])
01295       /* if this socket matches the second socket, and that was created with
01296          accept, then we MUST NOT call the callback but clear the accepted
01297          status */
01298       conn->sock_accepted[SECONDARYSOCKET] = FALSE;
01299     else {
01300       Curl_multi_closed(conn, sock);
01301       return conn->fclosesocket(conn->closesocket_client, sock);
01302     }
01303   }
01304 
01305   if(conn)
01306     /* tell the multi-socket code about this */
01307     Curl_multi_closed(conn, sock);
01308 
01309   sclose(sock);
01310 
01311   return 0;
01312 }
01313 
01314 /*
01315  * Create a socket based on info from 'conn' and 'ai'.
01316  *
01317  * 'addr' should be a pointer to the correct struct to get data back, or NULL.
01318  * 'sockfd' must be a pointer to a socket descriptor.
01319  *
01320  * If the open socket callback is set, used that!
01321  *
01322  */
01323 CURLcode Curl_socket(struct connectdata *conn,
01324                      const Curl_addrinfo *ai,
01325                      struct Curl_sockaddr_ex *addr,
01326                      curl_socket_t *sockfd)
01327 {
01328   struct Curl_easy *data = conn->data;
01329   struct Curl_sockaddr_ex dummy;
01330 
01331   if(!addr)
01332     /* if the caller doesn't want info back, use a local temp copy */
01333     addr = &dummy;
01334 
01335   /*
01336    * The Curl_sockaddr_ex structure is basically libcurl's external API
01337    * curl_sockaddr structure with enough space available to directly hold
01338    * any protocol-specific address structures. The variable declared here
01339    * will be used to pass / receive data to/from the fopensocket callback
01340    * if this has been set, before that, it is initialized from parameters.
01341    */
01342 
01343   addr->family = ai->ai_family;
01344   addr->socktype = conn->socktype;
01345   addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
01346   addr->addrlen = ai->ai_addrlen;
01347 
01348   if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
01349      addr->addrlen = sizeof(struct Curl_sockaddr_storage);
01350   memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
01351 
01352   if(data->set.fopensocket)
01353    /*
01354     * If the opensocket callback is set, all the destination address
01355     * information is passed to the callback. Depending on this information the
01356     * callback may opt to abort the connection, this is indicated returning
01357     * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
01358     * the callback returns a valid socket the destination address information
01359     * might have been changed and this 'new' address will actually be used
01360     * here to connect.
01361     */
01362     *sockfd = data->set.fopensocket(data->set.opensocket_client,
01363                                     CURLSOCKTYPE_IPCXN,
01364                                     (struct curl_sockaddr *)addr);
01365   else
01366     /* opensocket callback not set, so simply create the socket now */
01367     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
01368 
01369   if(*sockfd == CURL_SOCKET_BAD)
01370     /* no socket, no connection */
01371     return CURLE_COULDNT_CONNECT;
01372 
01373 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
01374   if(conn->scope_id && (addr->family == AF_INET6)) {
01375     struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
01376     sa6->sin6_scope_id = conn->scope_id;
01377   }
01378 #endif
01379 
01380   return CURLE_OK;
01381 
01382 }
01383 
01384 /*
01385  * Curl_conncontrol() marks streams or connection for closure.
01386  */
01387 void Curl_conncontrol(struct connectdata *conn,
01388                       int ctrl /* see defines in header */
01389 #ifdef DEBUGBUILD
01390                       , const char *reason
01391 #endif
01392   )
01393 {
01394   /* close if a connection, or a stream that isn't multiplexed */
01395   bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
01396     ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
01397   if((ctrl == CONNCTRL_STREAM) &&
01398      (conn->handler->flags & PROTOPT_STREAM))
01399     DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
01400   else if(closeit != conn->bits.close) {
01401     DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
01402                  closeit?"closure":"keep alive", reason));
01403     conn->bits.close = closeit; /* the only place in the source code that
01404                                    should assign this bit */
01405   }
01406 }
01407 
01408 /* Data received can be cached at various levels, so check them all here. */
01409 bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
01410 {
01411   int readable;
01412 
01413   if(Curl_ssl_data_pending(conn, sockindex) ||
01414      Curl_recv_has_postponed_data(conn, sockindex))
01415     return true;
01416 
01417   readable = SOCKET_READABLE(conn->sock[sockindex], 0);
01418   return (readable > 0 && (readable & CURL_CSELECT_IN));
01419 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02