Loading lib/connect.c +172 −115 Original line number Diff line number Diff line Loading @@ -101,8 +101,16 @@ /* The last #include file should be: */ #include "memdebug.h" #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ static bool verifyconnect(curl_socket_t sockfd, int *error); static curl_socket_t singleipconnect(struct connectdata *conn, Curl_addrinfo *ai, /* start connecting to this */ long timeout_ms, bool *connected); /* * Curl_ourerrno() returns the errno (or equivalent) on this platform to * hide platform specific for the function that calls this. Loading Loading @@ -422,44 +430,75 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) return rc; } /* Used within the multi interface. Try next IP address, return TRUE if no more address exists */ static bool trynextip(struct connectdata *conn, int sockindex, long timeout, bool *connected) { curl_socket_t sockfd; Curl_addrinfo *ai; if(sockindex != FIRSTSOCKET) return TRUE; /* no next */ ai = conn->ip_addr->ai_next; while (ai) { sockfd = singleipconnect(conn, ai, timeout, connected); if(sockfd != CURL_SOCKET_BAD) { /* store the new socket descriptor */ conn->sock[sockindex] = sockfd; return FALSE; } ai = ai->ai_next; } return TRUE; } /* * Curl_is_connected() is used from the multi interface to check if the * firstsocket has connected. */ CURLcode Curl_is_connected(struct connectdata *conn, curl_socket_t sockfd, int sockindex, bool *connected) { int rc; struct SessionHandle *data = conn->data; CURLcode code = CURLE_OK; curl_socket_t sockfd = conn->sock[sockindex]; long allow = DEFAULT_CONNECT_TIMEOUT; long has_passed; *connected = FALSE; /* a very negative world view is best */ curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); if(data->set.timeout || data->set.connecttimeout) { /* there is a timeout set */ *connected = FALSE; /* a very negative world view is best */ /* Evaluate in milliseconds how much time that has passed */ long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start); has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start); /* subtract the most strict timeout of the ones */ if(data->set.timeout && data->set.connecttimeout) { if (data->set.timeout < data->set.connecttimeout) has_passed -= data->set.timeout*1000; allow = data->set.timeout*1000; else has_passed -= data->set.connecttimeout*1000; allow = data->set.connecttimeout*1000; } else if(data->set.timeout) { allow = data->set.timeout*1000; } else if(data->set.connecttimeout) { allow = data->set.connecttimeout*1000; } else if(data->set.timeout) has_passed -= data->set.timeout*1000; else has_passed -= data->set.connecttimeout*1000; if(has_passed > 0 ) { if(has_passed > allow ) { /* time-out, bail out, go home */ failf(data, "Connection time-out"); failf(data, "Connection time-out after %ld ms", has_passed); return CURLE_OPERATION_TIMEOUTED; } } if(conn->bits.tcpconnect) { /* we are connected already! */ *connected = TRUE; Loading @@ -476,21 +515,27 @@ CURLcode Curl_is_connected(struct connectdata *conn, return CURLE_OK; } /* nope, not connected for real */ failf(data, "Connection failed"); return CURLE_COULDNT_CONNECT; infof(data, "Connection failed\n"); if(trynextip(conn, sockindex, allow-has_passed, connected)) { code = CURLE_COULDNT_CONNECT; } } else if(WAITCONN_TIMEOUT != rc) { /* nope, not connected */ infof(data, "Connection failed\n"); if(trynextip(conn, sockindex, allow-has_passed, connected)) { int error = Curl_ourerrno(); failf(data, "Failed connect to %s:%d; %s", conn->host.name, conn->port, Curl_strerror(conn,error)); return CURLE_COULDNT_CONNECT; code = CURLE_COULDNT_CONNECT; } } /* * If the connection failed here, we should attempt to connect to the "next * address" for the given host. */ return CURLE_OK; return code; } static void tcpnodelay(struct connectdata *conn, Loading @@ -511,6 +556,95 @@ static void tcpnodelay(struct connectdata *conn, #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(struct connectdata *conn, Curl_addrinfo *ai, long timeout_ms, bool *connected) { char addr_buf[128]; int rc; int error; bool conected; struct SessionHandle *data = conn->data; curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd == CURL_SOCKET_BAD) return CURL_SOCKET_BAD; *connected = FALSE; /* default is not connected */ Curl_printable_address(ai, addr_buf, sizeof(addr_buf)); infof(data, " Trying %s... ", addr_buf); if(data->set.tcp_nodelay) tcpnodelay(conn, sockfd); if(conn->data->set.device) { /* user selected to bind the outgoing socket to a specified "device" before doing connect */ CURLcode res = bindlocal(conn, sockfd); if(res) return res; } /* set socket non-blocking */ Curl_nonblock(sockfd, TRUE); rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); if(-1 == rc) { error = Curl_ourerrno(); switch (error) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK /* On some platforms EAGAIN and EWOULDBLOCK are the * same value, and on others they are different, hence * the odd #if */ case EAGAIN: #endif rc = waitconnect(sockfd, timeout_ms); break; default: /* unknown error, fallthrough and try another address! */ failf(data, "Failed to connect to %s: %s", addr_buf, Curl_strerror(conn,error)); break; } } /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from connect(). We can be sure of this since connect() cannot return 1. */ if((WAITCONN_TIMEOUT == rc) && (data->state.used_interface == Curl_if_multi)) { /* Timeout when running the multi interface */ return sockfd; } conected = verifyconnect(sockfd, &error); if(!rc && conected) { /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ infof(data, "connected\n"); return sockfd; } else if(WAITCONN_TIMEOUT == rc) infof(data, "Timeout\n"); else infof(data, "%s\n", Curl_strerror(conn, error)); /* connect failed or timed out */ sclose(sockfd); return CURL_SOCKET_BAD; } /* * TCP connect to the given host with timeout, proxy or remote doesn't matter. * There might be more than one IP address to try out. Fill in the passed Loading @@ -525,11 +659,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ { struct SessionHandle *data = conn->data; curl_socket_t sockfd = CURL_SOCKET_BAD; int rc, error; int aliasindex; int num_addr; bool conected; char addr_buf[256]; Curl_addrinfo *ai; Curl_addrinfo *curr_addr; Loading @@ -539,7 +670,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ /************************************************************* * Figure out what maximum time we have left *************************************************************/ long timeout_ms=300000; /* milliseconds, default to five minutes total */ long timeout_ms= DEFAULT_CONNECT_TIMEOUT; long timeout_per_addr; *connected = FALSE; /* default to not connected */ Loading Loading @@ -583,98 +714,24 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ ai = remotehost->addr; /* Below is the loop that attempts to connect to all IP-addresses we * know for the given host. One by one until one IP succeedes. */ /* * Connecting with a getaddrinfo chain * know for the given host. One by one until one IP succeeds. */ for (curr_addr = ai, aliasindex=0; curr_addr; curr_addr = curr_addr->ai_next, aliasindex++) { sockfd = socket(curr_addr->ai_family, curr_addr->ai_socktype, curr_addr->ai_protocol); if (sockfd == CURL_SOCKET_BAD) { timeout_per_addr += timeout_per_addr / (num_addr - aliasindex); continue; } Curl_printable_address(curr_addr, addr_buf, sizeof(addr_buf)); infof(data, " Trying %s... ", addr_buf); if(data->set.tcp_nodelay) tcpnodelay(conn, sockfd); if(conn->data->set.device) { /* user selected to bind the outgoing socket to a specified "device" before doing connect */ CURLcode res = bindlocal(conn, sockfd); if(res) return res; } /* set socket non-blocking */ Curl_nonblock(sockfd, TRUE); /* do not use #ifdef within the function arguments below, as connect() is a defined macro on some platforms and some compilers don't like to mix #ifdefs with macro usage! (AmigaOS is one such platform) */ rc = connect(sockfd, curr_addr->ai_addr, curr_addr->ai_addrlen); if(-1 == rc) { error = Curl_ourerrno(); switch (error) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK /* On some platforms EAGAIN and EWOULDBLOCK are the * same value, and on others they are different, hence * the odd #if */ case EAGAIN: #endif /* asynchronous connect, wait for connect or timeout */ if(data->state.used_interface == Curl_if_multi) /* don't hang when doing multi */ timeout_per_addr = timeout_ms = 0; rc = waitconnect(sockfd, timeout_per_addr); break; default: /* unknown error, fallthrough and try another address! */ failf(data, "Failed to connect to %s (IP number %d): %s", addr_buf, aliasindex+1, Curl_strerror(conn,error)); break; } } /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from connect(). We can be sure of this since connect() cannot return 1. */ if((WAITCONN_TIMEOUT == rc) && (data->state.used_interface == Curl_if_multi)) { /* Timeout when running the multi interface, we return here with a CURLE_OK return code. */ rc = 0; break; } /* * Connecting with a Curl_addrinfo chain */ for (curr_addr = ai, aliasindex=0; curr_addr; curr_addr = curr_addr->ai_next, aliasindex++) { conected = verifyconnect(sockfd, &error); /* start connecting to the IP curr_addr points to */ sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected); if(!rc && conected) { /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ if(sockfd != CURL_SOCKET_BAD) break; } if(WAITCONN_TIMEOUT == rc) infof(data, "Timeout\n"); else infof(data, "%s\n", Curl_strerror(conn, error)); /* connect failed or timed out */ sclose(sockfd); sockfd = CURL_SOCKET_BAD; /* get a new timeout for next attempt */ after = Curl_tvnow(); Loading lib/multi.c +4 −7 Original line number Diff line number Diff line Loading @@ -320,7 +320,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) easy=multi->easy.next; while(easy) { #ifdef CURLDEBUG #if 0 fprintf(stderr, "HANDLE %p: State: %x\n", (char *)easy, easy->state); #endif Loading Loading @@ -416,8 +416,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) case CURLM_STATE_WAITCONNECT: /* awaiting a completion of an asynch connect */ easy->result = Curl_is_connected(easy->easy_conn, easy->easy_conn->sock[FIRSTSOCKET], easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET, &connected); if(connected) easy->result = Curl_protocol_connect(easy->easy_conn); Loading Loading @@ -463,9 +462,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) /* * First, check if we really are ready to do more. */ easy->result = Curl_is_connected(easy->easy_conn, easy->easy_conn->sock[SECONDARYSOCKET], easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET, &connected); if(connected) { /* Loading Loading
lib/connect.c +172 −115 Original line number Diff line number Diff line Loading @@ -101,8 +101,16 @@ /* The last #include file should be: */ #include "memdebug.h" #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ static bool verifyconnect(curl_socket_t sockfd, int *error); static curl_socket_t singleipconnect(struct connectdata *conn, Curl_addrinfo *ai, /* start connecting to this */ long timeout_ms, bool *connected); /* * Curl_ourerrno() returns the errno (or equivalent) on this platform to * hide platform specific for the function that calls this. Loading Loading @@ -422,44 +430,75 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) return rc; } /* Used within the multi interface. Try next IP address, return TRUE if no more address exists */ static bool trynextip(struct connectdata *conn, int sockindex, long timeout, bool *connected) { curl_socket_t sockfd; Curl_addrinfo *ai; if(sockindex != FIRSTSOCKET) return TRUE; /* no next */ ai = conn->ip_addr->ai_next; while (ai) { sockfd = singleipconnect(conn, ai, timeout, connected); if(sockfd != CURL_SOCKET_BAD) { /* store the new socket descriptor */ conn->sock[sockindex] = sockfd; return FALSE; } ai = ai->ai_next; } return TRUE; } /* * Curl_is_connected() is used from the multi interface to check if the * firstsocket has connected. */ CURLcode Curl_is_connected(struct connectdata *conn, curl_socket_t sockfd, int sockindex, bool *connected) { int rc; struct SessionHandle *data = conn->data; CURLcode code = CURLE_OK; curl_socket_t sockfd = conn->sock[sockindex]; long allow = DEFAULT_CONNECT_TIMEOUT; long has_passed; *connected = FALSE; /* a very negative world view is best */ curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); if(data->set.timeout || data->set.connecttimeout) { /* there is a timeout set */ *connected = FALSE; /* a very negative world view is best */ /* Evaluate in milliseconds how much time that has passed */ long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start); has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start); /* subtract the most strict timeout of the ones */ if(data->set.timeout && data->set.connecttimeout) { if (data->set.timeout < data->set.connecttimeout) has_passed -= data->set.timeout*1000; allow = data->set.timeout*1000; else has_passed -= data->set.connecttimeout*1000; allow = data->set.connecttimeout*1000; } else if(data->set.timeout) { allow = data->set.timeout*1000; } else if(data->set.connecttimeout) { allow = data->set.connecttimeout*1000; } else if(data->set.timeout) has_passed -= data->set.timeout*1000; else has_passed -= data->set.connecttimeout*1000; if(has_passed > 0 ) { if(has_passed > allow ) { /* time-out, bail out, go home */ failf(data, "Connection time-out"); failf(data, "Connection time-out after %ld ms", has_passed); return CURLE_OPERATION_TIMEOUTED; } } if(conn->bits.tcpconnect) { /* we are connected already! */ *connected = TRUE; Loading @@ -476,21 +515,27 @@ CURLcode Curl_is_connected(struct connectdata *conn, return CURLE_OK; } /* nope, not connected for real */ failf(data, "Connection failed"); return CURLE_COULDNT_CONNECT; infof(data, "Connection failed\n"); if(trynextip(conn, sockindex, allow-has_passed, connected)) { code = CURLE_COULDNT_CONNECT; } } else if(WAITCONN_TIMEOUT != rc) { /* nope, not connected */ infof(data, "Connection failed\n"); if(trynextip(conn, sockindex, allow-has_passed, connected)) { int error = Curl_ourerrno(); failf(data, "Failed connect to %s:%d; %s", conn->host.name, conn->port, Curl_strerror(conn,error)); return CURLE_COULDNT_CONNECT; code = CURLE_COULDNT_CONNECT; } } /* * If the connection failed here, we should attempt to connect to the "next * address" for the given host. */ return CURLE_OK; return code; } static void tcpnodelay(struct connectdata *conn, Loading @@ -511,6 +556,95 @@ static void tcpnodelay(struct connectdata *conn, #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(struct connectdata *conn, Curl_addrinfo *ai, long timeout_ms, bool *connected) { char addr_buf[128]; int rc; int error; bool conected; struct SessionHandle *data = conn->data; curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd == CURL_SOCKET_BAD) return CURL_SOCKET_BAD; *connected = FALSE; /* default is not connected */ Curl_printable_address(ai, addr_buf, sizeof(addr_buf)); infof(data, " Trying %s... ", addr_buf); if(data->set.tcp_nodelay) tcpnodelay(conn, sockfd); if(conn->data->set.device) { /* user selected to bind the outgoing socket to a specified "device" before doing connect */ CURLcode res = bindlocal(conn, sockfd); if(res) return res; } /* set socket non-blocking */ Curl_nonblock(sockfd, TRUE); rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); if(-1 == rc) { error = Curl_ourerrno(); switch (error) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK /* On some platforms EAGAIN and EWOULDBLOCK are the * same value, and on others they are different, hence * the odd #if */ case EAGAIN: #endif rc = waitconnect(sockfd, timeout_ms); break; default: /* unknown error, fallthrough and try another address! */ failf(data, "Failed to connect to %s: %s", addr_buf, Curl_strerror(conn,error)); break; } } /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from connect(). We can be sure of this since connect() cannot return 1. */ if((WAITCONN_TIMEOUT == rc) && (data->state.used_interface == Curl_if_multi)) { /* Timeout when running the multi interface */ return sockfd; } conected = verifyconnect(sockfd, &error); if(!rc && conected) { /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ infof(data, "connected\n"); return sockfd; } else if(WAITCONN_TIMEOUT == rc) infof(data, "Timeout\n"); else infof(data, "%s\n", Curl_strerror(conn, error)); /* connect failed or timed out */ sclose(sockfd); return CURL_SOCKET_BAD; } /* * TCP connect to the given host with timeout, proxy or remote doesn't matter. * There might be more than one IP address to try out. Fill in the passed Loading @@ -525,11 +659,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ { struct SessionHandle *data = conn->data; curl_socket_t sockfd = CURL_SOCKET_BAD; int rc, error; int aliasindex; int num_addr; bool conected; char addr_buf[256]; Curl_addrinfo *ai; Curl_addrinfo *curr_addr; Loading @@ -539,7 +670,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ /************************************************************* * Figure out what maximum time we have left *************************************************************/ long timeout_ms=300000; /* milliseconds, default to five minutes total */ long timeout_ms= DEFAULT_CONNECT_TIMEOUT; long timeout_per_addr; *connected = FALSE; /* default to not connected */ Loading Loading @@ -583,98 +714,24 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ ai = remotehost->addr; /* Below is the loop that attempts to connect to all IP-addresses we * know for the given host. One by one until one IP succeedes. */ /* * Connecting with a getaddrinfo chain * know for the given host. One by one until one IP succeeds. */ for (curr_addr = ai, aliasindex=0; curr_addr; curr_addr = curr_addr->ai_next, aliasindex++) { sockfd = socket(curr_addr->ai_family, curr_addr->ai_socktype, curr_addr->ai_protocol); if (sockfd == CURL_SOCKET_BAD) { timeout_per_addr += timeout_per_addr / (num_addr - aliasindex); continue; } Curl_printable_address(curr_addr, addr_buf, sizeof(addr_buf)); infof(data, " Trying %s... ", addr_buf); if(data->set.tcp_nodelay) tcpnodelay(conn, sockfd); if(conn->data->set.device) { /* user selected to bind the outgoing socket to a specified "device" before doing connect */ CURLcode res = bindlocal(conn, sockfd); if(res) return res; } /* set socket non-blocking */ Curl_nonblock(sockfd, TRUE); /* do not use #ifdef within the function arguments below, as connect() is a defined macro on some platforms and some compilers don't like to mix #ifdefs with macro usage! (AmigaOS is one such platform) */ rc = connect(sockfd, curr_addr->ai_addr, curr_addr->ai_addrlen); if(-1 == rc) { error = Curl_ourerrno(); switch (error) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK /* On some platforms EAGAIN and EWOULDBLOCK are the * same value, and on others they are different, hence * the odd #if */ case EAGAIN: #endif /* asynchronous connect, wait for connect or timeout */ if(data->state.used_interface == Curl_if_multi) /* don't hang when doing multi */ timeout_per_addr = timeout_ms = 0; rc = waitconnect(sockfd, timeout_per_addr); break; default: /* unknown error, fallthrough and try another address! */ failf(data, "Failed to connect to %s (IP number %d): %s", addr_buf, aliasindex+1, Curl_strerror(conn,error)); break; } } /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from connect(). We can be sure of this since connect() cannot return 1. */ if((WAITCONN_TIMEOUT == rc) && (data->state.used_interface == Curl_if_multi)) { /* Timeout when running the multi interface, we return here with a CURLE_OK return code. */ rc = 0; break; } /* * Connecting with a Curl_addrinfo chain */ for (curr_addr = ai, aliasindex=0; curr_addr; curr_addr = curr_addr->ai_next, aliasindex++) { conected = verifyconnect(sockfd, &error); /* start connecting to the IP curr_addr points to */ sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected); if(!rc && conected) { /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ if(sockfd != CURL_SOCKET_BAD) break; } if(WAITCONN_TIMEOUT == rc) infof(data, "Timeout\n"); else infof(data, "%s\n", Curl_strerror(conn, error)); /* connect failed or timed out */ sclose(sockfd); sockfd = CURL_SOCKET_BAD; /* get a new timeout for next attempt */ after = Curl_tvnow(); Loading
lib/multi.c +4 −7 Original line number Diff line number Diff line Loading @@ -320,7 +320,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) easy=multi->easy.next; while(easy) { #ifdef CURLDEBUG #if 0 fprintf(stderr, "HANDLE %p: State: %x\n", (char *)easy, easy->state); #endif Loading Loading @@ -416,8 +416,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) case CURLM_STATE_WAITCONNECT: /* awaiting a completion of an asynch connect */ easy->result = Curl_is_connected(easy->easy_conn, easy->easy_conn->sock[FIRSTSOCKET], easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET, &connected); if(connected) easy->result = Curl_protocol_connect(easy->easy_conn); Loading Loading @@ -463,9 +462,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) /* * First, check if we really are ready to do more. */ easy->result = Curl_is_connected(easy->easy_conn, easy->easy_conn->sock[SECONDARYSOCKET], easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET, &connected); if(connected) { /* Loading