diff options
Diffstat (limited to 'libs/libcurl/src/connect.c')
-rw-r--r-- | libs/libcurl/src/connect.c | 187 |
1 files changed, 91 insertions, 96 deletions
diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c index 0a7475cb6a..421f904159 100644 --- a/libs/libcurl/src/connect.c +++ b/libs/libcurl/src/connect.c @@ -167,11 +167,12 @@ tcpkeepalive(struct Curl_easy *data, static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, /* start connecting to this */ - int sockindex); /* 0 or 1 among the temp ones */ + int tempindex); /* 0 or 1 among the temp ones */ /* * Curl_timeleft() returns the amount of milliseconds left allowed for the - * transfer/connection. If the value is negative, the timeout time has already + * transfer/connection. If the value is 0, there's no timeout (ie there's + * infinite time left). If the value is negative, the timeout time has already * elapsed. * * The start time is stored in progress.t_startsingle - as set with @@ -555,13 +556,27 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) return rc; } +/* update tempaddr[tempindex] (to the next entry), makes sure to stick + to the correct family */ +static Curl_addrinfo *ainext(struct connectdata *conn, + int tempindex, + bool next) /* use current or next entry */ +{ + Curl_addrinfo *ai = conn->tempaddr[tempindex]; + if(ai && next) + ai = ai->ai_next; + while(ai && (ai->ai_family != conn->tempfamily[tempindex])) + ai = ai->ai_next; + conn->tempaddr[tempindex] = ai; + return ai; +} + /* Used within the multi interface. Try next IP address, return TRUE if no more address exists or error */ static CURLcode trynextip(struct connectdata *conn, int sockindex, int tempindex) { - const int other = tempindex ^ 1; CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. @@ -572,38 +587,15 @@ static CURLcode trynextip(struct connectdata *conn, conn->tempsock[tempindex] = CURL_SOCKET_BAD; if(sockindex == FIRSTSOCKET) { - Curl_addrinfo *ai = NULL; - int family = AF_UNSPEC; - - if(conn->tempaddr[tempindex]) { - /* find next address in the same protocol family */ - 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; - family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; - ai = conn->tempaddr[0]->ai_next; - } -#endif + Curl_addrinfo *ai = conn->tempaddr[tempindex]; while(ai) { - 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) { result = singleipconnect(conn, ai, tempindex); if(result == CURLE_COULDNT_CONNECT) { - ai = ai->ai_next; + ai = ainext(conn, tempindex, TRUE); continue; } - - conn->tempaddr[tempindex] = ai; } break; } @@ -688,58 +680,56 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { - if(conn->transport != TRNSPRT_TCP) - /* there's no TCP connection! */ - return; - + if(conn->transport == TRNSPRT_TCP) { #if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME) - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { - struct Curl_easy *data = conn->data; - char buffer[STRERROR_LEN]; - struct Curl_sockaddr_storage ssrem; - struct Curl_sockaddr_storage ssloc; - curl_socklen_t plen; - curl_socklen_t slen; + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { + struct Curl_easy *data = conn->data; + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssrem; + struct Curl_sockaddr_storage ssloc; + curl_socklen_t plen; + curl_socklen_t slen; #ifdef HAVE_GETPEERNAME - plen = sizeof(struct Curl_sockaddr_storage); - if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { - int error = SOCKERRNO; - failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } + plen = sizeof(struct Curl_sockaddr_storage); + if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { + int error = SOCKERRNO; + failf(data, "getpeername() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } #endif #ifdef HAVE_GETSOCKNAME - slen = sizeof(struct Curl_sockaddr_storage); - memset(&ssloc, 0, sizeof(ssloc)); - if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { - int error = SOCKERRNO; - failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } + slen = sizeof(struct Curl_sockaddr_storage); + memset(&ssloc, 0, sizeof(ssloc)); + if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { + int error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } #endif #ifdef HAVE_GETPEERNAME - if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, - conn->primary_ip, &conn->primary_port)) { - failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } - memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); + if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, + conn->primary_ip, &conn->primary_port)) { + failf(data, "ssrem inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } + memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); #endif #ifdef HAVE_GETSOCKNAME - if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, - conn->local_ip, &conn->local_port)) { - failf(data, "ssloc inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } + if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, + conn->local_ip, &conn->local_port)) { + failf(data, "ssloc inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } #endif - } + } #else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */ - (void)sockfd; /* unused */ + (void)sockfd; /* unused */ #endif + } /* end of TCP-only section */ /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -816,6 +806,7 @@ static void post_SOCKS(struct connectdata *conn, Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */ Curl_updateconninfo(conn, conn->sock[sockindex]); Curl_verboseconnect(conn); + conn->data->info.numconnects++; /* to track the number of connections made */ } /* @@ -880,6 +871,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->sock[sockindex] = conn->tempsock[i]; conn->ip_addr = conn->tempaddr[i]; conn->tempsock[i] = CURL_SOCKET_BAD; + post_SOCKS(conn, sockindex, connected); connkeep(conn, "HTTP/3 default"); } return result; @@ -905,9 +897,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, } /* should we try another protocol family? */ - if(i == 0 && conn->tempaddr[1] == NULL && + if(i == 0 && !conn->parallel_connect && (Curl_timediff(now, conn->connecttime) >= data->set.happy_eyeballs_timeout)) { + conn->parallel_connect = TRUE; /* starting now */ trynextip(conn, sockindex, 1); } } @@ -967,7 +960,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; - + ainext(conn, i, TRUE); status = trynextip(conn, sockindex, i); if((status != CURLE_COULDNT_CONNECT) || conn->tempsock[other] == CURL_SOCKET_BAD) @@ -984,7 +977,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, /* 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) { + { result = trynextip(conn, sockindex, 1); if(!result) return result; @@ -1113,7 +1106,7 @@ void Curl_sndbufset(curl_socket_t sockfd) */ static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, - int sockindex) + int tempindex) { struct Curl_sockaddr_ex addr; int rc = -1; @@ -1129,15 +1122,12 @@ static CURLcode singleipconnect(struct connectdata *conn, int optval = 1; #endif char buffer[STRERROR_LEN]; - curl_socket_t *sockp = &conn->tempsock[sockindex]; + curl_socket_t *sockp = &conn->tempsock[tempindex]; *sockp = CURL_SOCKET_BAD; 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. */ - return CURLE_OK; + return result; /* store remote address and port used in this connection attempt */ if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen, @@ -1257,7 +1247,7 @@ static CURLcode singleipconnect(struct connectdata *conn, else if(conn->transport == TRNSPRT_QUIC) { /* pass in 'sockfd' separately since it hasn't been put into the tempsock array at this point */ - result = Curl_quic_connect(conn, sockfd, sockindex, + result = Curl_quic_connect(conn, sockfd, tempindex, &addr.sa_addr, addr.addrlen); if(result) error = SOCKERRNO; @@ -1315,7 +1305,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ struct Curl_easy *data = conn->data; struct curltime before = Curl_now(); CURLcode result = CURLE_COULDNT_CONNECT; - + int i; timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { @@ -1325,30 +1315,35 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } conn->num_addr = Curl_num_addresses(remotehost->addr); - conn->tempaddr[0] = remotehost->addr; - conn->tempaddr[1] = NULL; - conn->tempsock[0] = CURL_SOCKET_BAD; - conn->tempsock[1] = CURL_SOCKET_BAD; + conn->tempaddr[0] = conn->tempaddr[1] = remotehost->addr; + conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD; /* Max time for the next connection attempt */ conn->timeoutms_per_addr = conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; - /* start connecting to first IP */ - while(conn->tempaddr[0]) { - result = singleipconnect(conn, conn->tempaddr[0], 0); - if(!result) - break; - conn->tempaddr[0] = conn->tempaddr[0]->ai_next; - } + conn->tempfamily[0] = conn->tempaddr[0]? + conn->tempaddr[0]->ai_family:0; + conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ? + AF_INET : AF_INET6; + ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */ - if(conn->tempsock[0] == CURL_SOCKET_BAD) { - if(!result) - result = CURLE_COULDNT_CONNECT; - return result; + DEBUGF(infof(data, "family0 == %s, family1 == %s\n", + conn->tempfamily[0] == AF_INET ? "v4" : "v6", + conn->tempfamily[1] == AF_INET ? "v4" : "v6")); + + /* get through the list in family order in case of quick failures */ + for(i = 0; (i < 2) && result; i++) { + while(conn->tempaddr[i]) { + result = singleipconnect(conn, conn->tempaddr[i], i); + if(!result) + break; + ainext(conn, i, TRUE); + } } + if(result) + return result; - data->info.numconnects++; /* to track the number of connections made */ Curl_expire(conn->data, data->set.happy_eyeballs_timeout, EXPIRE_HAPPY_EYEBALLS); |