diff options
Diffstat (limited to 'Utilities/cmcurl/lib/connect.c')
-rw-r--r-- | Utilities/cmcurl/lib/connect.c | 227 |
1 files changed, 135 insertions, 92 deletions
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index fb315fc..18ac32c 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,15 +56,12 @@ #include <inet.h> #endif -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "urldata.h" #include "sendf.h" #include "if2ip.h" #include "strerror.h" #include "connect.h" -#include "curl_memory.h" #include "select.h" #include "url.h" /* for Curl_safefree() */ #include "multiif.h" @@ -77,7 +74,8 @@ #include "conncache.h" #include "multihandle.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifdef __SYMBIAN32__ @@ -238,7 +236,7 @@ long Curl_timeleft(struct SessionHandle *data, } static CURLcode bindlocal(struct connectdata *conn, - curl_socket_t sockfd, int af) + curl_socket_t sockfd, int af, unsigned int scope) { struct SessionHandle *data = conn->data; @@ -257,12 +255,6 @@ static CURLcode bindlocal(struct connectdata *conn, int portnum = data->set.localportrange; const char *dev = data->set.str[STRING_DEVICE]; int error; - char myhost[256] = ""; - int done = 0; /* -1 for error, 1 for address found */ - bool is_interface = FALSE; - bool is_host = FALSE; - static const char *if_prefix = "if!"; - static const char *host_prefix = "host!"; /************************************************************* * Select device to bind socket to @@ -274,6 +266,13 @@ static CURLcode bindlocal(struct connectdata *conn, memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); if(dev && (strlen(dev)<255) ) { + char myhost[256] = ""; + int done = 0; /* -1 for error, 1 for address found */ + bool is_interface = FALSE; + bool is_host = FALSE; + static const char *if_prefix = "if!"; + static const char *host_prefix = "host!"; + if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { dev += strlen(if_prefix); is_interface = TRUE; @@ -285,7 +284,8 @@ static CURLcode bindlocal(struct connectdata *conn, /* interface */ if(!is_host) { - switch(Curl_if2ip(af, conn->scope, dev, myhost, sizeof(myhost))) { + switch(Curl_if2ip(af, scope, conn->scope_id, dev, + myhost, sizeof(myhost))) { case IF2IP_NOT_FOUND: if(is_interface) { /* Do not fall back to treating it as a host name */ @@ -374,7 +374,7 @@ static CURLcode bindlocal(struct connectdata *conn, if(done > 0) { #ifdef ENABLE_IPV6 - /* ipv6 address */ + /* IPv6 address */ if(af == AF_INET6) { #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID char *scope_ptr = strchr(myhost, '%'); @@ -397,7 +397,7 @@ static CURLcode bindlocal(struct connectdata *conn, } else #endif - /* ipv4 address */ + /* IPv4 address */ if((af == AF_INET) && (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { si4->sin_family = AF_INET; @@ -540,7 +540,8 @@ static CURLcode trynextip(struct connectdata *conn, int sockindex, int tempindex) { - CURLcode rc = CURLE_COULDNT_CONNECT; + const int other = tempindex ^ 1; + CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. Don't close it yet to ensure that the next IP's socket gets a different @@ -558,27 +559,29 @@ static CURLcode trynextip(struct connectdata *conn, family = conn->tempaddr[tempindex]->ai_family; ai = conn->tempaddr[tempindex]->ai_next; } +#ifdef ENABLE_IPV6 else if(conn->tempaddr[0]) { /* happy eyeballs - try the other protocol family */ int firstfamily = conn->tempaddr[0]->ai_family; -#ifdef ENABLE_IPV6 family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; -#else - family = firstfamily; -#endif ai = conn->tempaddr[0]->ai_next; } +#endif while(ai) { - while(ai && ai->ai_family != family) - ai = ai->ai_next; + if(conn->tempaddr[other]) { + /* we can safely skip addresses of the other protocol family */ + while(ai && ai->ai_family != family) + ai = ai->ai_next; + } if(ai) { - rc = singleipconnect(conn, ai, &conn->tempsock[tempindex]); - if(rc == CURLE_COULDNT_CONNECT) { + result = singleipconnect(conn, ai, &conn->tempsock[tempindex]); + if(result == CURLE_COULDNT_CONNECT) { ai = ai->ai_next; continue; } + conn->tempaddr[tempindex] = ai; } break; @@ -588,7 +591,7 @@ static CURLcode trynextip(struct connectdata *conn, if(fd_to_close != CURL_SOCKET_BAD) Curl_closesocket(conn, fd_to_close); - return rc; + return result; } /* Copies connection info into the session handle to make it available @@ -656,7 +659,6 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { - int error; curl_socklen_t len; struct Curl_sockaddr_storage ssrem; struct Curl_sockaddr_storage ssloc; @@ -667,6 +669,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) return; if(!conn->bits.reuse) { + int error; len = sizeof(struct Curl_sockaddr_storage); if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) { @@ -677,6 +680,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) } len = sizeof(struct Curl_sockaddr_storage); + memset(&ssloc, 0, sizeof(ssloc)); if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) { error = SOCKERRNO; failf(data, "getsockname() failed with errno %d: %s", @@ -716,11 +720,11 @@ CURLcode Curl_is_connected(struct connectdata *conn, bool *connected) { struct SessionHandle *data = conn->data; - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; long allow; int error = 0; struct timeval now; - int result; + int rc; int i; DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); @@ -745,6 +749,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, } for(i=0; i<2; i++) { + const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) continue; @@ -756,9 +761,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, #endif /* check socket for connect */ - result = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); + rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); - if(result == 0) { /* no connection yet */ + if(rc == 0) { /* no connection yet */ if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { infof(data, "After %ldms connect time, move on!\n", conn->timeoutms_per_addr); @@ -771,10 +776,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, trynextip(conn, sockindex, 1); } } - else if(result == CURL_CSELECT_OUT) { + else if(rc == CURL_CSELECT_OUT) { if(verifyconnect(conn->tempsock[i], &error)) { /* we are connected with TCP, awesome! */ - int other = i ^ 1; /* use this socket from now on */ conn->sock[sockindex] = conn->tempsock[i]; @@ -788,9 +792,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, } /* see if we need to do any proxy magic first once we connected */ - code = Curl_connected_proxy(conn, sockindex); - if(code) - return code; + result = Curl_connected_proxy(conn, sockindex); + if(result) + return result; conn->bits.tcpconnect[sockindex] = TRUE; @@ -805,7 +809,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, else infof(data, "Connection failed\n"); } - else if(result & CURL_CSELECT_ERR) + else if(rc & CURL_CSELECT_ERR) (void)verifyconnect(conn->tempsock[i], &error); /* @@ -813,10 +817,11 @@ CURLcode Curl_is_connected(struct connectdata *conn, * address" for the given host. But first remember the latest error. */ if(error) { - char ipaddress[MAX_IPADR_LEN]; data->state.os_errno = error; SET_SOCKERRNO(error); if(conn->tempaddr[i]) { + CURLcode status; + char ipaddress[MAX_IPADR_LEN]; Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); infof(data, "connect to %s port %ld failed: %s\n", ipaddress, conn->port, Curl_strerror(conn, error)); @@ -824,21 +829,24 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; - code = trynextip(conn, sockindex, i); + status = trynextip(conn, sockindex, i); + if(status != CURLE_COULDNT_CONNECT + || conn->tempsock[other] == CURL_SOCKET_BAD) + /* the last attempt failed and no other sockets remain open */ + result = status; } } } - if(code) { + if(result) { /* no more addresses to try */ /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ if(conn->tempaddr[1] == NULL) { - int rc; - rc = trynextip(conn, sockindex, 1); - if(rc == CURLE_OK) - return CURLE_OK; + result = trynextip(conn, sockindex, 1); + if(!result) + return result; } failf(data, "Failed to connect to %s port %ld: %s", @@ -846,7 +854,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->port, Curl_strerror(conn, error)); } - return code; + return result; } static void tcpnodelay(struct connectdata *conn, @@ -875,7 +883,7 @@ static void tcpnodelay(struct connectdata *conn, infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(conn, SOCKERRNO)); else - infof(data,"TCP_NODELAY set\n"); + infof(data, "TCP_NODELAY set\n"); #else (void)conn; (void)sockfd; @@ -941,16 +949,21 @@ void Curl_sndbufset(curl_socket_t sockfd) detectOsState = DETECT_OS_VISTA_OR_LATER; } #else - ULONGLONG majorVersionMask; + ULONGLONG cm; OSVERSIONINFOEX osver; memset(&osver, 0, sizeof(osver)); osver.dwOSVersionInfoSize = sizeof(osver); osver.dwMajorVersion = majorVersion; - majorVersionMask = VerSetConditionMask(0, VER_MAJORVERSION, - VER_GREATER_EQUAL); - if(VerifyVersionInfo(&osver, VER_MAJORVERSION, majorVersionMask)) + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm)) detectOsState = DETECT_OS_VISTA_OR_LATER; else detectOsState = DETECT_OS_PREVISTA; @@ -977,10 +990,9 @@ void Curl_sndbufset(curl_socket_t sockfd) * singleipconnect() connects to the given IP only, and it may return without * having connected. */ -static CURLcode -singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, - curl_socket_t *sockp) +static CURLcode singleipconnect(struct connectdata *conn, + const Curl_addrinfo *ai, + curl_socket_t *sockp) { struct Curl_sockaddr_ex addr; int rc; @@ -988,14 +1000,15 @@ singleipconnect(struct connectdata *conn, bool isconnected = FALSE; struct SessionHandle *data = conn->data; curl_socket_t sockfd; - CURLcode res = CURLE_OK; + CURLcode result; char ipaddress[MAX_IPADR_LEN]; long port; + bool is_tcp; *sockp = CURL_SOCKET_BAD; - res = Curl_socket(conn, ai, &addr, &sockfd); - if(res) + result = Curl_socket(conn, ai, &addr, &sockfd); + if(result) /* Failed to create the socket, but still return OK since we signal the lack of socket as well. This allows the parent function to keep looping over alternative addresses/socket families etc. */ @@ -1013,14 +1026,20 @@ singleipconnect(struct connectdata *conn, } infof(data, " Trying %s...\n", ipaddress); - if(data->set.tcp_nodelay) +#ifdef ENABLE_IPV6 + is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && + addr.socktype == SOCK_STREAM; +#else + is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; +#endif + if(is_tcp && data->set.tcp_nodelay) tcpnodelay(conn, sockfd); nosigpipe(conn, sockfd); Curl_sndbufset(sockfd); - if(data->set.tcp_keepalive) + if(is_tcp && data->set.tcp_keepalive) tcpkeepalive(data, sockfd); if(data->set.fsockopt) { @@ -1038,19 +1057,26 @@ singleipconnect(struct connectdata *conn, } /* possibly bind the local end to an IP, interface or port */ - res = bindlocal(conn, sockfd, addr.family); - if(res) { - Curl_closesocket(conn, sockfd); /* close socket and bail out */ - if(res == CURLE_UNSUPPORTED_PROTOCOL) { - /* The address family is not supported on this interface. - We can continue trying addresses */ - return CURLE_OK; + if(addr.family == AF_INET +#ifdef ENABLE_IPV6 + || addr.family == AF_INET6 +#endif + ) { + result = bindlocal(conn, sockfd, addr.family, + Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr)); + if(result) { + Curl_closesocket(conn, sockfd); /* close socket and bail out */ + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + /* The address family is not supported on this interface. + We can continue trying addresses */ + return CURLE_COULDNT_CONNECT; + } + return result; } - return res; } /* set socket non-blocking */ - curlx_nonblock(sockfd, TRUE); + (void)curlx_nonblock(sockfd, TRUE); conn->connecttime = Curl_tvnow(); if(conn->num_addr > 1) @@ -1084,25 +1110,25 @@ singleipconnect(struct connectdata *conn, case EAGAIN: #endif #endif - res = CURLE_OK; + result = CURLE_OK; break; default: /* unknown error, fallthrough and try another address! */ infof(data, "Immediate connect fail for %s: %s\n", - ipaddress, Curl_strerror(conn,error)); + ipaddress, Curl_strerror(conn, error)); data->state.os_errno = error; /* connect failed */ Curl_closesocket(conn, sockfd); - res = CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; } } - if(!res) + if(!result) *sockp = sockfd; - return res; + return result; } /* @@ -1116,7 +1142,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ { struct SessionHandle *data = conn->data; struct timeval before = Curl_tvnow(); - CURLcode res = CURLE_COULDNT_CONNECT; + CURLcode result = CURLE_COULDNT_CONNECT; long timeout_ms = Curl_timeleft(data, &before, TRUE); @@ -1139,14 +1165,17 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ /* start connecting to first IP */ while(conn->tempaddr[0]) { - res = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); - if(res == CURLE_OK) - break; + result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); + if(!result) + break; conn->tempaddr[0] = conn->tempaddr[0]->ai_next; } - if(conn->tempsock[0] == CURL_SOCKET_BAD) - return res; + if(conn->tempsock[0] == CURL_SOCKET_BAD) { + if(!result) + result = CURLE_COULDNT_CONNECT; + return result; + } data->info.numconnects++; /* to track the number of connections made */ @@ -1181,15 +1210,20 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, DEBUGASSERT(data); - /* this only works for an easy handle that has been used for - curl_easy_perform()! */ - if(data->state.lastconnect && data->multi_easy) { + /* this works for an easy handle: + * - that has been used for curl_easy_perform() + * - that is associated with a multi handle, and whose connection + * was detached with CURLOPT_CONNECT_ONLY + */ + if(data->state.lastconnect && (data->multi_easy || data->multi)) { struct connectdata *c = data->state.lastconnect; struct connfind find; find.tofind = data->state.lastconnect; find.found = FALSE; - Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn); + Curl_conncache_foreach(data->multi_easy? + &data->multi_easy->conn_cache: + &data->multi->conn_cache, &find, conn_is_conn); if(!find.found) { data->state.lastconnect = NULL; @@ -1240,15 +1274,18 @@ int Curl_closesocket(struct connectdata *conn, accept, then we MUST NOT call the callback but clear the accepted status */ conn->sock_accepted[SECONDARYSOCKET] = FALSE; - else + else { + Curl_multi_closed(conn, sock); return conn->fclosesocket(conn->closesocket_client, sock); + } } - sclose(sock); if(conn) /* tell the multi-socket code about this */ Curl_multi_closed(conn, sock); + sclose(sock); + return 0; } @@ -1312,9 +1349,9 @@ CURLcode Curl_socket(struct connectdata *conn, return CURLE_COULDNT_CONNECT; #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - if(conn->scope && (addr->family == AF_INET6)) { + if(conn->scope_id && (addr->family == AF_INET6)) { struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; - sa6->sin6_scope_id = conn->scope; + sa6->sin6_scope_id = conn->scope_id; } #endif @@ -1325,16 +1362,22 @@ CURLcode Curl_socket(struct connectdata *conn, #ifdef CURLDEBUG /* * Curl_conncontrol() is used to set the conn->bits.close bit on or off. It - * MUST be called with the connclose() or connclose() macros with a stated + * MUST be called with the connclose() or connkeep() macros with a stated * reason. The reason is only shown in debug builds but helps to figure out * decision paths when connections are or aren't re-used as expected. */ void Curl_conncontrol(struct connectdata *conn, bool closeit, const char *reason) { - infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", - reason); - conn->bits.close = closeit; /* the only place in the source code that should - assign this bit */ +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) reason; +#endif + if(closeit != conn->bits.close) { + infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", + reason); + + conn->bits.close = closeit; /* the only place in the source code that + should assign this bit */ + } } #endif |