aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/connect.c298
-rw-r--r--lib/connect.h2
-rw-r--r--lib/ftp.c5
-rw-r--r--lib/multi.c13
-rw-r--r--lib/url.c8
-rw-r--r--lib/urldata.h2
6 files changed, 164 insertions, 164 deletions
diff --git a/lib/connect.c b/lib/connect.c
index c442c48f8..4bf0232f9 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -233,45 +233,6 @@ long Curl_timeleft(struct SessionHandle *data,
return timeout_ms;
}
-/*
- * checkconnect() checks for a TCP connect on the given socket.
- * It returns:
- */
-
-enum chkconn_t {
- CHKCONN_SELECT_ERROR = -1,
- CHKCONN_CONNECTED = 0,
- CHKCONN_IDLE = 1,
- CHKCONN_FDSET_ERROR = 2
-};
-
-static enum chkconn_t
-checkconnect(curl_socket_t sockfd)
-{
- int rc;
-#ifdef mpeix
- /* Call this function once now, and ignore the results. We do this to
- "clear" the error state on the socket so that we can later read it
- reliably. This is reported necessary on the MPE/iX operating system. */
- (void)verifyconnect(sockfd, NULL);
-#endif
-
- rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 0);
-
- if(-1 == rc)
- /* error, no connect here, try next */
- return CHKCONN_SELECT_ERROR;
-
- else if(rc & CURL_CSELECT_ERR)
- /* error condition caught */
- return CHKCONN_FDSET_ERROR;
-
- else if(rc)
- return CHKCONN_CONNECTED;
-
- return CHKCONN_IDLE;
-}
-
static CURLcode bindlocal(struct connectdata *conn,
curl_socket_t sockfd, int af)
{
@@ -573,17 +534,19 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
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->sock[sockindex];
- conn->sock[sockindex] = CURL_SOCKET_BAD;
+ curl_socket_t fd_to_close = conn->tempsock[tempindex];
+ conn->tempsock[tempindex] = CURL_SOCKET_BAD;
*connected = FALSE;
if(sockindex != FIRSTSOCKET) {
@@ -591,21 +554,26 @@ static CURLcode trynextip(struct connectdata *conn,
return CURLE_COULDNT_CONNECT; /* no next */
}
- /* try the next address */
- ai = conn->ip_addr->ai_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) {
+ 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->sock[sockindex] = sockfd;
- conn->ip_addr = ai;
+ conn->tempsock[tempindex] = sockfd;
+ conn->tempaddr[tempindex] = ai;
Curl_closesocket(conn, fd_to_close);
return CURLE_OK;
}
- ai = ai->ai_next;
+
+ do {
+ ai = ai->ai_next;
+ } while(ai && ai->ai_family == family);
}
Curl_closesocket(conn, fd_to_close);
return CURLE_COULDNT_CONNECT;
@@ -707,6 +675,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
error, Curl_strerror(conn, error));
return;
}
+ memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
if(!getaddressinfo((struct sockaddr*)&ssloc,
conn->local_ip, &conn->local_port)) {
@@ -732,11 +701,11 @@ CURLcode Curl_is_connected(struct connectdata *conn,
{
struct SessionHandle *data = conn->data;
CURLcode code = CURLE_OK;
- curl_socket_t sockfd = conn->sock[sockindex];
long allow = DEFAULT_CONNECT_TIMEOUT;
int error = 0;
struct timeval now;
- enum chkconn_t chk;
+ int result;
+ int i;
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
@@ -759,69 +728,94 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
- /* check socket for connect */
- chk = checkconnect(sockfd);
- if(CHKCONN_IDLE == chk) {
- if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
- infof(data, "After %ldms connect time, move on!\n",
- conn->timeoutms_per_addr);
- goto next;
- }
+ for(i=0; i<2; i++) {
+ if(conn->tempsock[i] == CURL_SOCKET_BAD)
+ continue;
- /* not an error, but also no connection yet */
- return code;
- }
+#ifdef mpeix
+ /* Call this function once now, and ignore the results. We do this to
+ "clear" the error state on the socket so that we can later read it
+ reliably. This is reported necessary on the MPE/iX operating system. */
+ (void)verifyconnect(conn->tempsock[i], NULL);
+#endif
+
+ /* check socket for connect */
+ result = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);
+
+ switch(result) {
+ case 0: /* no connection yet */
+ if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
+ infof(data, "After %ldms connect time, move on!\n",
+ conn->timeoutms_per_addr);
+ break;
+ }
+ return CURLE_OK;
+
+ case CURL_CSELECT_OUT:
+ if(verifyconnect(conn->tempsock[i], &error)) {
+ /* we are connected with TCP, awesome! */
+ int other = i ^ 1;
+
+ /* use this socket from now on */
+ conn->sock[sockindex] = conn->tempsock[i];
+ conn->ip_addr = conn->tempaddr[i];
+
+ /* close the other socket, if open */
+ if(conn->tempsock[other] != CURL_SOCKET_BAD) {
+ if(conn->fclosesocket)
+ conn->fclosesocket(conn->closesocket_client,
+ conn->tempsock[other]);
+ else
+ sclose(conn->tempsock[other]);
+ }
- if(CHKCONN_CONNECTED == chk) {
- if(verifyconnect(sockfd, &error)) {
- /* we are connected with TCP, awesome! */
+ /* see if we need to do any proxy magic first once we connected */
+ code = Curl_connected_proxy(conn, sockindex);
+ if(code)
+ return code;
- /* see if we need to do any proxy magic first once we connected */
- code = Curl_connected_proxy(conn, sockindex);
- if(code)
- return code;
+ conn->bits.tcpconnect[sockindex] = TRUE;
- conn->bits.tcpconnect[sockindex] = TRUE;
+ *connected = TRUE;
+ if(sockindex == FIRSTSOCKET)
+ Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+ Curl_updateconninfo(conn, conn->sock[sockindex]);
+ Curl_verboseconnect(conn);
- *connected = TRUE;
- if(sockindex == FIRSTSOCKET)
- Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
- Curl_verboseconnect(conn);
- Curl_updateconninfo(conn, sockfd);
+ return CURLE_OK;
+ }
+ else
+ infof(data, "Connection failed\n");
+ break;
+ case CURL_CSELECT_ERR|CURL_CSELECT_OUT:
+ (void)verifyconnect(conn->tempsock[i], &error);
+ break;
+
+ default:
+ infof(data, "Whut?\n");
return CURLE_OK;
}
- /* nope, not connected for real */
- }
- else {
- /* nope, not connected */
- if(CHKCONN_FDSET_ERROR == chk) {
- (void)verifyconnect(sockfd, &error);
- infof(data, "%s\n",Curl_strerror(conn, error));
- }
- else
- infof(data, "Connection failed\n");
- }
- /*
- * The connection failed here, we should attempt to connect to the "next
- * address" for the given host. But first remember the latest error.
- */
- if(error) {
- data->state.os_errno = error;
- SET_SOCKERRNO(error);
- }
- next:
+ /*
+ * The connection failed here, we should attempt to connect to the "next
+ * address" for the given host. But first remember the latest error.
+ */
+ if(error) {
+ data->state.os_errno = error;
+ SET_SOCKERRNO(error);
+ }
- conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
- allow : allow / 2;
- code = trynextip(conn, sockindex, connected);
+ conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
+ allow : allow / 2;
+ code = trynextip(conn, sockindex, i, 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));
+ 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));
+ }
}
return code;
@@ -948,6 +942,8 @@ singleipconnect(struct connectdata *conn,
struct SessionHandle *data = conn->data;
curl_socket_t sockfd;
CURLcode res = CURLE_OK;
+ char ipaddress[MAX_IPADR_LEN];
+ long port;
*sockp = CURL_SOCKET_BAD;
*connected = FALSE; /* default is not connected */
@@ -961,7 +957,7 @@ singleipconnect(struct connectdata *conn,
/* store remote address and port used in this connection attempt */
if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
- conn->primary_ip, &conn->primary_port)) {
+ ipaddress, &port)) {
/* malformed address or bug in inet_ntop, try next address */
error = ERRNO;
failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
@@ -969,10 +965,7 @@ singleipconnect(struct connectdata *conn,
Curl_closesocket(conn, sockfd);
return CURLE_OK;
}
- memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
- infof(data, " Trying %s...\n", conn->ip_addr_str);
-
- Curl_persistconninfo(conn);
+ infof(data, " Trying %s...\n", ipaddress);
if(data->set.tcp_nodelay)
tcpnodelay(conn, sockfd);
@@ -1074,24 +1067,18 @@ singleipconnect(struct connectdata *conn,
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;
- Curl_addrinfo *ai;
- Curl_addrinfo *curr_addr;
-
struct timeval after;
struct timeval before = Curl_tvnow();
+ int i;
/*************************************************************
* Figure out what maximum time we have left
*************************************************************/
long timeout_ms;
- DEBUGASSERT(sockconn);
*connected = FALSE; /* default to not connected */
/* get the timeout left */
@@ -1104,45 +1091,62 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
}
conn->num_addr = Curl_num_addresses(remotehost->addr);
-
- ai = 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 until one IP succeeds.
+ * know for the given host.
+ * One by one, for each protocol, until one IP succeeds.
*/
- /*
- * Connecting with a Curl_addrinfo chain
- */
- for(curr_addr = ai; curr_addr; curr_addr = curr_addr->ai_next) {
- CURLcode res;
-
- /* Max time for the next address */
- conn->timeoutms_per_addr = curr_addr->ai_next == NULL ?
- timeout_ms : timeout_ms / 2;
-
- /* start connecting to the IP curr_addr points to */
- res = singleipconnect(conn, curr_addr,
- &sockfd, connected);
- if(res)
- return res;
-
- if(sockfd != CURL_SOCKET_BAD)
- break;
+ 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;
- /* 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 */
+ /* next addresses */
+ do {
+ ai = ai->ai_next;
+ } while(ai && ai->ai_family != family);
+ } /* end of connect-to-each-address loop */
- *sockconn = sockfd; /* the socket descriptor we've connected */
+ conn->tempsock[i] = sockfd;
+ conn->tempaddr[i] = ai;
+ }
- if(sockfd == CURL_SOCKET_BAD) {
+ 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",
@@ -1152,10 +1156,6 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* 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;
diff --git a/lib/connect.h b/lib/connect.h
index ab9800289..526ce37a0 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -33,8 +33,6 @@ CURLcode Curl_is_connected(struct connectdata *conn,
CURLcode Curl_connecthost(struct connectdata *conn,
const struct Curl_dns_entry *host, /* connect to
this */
- curl_socket_t *sockconn, /* not set if error */
- Curl_addrinfo **addr, /* the one we used */
bool *connected); /* truly connected? */
/* generic function that returns how much time there's left to run, according
diff --git a/lib/ftp.c b/lib/ftp.c
index e66a8a808..46ec8a6f6 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1881,7 +1881,6 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
struct ftp_conn *ftpc = &conn->proto.ftpc;
CURLcode result;
struct SessionHandle *data=conn->data;
- Curl_addrinfo *conninfo;
struct Curl_dns_entry *addr=NULL;
int rc;
unsigned short connectport; /* the local port connect() should use! */
@@ -2041,8 +2040,6 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
result = Curl_connecthost(conn,
addr,
- &conn->sock[SECONDARYSOCKET],
- &conninfo,
&connected);
Curl_resolv_unlock(data, addr); /* we're done using this address */
@@ -2064,7 +2061,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
if(data->set.verbose)
/* this just dumps information about this second connection */
- ftp_pasv_verbose(conn, conninfo, ftpc->newhost, connectport);
+ ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
if(connected) {
/* Only do the proxy connection magic if we're actually connected. We do
diff --git a/lib/multi.c b/lib/multi.c
index e723a3ebf..f11ba069b 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -621,17 +621,26 @@ static int waitconnect_getsock(struct connectdata *conn,
curl_socket_t *sock,
int numsocks)
{
+ int i;
+ int s=0;
+ int rc=0;
+
if(!numsocks)
return GETSOCK_BLANK;
- sock[0] = conn->sock[FIRSTSOCKET];
+ for(i=0; i<2; i++) {
+ if(conn->tempsock[i] != CURL_SOCKET_BAD) {
+ sock[s] = conn->tempsock[i];
+ rc |= GETSOCK_WRITESOCK(s++);
+ }
+ }
/* when we've sent a CONNECT to a proxy, we should rather wait for the
socket to become readable to be able to get the response headers */
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
return GETSOCK_READSOCK(0);
- return GETSOCK_WRITESOCK(0);
+ return rc;
}
static int domore_getsock(struct connectdata *conn,
diff --git a/lib/url.c b/lib/url.c
index 9973bd273..e86fbc252 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -3260,7 +3260,6 @@ static CURLcode ConnectPlease(struct SessionHandle *data,
bool *connected)
{
CURLcode result;
- Curl_addrinfo *addr;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name;
@@ -3276,13 +3275,8 @@ static CURLcode ConnectPlease(struct SessionHandle *data,
*************************************************************/
result= Curl_connecthost(conn,
conn->dns_entry,
- &conn->sock[FIRSTSOCKET],
- &addr,
connected);
if(CURLE_OK == result) {
- /* All is cool, we store the current information */
- conn->ip_addr = addr;
-
if(*connected) {
result = Curl_connected_proxy(conn, FIRSTSOCKET);
if(!result) {
@@ -5643,8 +5637,8 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
*protocol_done = TRUE;
- Curl_verboseconnect(conn);
Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
+ Curl_verboseconnect(conn);
}
/* Stop the loop now */
break;
diff --git a/lib/urldata.h b/lib/urldata.h
index ebaaf6ff4..98686bb33 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -838,6 +838,7 @@ struct connectdata {
within the DNS cache, so this pointer is only valid as long as the DNS
cache entry remains locked. It gets unlocked in Curl_done() */
Curl_addrinfo *ip_addr;
+ Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */
/* 'ip_addr_str' is the ip_addr data as a human readable string.
It remains available as long as the connection does, which is longer than
@@ -889,6 +890,7 @@ struct connectdata {
struct timeval created; /* creation time */
curl_socket_t sock[2]; /* two sockets, the second is used for the data
transfer when doing FTP */
+ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */
bool sock_accepted[2]; /* TRUE if the socket on this index was created with
accept() */
Curl_recv *recv[2];