diff --git a/lib/connect.c b/lib/connect.c index 12e71278e..0495887b0 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -112,10 +112,11 @@ struct Curl_sockaddr_ex { static bool verifyconnect(curl_socket_t sockfd, int *error); -static curl_socket_t +static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, /* start connecting to this */ long timeout_ms, + curl_socket_t *sock, bool *connected); /* @@ -180,16 +181,13 @@ long Curl_timeleft(struct connectdata *conn, /* * waitconnect() waits for a TCP connect on the given socket for the specified * number if milliseconds. It returns: - * 0 fine connect - * -1 select() error - * 1 select() timeout - * 2 select() returned with an error condition fd_set */ #define WAITCONN_CONNECTED 0 #define WAITCONN_SELECT_ERROR -1 #define WAITCONN_TIMEOUT 1 #define WAITCONN_FDSET_ERROR 2 +#define WAITCONN_ABORTED 3 static int waitconnect(struct connectdata *conn, @@ -209,9 +207,8 @@ int waitconnect(struct connectdata *conn, /* now select() until we get connect or timeout */ rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)(timeout_msec>1000? 1000:timeout_msec)); - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; + return WAITCONN_ABORTED; if(-1 == rc) /* error, no connect here, try next */ @@ -492,9 +489,9 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) /* Used within the multi interface. Try next IP address, return TRUE if no more address exists or error */ -static bool trynextip(struct connectdata *conn, - int sockindex, - bool *connected) +static CURLcode trynextip(struct connectdata *conn, + int sockindex, + bool *connected) { curl_socket_t sockfd; Curl_addrinfo *ai; @@ -509,25 +506,27 @@ static bool trynextip(struct connectdata *conn, if(sockindex != FIRSTSOCKET) { sclose(fd_to_close); - return TRUE; /* no next */ + return CURLE_COULDNT_CONNECT; /* no next */ } /* try the next address */ ai = conn->ip_addr->ai_next; while(ai) { - sockfd = singleipconnect(conn, ai, 0L, connected); + CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected); + if(res) + return res; if(sockfd != CURL_SOCKET_BAD) { /* store the new socket descriptor */ conn->sock[sockindex] = sockfd; conn->ip_addr = ai; sclose(fd_to_close); - return FALSE; + return CURLE_OK; } ai = ai->ai_next; } sclose(fd_to_close); - return TRUE; + return CURLE_COULDNT_CONNECT; } /* retrieves ip address and port from a sockaddr structure */ @@ -675,11 +674,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, /* nope, not connected for real */ data->state.os_errno = error; infof(data, "Connection failed\n"); - if(trynextip(conn, sockindex, connected)) { + code = trynextip(conn, sockindex, connected); + if(code) failf(data, "Failed connect to %s:%ld; %s", conn->host.name, conn->port, Curl_strerror(conn, error)); - code = CURLE_COULDNT_CONNECT; - } } else if(WAITCONN_TIMEOUT != rc) { int error = 0; @@ -693,12 +691,13 @@ CURLcode Curl_is_connected(struct connectdata *conn, else infof(data, "Connection failed\n"); - if(trynextip(conn, sockindex, connected)) { + code = trynextip(conn, sockindex, connected); + + if(code) { error = SOCKERRNO; data->state.os_errno = error; failf(data, "Failed connect to %s:%ld; %s", conn->host.name, conn->port, Curl_strerror(conn, error)); - code = CURLE_COULDNT_CONNECT; } } /* @@ -786,12 +785,20 @@ void Curl_sndbufset(curl_socket_t sockfd) #endif -/* singleipconnect() connects to the given IP only, and it may return without - having connected if used from the multi interface. */ -static curl_socket_t +/* + * singleipconnect() + * + * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to + * CURL_SOCKET_BAD. Other errors will however return proper errors. + * + * singleipconnect() connects to the given IP only, and it may return without + * having connected if used from the multi interface. + */ +static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, long timeout_ms, + curl_socket_t *sockp, bool *connected) { struct Curl_sockaddr_ex addr; @@ -801,13 +808,15 @@ singleipconnect(struct connectdata *conn, bool isconnected; struct SessionHandle *data = conn->data; curl_socket_t sockfd; - CURLcode res; + CURLcode res = CURLE_OK; const void *iptoprint; struct sockaddr_in * const sa4 = (void *)&addr.sa_addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr; #endif + *sockp = CURL_SOCKET_BAD; + /* * The Curl_sockaddr_ex structure is basically libcurl's external API * curl_sockaddr structure with enough space available to directly hold @@ -846,7 +855,7 @@ singleipconnect(struct connectdata *conn, if(sockfd == CURL_SOCKET_BAD) /* no socket, no connection */ - return CURL_SOCKET_BAD; + return CURLE_OK; #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) if (conn->scope && (addr.family == AF_INET6)) @@ -899,7 +908,7 @@ singleipconnect(struct connectdata *conn, CURLSOCKTYPE_IPCXN); if(error) { sclose(sockfd); /* close the socket and bail out */ - return CURL_SOCKET_BAD; + return res; } } @@ -907,7 +916,7 @@ singleipconnect(struct connectdata *conn, res = bindlocal(conn, sockfd, addr.family); if(res) { sclose(sockfd); /* close socket and bail out */ - return CURL_SOCKET_BAD; + return res; } /* set socket non-blocking */ @@ -935,6 +944,10 @@ singleipconnect(struct connectdata *conn, #endif #endif rc = waitconnect(conn, sockfd, timeout_ms); + if(WAITCONN_ABORTED == rc) { + sclose(sockfd); + return CURLE_ABORTED_BY_CALLBACK; + } break; default: /* unknown error, fallthrough and try another address! */ @@ -950,7 +963,8 @@ singleipconnect(struct connectdata *conn, if((WAITCONN_TIMEOUT == rc) && (data->state.used_interface == Curl_if_multi)) { /* Timeout when running the multi interface */ - return sockfd; + *sockp = sockfd; + return CURLE_OK; } isconnected = verifyconnect(sockfd, &error); @@ -960,7 +974,8 @@ singleipconnect(struct connectdata *conn, *connected = TRUE; /* this is a true connect */ infof(data, "connected\n"); Curl_updateconninfo(conn, sockfd); - return sockfd; + *sockp = sockfd; + return CURLE_OK; } else if(WAITCONN_TIMEOUT == rc) infof(data, "Timeout\n"); @@ -972,7 +987,7 @@ singleipconnect(struct connectdata *conn, /* connect failed or timed out */ sclose(sockfd); - return CURL_SOCKET_BAD; + return CURLE_OK; } /* @@ -1037,7 +1052,11 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ curr_addr = curr_addr->ai_next, aliasindex++) { /* start connecting to the IP curr_addr points to */ - sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected); + CURLcode res = + singleipconnect(conn, curr_addr, timeout_per_addr, &sockfd, connected); + + if(res) + return res; if(sockfd != CURL_SOCKET_BAD) break; diff --git a/tests/data/test1084 b/tests/data/test1084 index 2bc0183a7..1cfab68dc 100644 --- a/tests/data/test1084 +++ b/tests/data/test1084 @@ -35,7 +35,7 @@ http://%HOSTIP:%HTTPPORT/1084 --interface non-existing-host.haxx.se. # Verify data after the test has been "shot" -7 +45 diff --git a/tests/data/test1085 b/tests/data/test1085 index 0cedefe3b..db02e6033 100644 --- a/tests/data/test1085 +++ b/tests/data/test1085 @@ -42,7 +42,7 @@ HTTP-IPv6 GET with invalid --interface # Verify data after the test has been "shot" -7 +45