/* Used within the multi interface. Try next IP address, return TRUE if no more address exists */ static bool trynextip(struct connectdata *conn, int sockindex, bool *connected) { curl_socket_t sockfd; Curl_addrinfo *ai; /* first close the failed socket */ sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; *connected = FALSE; if(sockindex != FIRSTSOCKET) return TRUE; /* no next */ /* try the next address */ ai = conn->ip_addr->ai_next; while (ai) { sockfd = singleipconnect(conn, ai, 0L, connected); if(sockfd != CURL_SOCKET_BAD) { /* store the new socket descriptor */ conn->sock[sockindex] = sockfd; conn->ip_addr = ai; Curl_store_ip_addr(conn); return FALSE; } ai = ai->ai_next; } return TRUE; }
/* 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. Don't close it yet to ensure that the next IP's socket gets a different file descriptor, which can prevent bugs when the curl_multi_socket_action interface is used with certain select() replacements such as kqueue. */ curl_socket_t fd_to_close = conn->tempsock[tempindex]; 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 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, &conn->tempsock[tempindex]); if(result == CURLE_COULDNT_CONNECT) { ai = ai->ai_next; continue; } conn->tempaddr[tempindex] = ai; } break; } } if(fd_to_close != CURL_SOCKET_BAD) Curl_closesocket(conn, fd_to_close); return result; }
/* 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, bool *connected) { curl_socket_t sockfd; Curl_addrinfo *ai; int family = tempindex ? AF_INET6 : AF_INET; /* First clean up after the failed socket. Don't close it yet to ensure that the next IP's socket gets a different file descriptor, which can prevent bugs when the curl_multi_socket_action interface is used with certain select() replacements such as kqueue. */ curl_socket_t fd_to_close = conn->tempsock[tempindex]; conn->tempsock[tempindex] = CURL_SOCKET_BAD; *connected = FALSE; if(sockindex != FIRSTSOCKET) { Curl_closesocket(conn, fd_to_close); return CURLE_COULDNT_CONNECT; /* no next */ } /* try the next address with same family */ ai = conn->tempaddr[tempindex]->ai_next; while(ai && ai->ai_family != family) ai = ai->ai_next; while(ai && ai->ai_family == family) { CURLcode res = singleipconnect(conn, ai, &sockfd, connected); if(res) return res; if(sockfd != CURL_SOCKET_BAD) { /* store the new socket descriptor */ conn->tempsock[tempindex] = sockfd; conn->tempaddr[tempindex] = ai; Curl_closesocket(conn, fd_to_close); return CURLE_OK; } do { ai = ai->ai_next; } while(ai && ai->ai_family != family); } Curl_closesocket(conn, fd_to_close); return CURLE_COULDNT_CONNECT; }
CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost) { struct SessionHandle *data = conn->data; struct timeval before = Curl_tvnow(); CURLcode result = CURLE_COULDNT_CONNECT; long timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } 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; Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT); /* 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], &(conn->tempsock[0])); if(!result) break; conn->tempaddr[0] = conn->tempaddr[0]->ai_next; } 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 */ return CURLE_OK; }
/* 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) { CURLcode rc = 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 file descriptor, which can prevent bugs when the curl_multi_socket_action interface is used with certain select() replacements such as kqueue. */ curl_socket_t fd_to_close = conn->tempsock[tempindex]; conn->tempsock[tempindex] = CURL_SOCKET_BAD; if(sockindex == FIRSTSOCKET) { Curl_addrinfo *ai; int family; if(conn->tempaddr[tempindex]) { /* find next address in the same protocol family */ family = conn->tempaddr[tempindex]->ai_family; ai = conn->tempaddr[tempindex]->ai_next; } else { /* 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; } while(ai && ai->ai_family != family) ai = ai->ai_next; if(ai) { rc = singleipconnect(conn, ai, &conn->tempsock[tempindex]); conn->tempaddr[tempindex] = ai; } } if(fd_to_close != CURL_SOCKET_BAD) Curl_closesocket(conn, fd_to_close); return rc; }
/* 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, bool *connected) { curl_socket_t sockfd; Curl_addrinfo *ai; /* First clean up after the failed socket. Don't close it yet to ensure that the next IP's socket gets a different file descriptor, which can prevent bugs when the curl_multi_socket_action interface is used with certain select() replacements such as kqueue. */ curl_socket_t fd_to_close = conn->sock[sockindex]; conn->sock[sockindex] = CURL_SOCKET_BAD; *connected = FALSE; if(sockindex != FIRSTSOCKET) { sclose(fd_to_close); return CURLE_COULDNT_CONNECT; /* no next */ } /* try the next address */ ai = conn->ip_addr->ai_next; while(ai) { 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 CURLE_OK; } ai = ai->ai_next; } sclose(fd_to_close); return CURLE_COULDNT_CONNECT; }
CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost, /* use this one */ curl_socket_t *sockconn, /* the connected socket */ Curl_addrinfo **addr, /* the one we used */ bool *connected) /* really connected? */ { struct SessionHandle *data = conn->data; curl_socket_t sockfd = CURL_SOCKET_BAD; int aliasindex; int num_addr; Curl_addrinfo *ai; Curl_addrinfo *curr_addr; struct timeval after; struct timeval before = Curl_tvnow(); /************************************************************* * Figure out what maximum time we have left *************************************************************/ long timeout_ms= DEFAULT_CONNECT_TIMEOUT; long timeout_per_addr; *connected = FALSE; /* default to not connected */ if(data->set.timeout || data->set.connecttimeout) { long has_passed; /* Evaluate in milliseconds how much time that has passed */ has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif /* get the most strict timeout of the ones converted to milliseconds */ if(data->set.timeout && data->set.connecttimeout) { if (data->set.timeout < data->set.connecttimeout) timeout_ms = data->set.timeout*1000; else timeout_ms = data->set.connecttimeout*1000; } else if(data->set.timeout) timeout_ms = data->set.timeout*1000; else timeout_ms = data->set.connecttimeout*1000; /* subtract the passed time */ timeout_ms -= has_passed; if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEOUTED; } } Curl_expire(data, timeout_ms); /* Max time for each address */ num_addr = Curl_num_addresses(remotehost->addr); timeout_per_addr = timeout_ms / num_addr; 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 succeeds. */ if(data->state.used_interface == Curl_if_multi) /* don't hang when doing multi */ timeout_per_addr = 0; /* * Connecting with a Curl_addrinfo chain */ for (curr_addr = ai, aliasindex=0; curr_addr; 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); if(sockfd != CURL_SOCKET_BAD) break; /* get a new timeout for next attempt */ after = Curl_tvnow(); timeout_ms -= Curl_tvdiff(after, before); if(timeout_ms < 0) { failf(data, "connect() timed out!"); return CURLE_OPERATION_TIMEOUTED; } before = after; } /* end of connect-to-each-address loop */ if (sockfd == CURL_SOCKET_BAD) { /* no good connect was made */ *sockconn = CURL_SOCKET_BAD; failf(data, "couldn't connect to host"); return CURLE_COULDNT_CONNECT; } /* leave the socket in non-blocking mode */ /* store the address we use */ if(addr) *addr = curr_addr; /* allow NULL-pointers to get passed in */ if(sockconn) *sockconn = sockfd; /* the socket descriptor we've connected */ data->info.numconnects++; /* to track the number of connections made */ return CURLE_OK; }
CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost, curl_socket_t *sockconn, /* the connected socket */ Curl_addrinfo **addr, /* the one we used */ bool *connected) /* really connected? */ { struct SessionHandle *data = conn->data; curl_socket_t sockfd = CURL_SOCKET_BAD; int aliasindex; int num_addr; Curl_addrinfo *ai; Curl_addrinfo *curr_addr; struct timeval after; struct timeval before = Curl_tvnow(); /************************************************************* * Figure out what maximum time we have left *************************************************************/ long timeout_ms; long timeout_per_addr; DEBUGASSERT(sockconn); *connected = FALSE; /* default to not connected */ /* get the timeout left */ timeout_ms = Curl_timeleft(conn, &before, TRUE); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } Curl_expire(data, timeout_ms); /* Max time for each address */ num_addr = Curl_num_addresses(remotehost->addr); timeout_per_addr = timeout_ms / num_addr; 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 succeeds. */ if(data->state.used_interface == Curl_if_multi) /* don't hang when doing multi */ timeout_per_addr = 0; /* * Connecting with a Curl_addrinfo chain */ for (curr_addr = ai, aliasindex=0; curr_addr; 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); if(sockfd != CURL_SOCKET_BAD) break; /* get a new timeout for next attempt */ after = Curl_tvnow(); timeout_ms -= Curl_tvdiff(after, before); if(timeout_ms < 0) { failf(data, "connect() timed out!"); return CURLE_OPERATION_TIMEDOUT; } before = after; } /* end of connect-to-each-address loop */ *sockconn = sockfd; /* the socket descriptor we've connected */ if(sockfd == CURL_SOCKET_BAD) { /* no good connect was made */ failf(data, "couldn't connect to host"); return CURLE_COULDNT_CONNECT; } /* leave the socket in non-blocking mode */ /* store the address we use */ if(addr) *addr = curr_addr; data->info.numconnects++; /* to track the number of connections made */ return CURLE_OK; }
CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost, bool *connected) /* really connected? */ { struct SessionHandle *data = conn->data; struct timeval after; struct timeval before = Curl_tvnow(); int i; /************************************************************* * Figure out what maximum time we have left *************************************************************/ long timeout_ms; *connected = FALSE; /* default to not connected */ /* get the timeout left */ timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } conn->num_addr = Curl_num_addresses(remotehost->addr); conn->tempaddr[0] = remotehost->addr; conn->tempaddr[1] = remotehost->addr; /* Below is the loop that attempts to connect to all IP-addresses we * know for the given host. * One by one, for each protocol, until one IP succeeds. */ for(i=0; i<2; i++) { curl_socket_t sockfd = CURL_SOCKET_BAD; Curl_addrinfo *ai = conn->tempaddr[i]; int family = i ? AF_INET6 : AF_INET; /* find first address for this address family, if any */ while(ai && ai->ai_family != family) ai = ai->ai_next; /* * Connecting with a Curl_addrinfo chain */ while(ai) { CURLcode res; /* Max time for the next connection attempt */ conn->timeoutms_per_addr = ai->ai_next == NULL ? timeout_ms : timeout_ms / 2; /* start connecting to the IP curr_addr points to */ res = singleipconnect(conn, ai, &sockfd, connected); if(res) return res; if(sockfd != CURL_SOCKET_BAD) break; /* get a new timeout for next attempt */ after = Curl_tvnow(); timeout_ms -= Curl_tvdiff(after, before); if(timeout_ms < 0) { failf(data, "connect() timed out!"); return CURLE_OPERATION_TIMEDOUT; } before = after; /* next addresses */ do { ai = ai->ai_next; } while(ai && ai->ai_family != family); } /* end of connect-to-each-address loop */ conn->tempsock[i] = sockfd; conn->tempaddr[i] = ai; } if((conn->tempsock[0] == CURL_SOCKET_BAD) && (conn->tempsock[1] == CURL_SOCKET_BAD)) { /* no good connect was made */ failf(data, "couldn't connect to %s at %s:%ld", conn->bits.proxy?"proxy":"host", conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port); return CURLE_COULDNT_CONNECT; } /* leave the socket in non-blocking mode */ data->info.numconnects++; /* to track the number of connections made */ return CURLE_OK; }