Peter Sylvester found a flaw in the connect code for ipv6-enabled hosts.
I guess it seldomly happens on linux and that's why it wasn't found before. He used Solaris to notice it. I took the opportunity to rewrite the Curl_connecthost() slightly to feature less duplicate code in the two different versions (ipv4/ipv6).
This commit is contained in:
parent
b9d3c71178
commit
43bb20461f
16
CHANGES
16
CHANGES
@ -7,6 +7,22 @@
|
|||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
|
||||||
|
Daniel (13 November)
|
||||||
|
- Default Content-Type for parts in multipart formposts has changed to
|
||||||
|
"application/octet-stream". This seems more appropriate, and I believe
|
||||||
|
mozilla and the likes do this. In the same area: .html files now get
|
||||||
|
text/html as Content-Type. (Pointed out in bug report #839806)
|
||||||
|
|
||||||
|
- Gisle Vanem corrected the --progress-bar output by doing a flush of the
|
||||||
|
output, which apparently makes it look better on at least windows, but
|
||||||
|
possibly other platforms too.
|
||||||
|
|
||||||
|
- Peter Sylvester identified a problem in the connect code, which made the
|
||||||
|
multi interface on a ipv6-enabled solaris box do bad. Test case 504 to be
|
||||||
|
specific. I've spent some time to clean-up the Curl_connecthost() function
|
||||||
|
now to use less duplicated code for the two different sections: ipv6 and
|
||||||
|
ipv4.
|
||||||
|
|
||||||
Daniel (11 November)
|
Daniel (11 November)
|
||||||
- Added CURLOPT_NETRC_FILE. Use this to tell libcurl which file to use instead
|
- Added CURLOPT_NETRC_FILE. Use this to tell libcurl which file to use instead
|
||||||
of trying to find a .netrc in the current user's home directory. The
|
of trying to find a .netrc in the current user's home directory. The
|
||||||
|
186
lib/connect.c
186
lib/connect.c
@ -473,6 +473,10 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
struct timeval after;
|
struct timeval after;
|
||||||
struct timeval before = Curl_tvnow();
|
struct timeval before = Curl_tvnow();
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
struct addrinfo *ai;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Figure out what maximum time we have left
|
* Figure out what maximum time we have left
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
@ -513,118 +517,21 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
}
|
}
|
||||||
|
|
||||||
hostname = data->change.proxy?conn->proxyhost:conn->hostname;
|
hostname = data->change.proxy?conn->proxyhost:conn->hostname;
|
||||||
infof(data, "About to connect() to %s%s%s:%d\n",
|
infof(data, "About to connect() to %s port %d\n",
|
||||||
conn->bits.ipv6_ip?"[":"",
|
hostname, port);
|
||||||
hostname,
|
|
||||||
conn->bits.ipv6_ip?"]":"",
|
|
||||||
port);
|
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
/*
|
/*
|
||||||
* Connecting with IPv6 support is so much easier and cleanly done
|
* Connecting with a getaddrinfo chain
|
||||||
*/
|
*/
|
||||||
{
|
for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
|
||||||
struct addrinfo *ai;
|
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
port =0; /* prevent compiler warning */
|
|
||||||
|
|
||||||
for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
|
|
||||||
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
|
||||||
if (sockfd < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
int 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
|
|
||||||
case EINTR:
|
|
||||||
/* asynchronous connect, wait for connect or timeout */
|
|
||||||
if(data->state.used_interface == Curl_if_multi)
|
|
||||||
/* don't hang when doing multi */
|
|
||||||
timeout_ms = 0;
|
|
||||||
|
|
||||||
rc = waitconnect(sockfd, timeout_ms);
|
|
||||||
break;
|
|
||||||
case ECONNREFUSED: /* no one listening */
|
|
||||||
default:
|
|
||||||
/* unknown error, fallthrough and try another address! */
|
|
||||||
failf(data, "Failed connect to %s: %d", hostname, error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 == rc) {
|
|
||||||
/* we might be connected, if the socket says it is OK! Ask it! */
|
|
||||||
if(verifyconnect(sockfd)) {
|
|
||||||
/* we are connected, awesome! */
|
|
||||||
*connected = TRUE; /* this is truly a connect */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
failf(data, "socket error");
|
|
||||||
/* we are _not_ connected, it was a false alert, continue please */
|
|
||||||
}
|
|
||||||
else if(2 == rc)
|
|
||||||
/* waitconnect() returned error */
|
|
||||||
;
|
|
||||||
else if(data->state.used_interface == Curl_if_multi) {
|
|
||||||
/* When running the multi interface, we bail out here */
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* connect failed or timed out */
|
|
||||||
sclose(sockfd);
|
|
||||||
sockfd = -1;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (sockfd < 0)
|
if (sockfd < 0)
|
||||||
return CURLE_COULDNT_CONNECT;
|
continue;
|
||||||
|
|
||||||
/* leave the socket in non-blocking mode */
|
|
||||||
|
|
||||||
if(addr)
|
|
||||||
*addr = ai; /* the address we ended up connected to */
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* Connecting with IPv4-only support
|
* Connecting with old style IPv4-only support
|
||||||
*/
|
*/
|
||||||
if(!remotehost->addr->h_addr_list[0]) {
|
|
||||||
/* If there is no addresses in the address list, then we return
|
|
||||||
error right away */
|
|
||||||
failf(data, "no address available");
|
|
||||||
return CURLE_COULDNT_CONNECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is the loop that attempts to connect to all IP-addresses we
|
/* This is the loop that attempts to connect to all IP-addresses we
|
||||||
know for the given host. One by one. */
|
know for the given host. One by one. */
|
||||||
@ -639,7 +546,16 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
failf(data, "couldn't create socket");
|
failf(data, "couldn't create socket");
|
||||||
return CURLE_COULDNT_CONNECT; /* big time error */
|
return CURLE_COULDNT_CONNECT; /* big time error */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* nasty address work before connect can be made */
|
||||||
|
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
|
||||||
|
memcpy((char *)&(serv_addr.sin_addr),
|
||||||
|
(struct in_addr *)remotehost->addr->h_addr_list[aliasindex],
|
||||||
|
sizeof(struct in_addr));
|
||||||
|
serv_addr.sin_family = remotehost->addr->h_addrtype;
|
||||||
|
serv_addr.sin_port = htons((unsigned short)port);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(conn->data->set.device) {
|
if(conn->data->set.device) {
|
||||||
/* user selected to bind the outgoing socket to a specified "device"
|
/* user selected to bind the outgoing socket to a specified "device"
|
||||||
before doing connect */
|
before doing connect */
|
||||||
@ -648,19 +564,16 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert socket to non-blocking type */
|
/* set socket non-blocking */
|
||||||
Curl_nonblock(sockfd, TRUE);
|
Curl_nonblock(sockfd, TRUE);
|
||||||
|
|
||||||
/* do this nasty work to do the connect */
|
rc = connect(sockfd,
|
||||||
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
|
#ifdef ENABLE_IPV6
|
||||||
memcpy((char *)&(serv_addr.sin_addr),
|
ai->ai_addr, ai->ai_addrlen
|
||||||
(struct in_addr *)remotehost->addr->h_addr_list[aliasindex],
|
#else
|
||||||
sizeof(struct in_addr));
|
(struct sockaddr *)&serv_addr, sizeof(serv_addr)
|
||||||
serv_addr.sin_family = remotehost->addr->h_addrtype;
|
#endif
|
||||||
serv_addr.sin_port = htons((unsigned short)port);
|
);
|
||||||
|
|
||||||
rc = connect(sockfd, (struct sockaddr *)&serv_addr,
|
|
||||||
sizeof(serv_addr));
|
|
||||||
|
|
||||||
if(-1 == rc) {
|
if(-1 == rc) {
|
||||||
int error=Curl_ourerrno();
|
int error=Curl_ourerrno();
|
||||||
@ -679,7 +592,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
if(data->state.used_interface == Curl_if_multi)
|
if(data->state.used_interface == Curl_if_multi)
|
||||||
/* don't hang when doing multi */
|
/* don't hang when doing multi */
|
||||||
timeout_ms = 0;
|
timeout_ms = 0;
|
||||||
|
|
||||||
rc = waitconnect(sockfd, timeout_ms);
|
rc = waitconnect(sockfd, timeout_ms);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -698,7 +611,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 == rc) {
|
if(0 == rc) {
|
||||||
if (verifyconnect(sockfd)) {
|
if (verifyconnect(sockfd)) {
|
||||||
/* we are connected, awesome! */
|
/* we are connected, awesome! */
|
||||||
@ -709,22 +622,20 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 != rc) {
|
/* connect failed or timed out */
|
||||||
/* get a new timeout for next attempt */
|
sclose(sockfd);
|
||||||
sclose(sockfd);
|
sockfd = -1;
|
||||||
after = Curl_tvnow();
|
|
||||||
timeout_ms -= Curl_tvdiff(after, before);
|
|
||||||
if(timeout_ms < 0) {
|
|
||||||
failf(data, "Connect timeout on IP number %d", aliasindex+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
before = after;
|
|
||||||
continue; /* try next address */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 != rc) {
|
/* 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;
|
||||||
|
}
|
||||||
|
if (sockfd < 0) {
|
||||||
/* no good connect was made */
|
/* no good connect was made */
|
||||||
*sockconn = -1;
|
*sockconn = -1;
|
||||||
failf(data, "Connect failed");
|
failf(data, "Connect failed");
|
||||||
@ -733,10 +644,14 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
|
|
||||||
/* leave the socket in non-blocking mode */
|
/* leave the socket in non-blocking mode */
|
||||||
|
|
||||||
if(addr)
|
/* store the address we use */
|
||||||
/* this is the address we've connected to */
|
if(addr) {
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
*addr = ai;
|
||||||
|
#else
|
||||||
*addr = (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
|
*addr = (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* allow NULL-pointers to get passed in */
|
/* allow NULL-pointers to get passed in */
|
||||||
if(sockconn)
|
if(sockconn)
|
||||||
@ -744,4 +659,3 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user