From ced89553250030849a9896dae1d446c5ccf1ac3c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 2 Oct 2001 11:26:53 +0000 Subject: IPv6 adjustments, connect()ing to bad ports still don't work properly for IPv6 --- lib/connect.c | 115 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 39 deletions(-) (limited to 'lib/connect.c') diff --git a/lib/connect.c b/lib/connect.c index a5c2ddeb4..a71e3b3e2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -132,6 +132,7 @@ int waitconnect(int sockfd, /* socket */ int timeout_msec) { fd_set fd; + fd_set errfd; struct timeval interval; int rc; @@ -139,12 +140,15 @@ int waitconnect(int sockfd, /* socket */ FD_ZERO(&fd); FD_SET(sockfd, &fd); + FD_ZERO(&errfd); + FD_SET(sockfd, &errfd); + interval.tv_sec = timeout_msec/1000; timeout_msec -= interval.tv_sec*1000; interval.tv_usec = timeout_msec*1000; - rc = select(sockfd+1, NULL, &fd, NULL, &interval); + rc = select(sockfd+1, NULL, &fd, &errfd, &interval); if(-1 == rc) /* error, no connect here, try next */ return -1; @@ -153,10 +157,16 @@ int waitconnect(int sockfd, /* socket */ /* timeout, no connect today */ return 1; + if(FD_ISSET(sockfd, &errfd)) { + /* error condition caught */ + return 2; + } + /* we have a connect! */ return 0; } +#ifndef ENABLE_IPV6 static CURLcode bindlocal(struct connectdata *conn, int sockfd) { @@ -171,7 +181,6 @@ static CURLcode bindlocal(struct connectdata *conn, #define INADDR_NONE (unsigned long) ~0 #endif -#ifndef ENABLE_IPV6 struct SessionHandle *data = conn->data; /************************************************************* @@ -284,12 +293,12 @@ static CURLcode bindlocal(struct connectdata *conn, return CURLE_OK; } /* end of device selection support */ -#endif /* end of HAVE_INET_NTOA */ +#endif /* end of HAVE_INET_NTOA */ #endif /* end of not WIN32 */ -#endif /*ENABLE_IPV6*/ return CURLE_HTTP_PORT_FAILED; } +#endif /* end of ipv4-specific section */ /* * TCP connect to the given host with timeout, proxy or remote doesn't matter. @@ -341,54 +350,82 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } #ifdef ENABLE_IPV6 - struct addrinfo *ai; /* * Connecting with IPv6 support is so much easier and cleanly done */ - port =0; /* we already have port in the 'remotehost' struct */ - - for (ai = remotehost; ai; ai = ai->ai_next, aliasindex++) { - sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sockfd < 0) - continue; + { + struct addrinfo *ai; - /* set socket non-blocking */ - nonblock(sockfd, TRUE); + for (ai = remotehost; ai; ai = ai->ai_next, aliasindex++) { + sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sockfd < 0) + continue; - rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); + /* set socket non-blocking */ + nonblock(sockfd, TRUE); - if(0 == rc) - /* direct connect, awesome! */ - break; - - /* asynchronous connect, wait for connect or timeout */ - rc = waitconnect(sockfd, timeout_ms); - if(0 != rc) { - /* connect failed or timed out */ - sclose(sockfd); - sockfd = -1; + rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); - /* get a new timeout for next attempt */ - after = Curl_tvnow(); - timeout_ms -= (long)(Curl_tvdiff(after, before)*1000); - if(timeout_ms < 0) + if(-1 == rc) { + int error; +#ifdef WIN32 + error = (int)GetLastError(); +#else + error = errno; +#endif + 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 + case EINTR: + + /* asynchronous connect, wait for connect or timeout */ + rc = waitconnect(sockfd, timeout_ms); + break; + case ECONNREFUSED: /* no one listening */ + default: + /* unknown error, fallthrough and try another address! */ + failf(data, "Failed to connect to IP number %d", aliasindex+1); + break; + } + } + if(0 == rc) + /* direct connect, awesome! */ break; - before = after; - continue; + + else { + /* connect failed or timed out */ + sclose(sockfd); + sockfd = -1; + + /* get a new timeout for next attempt */ + after = Curl_tvnow(); + timeout_ms -= (long)(Curl_tvdiff(after, before)*1000); + if(timeout_ms < 0) { + failf(data, "connect() timed out!"); + return CURLE_OPERATION_TIMEOUTED; + } + before = after; + continue; + } + } + if (sockfd < 0) { + failf(data, "connect() failed"); + return CURLE_COULDNT_CONNECT; } /* now disable the non-blocking mode again */ nonblock(sockfd, FALSE); - break; - } - if (sockfd < 0) { - failf(data, strerror(errno)); - return CURLE_COULDNT_CONNECT; - } - - if(addr) - *addr = ai; /* the address we ended up connected to */ + if(addr) + *addr = ai; /* the address we ended up connected to */ + } #else /* * Connecting with IPv4-only support -- cgit v1.2.3