singleipconnect: simplify and clean up

Remove timeout argument that's never used.

Make the actual connection get detected on a single spot to reduce code
duplication.

Store the IPv6 state already when the connection is attempted.
This commit is contained in:
Daniel Stenberg 2013-02-01 00:17:07 +01:00
Родитель 32e8467a66
Коммит 56b7c87c74
1 изменённых файлов: 49 добавлений и 91 удалений

Просмотреть файл

@ -128,7 +128,6 @@ tcpkeepalive(struct SessionHandle *data,
static CURLcode static CURLcode
singleipconnect(struct connectdata *conn, singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai, /* start connecting to this */ const Curl_addrinfo *ai, /* start connecting to this */
long timeout_ms,
curl_socket_t *sock, curl_socket_t *sock,
bool *connected); bool *connected);
@ -199,20 +198,19 @@ long Curl_timeleft(struct SessionHandle *data,
} }
/* /*
* waitconnect() waits for a TCP connect on the given socket for the specified * checkconnect() checks for a TCP connect on the given socket.
* number if milliseconds. It returns: * It returns:
*/ */
#define WAITCONN_CONNECTED 0 enum chkconn_t {
#define WAITCONN_SELECT_ERROR -1 CHKCONN_SELECT_ERROR = -1,
#define WAITCONN_TIMEOUT 1 CHKCONN_CONNECTED = 0,
#define WAITCONN_FDSET_ERROR 2 CHKCONN_IDLE = 1,
#define WAITCONN_ABORTED 3 CHKCONN_FDSET_ERROR = 2
};
static static enum chkconn_t
int waitconnect(struct connectdata *conn, checkconnect(curl_socket_t sockfd)
curl_socket_t sockfd, /* socket */
long timeout_msec)
{ {
int rc; int rc;
#ifdef mpeix #ifdef mpeix
@ -222,34 +220,20 @@ int waitconnect(struct connectdata *conn,
(void)verifyconnect(sockfd, NULL); (void)verifyconnect(sockfd, NULL);
#endif #endif
for(;;) { rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 0);
/* now select() until we get connect or timeout */ if(-1 == rc)
rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, timeout_msec>1000? /* error, no connect here, try next */
1000:timeout_msec); return CHKCONN_SELECT_ERROR;
if(Curl_pgrsUpdate(conn))
return WAITCONN_ABORTED;
if(-1 == rc) else if(rc & CURL_CSELECT_ERR)
/* error, no connect here, try next */ /* error condition caught */
return WAITCONN_SELECT_ERROR; return CHKCONN_FDSET_ERROR;
else if(0 == rc) { else if(rc)
/* timeout */ return CHKCONN_CONNECTED;
timeout_msec -= 1000;
if(timeout_msec <= 0)
return WAITCONN_TIMEOUT;
continue; return CHKCONN_IDLE;
}
if(rc & CURL_CSELECT_ERR)
/* error condition caught */
return WAITCONN_FDSET_ERROR;
break;
}
return WAITCONN_CONNECTED;
} }
static CURLcode bindlocal(struct connectdata *conn, static CURLcode bindlocal(struct connectdata *conn,
@ -548,7 +532,7 @@ static CURLcode trynextip(struct connectdata *conn,
ai = conn->ip_addr->ai_next; ai = conn->ip_addr->ai_next;
while(ai) { while(ai) {
CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected); CURLcode res = singleipconnect(conn, ai, &sockfd, connected);
if(res) if(res)
return res; return res;
if(sockfd != CURL_SOCKET_BAD) { if(sockfd != CURL_SOCKET_BAD) {
@ -676,21 +660,20 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
} }
/* /*
* Curl_is_connected() is used from the multi interface to check if the * Curl_is_connected() checks if the socket has connected.
* firstsocket has connected.
*/ */
CURLcode Curl_is_connected(struct connectdata *conn, CURLcode Curl_is_connected(struct connectdata *conn,
int sockindex, int sockindex,
bool *connected) bool *connected)
{ {
int rc;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
CURLcode code = CURLE_OK; CURLcode code = CURLE_OK;
curl_socket_t sockfd = conn->sock[sockindex]; curl_socket_t sockfd = conn->sock[sockindex];
long allow = DEFAULT_CONNECT_TIMEOUT; long allow = DEFAULT_CONNECT_TIMEOUT;
int error = 0; int error = 0;
struct timeval now; struct timeval now;
enum chkconn_t chk;
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
@ -713,9 +696,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT; return CURLE_OPERATION_TIMEDOUT;
} }
/* check for connect without timeout as we want to return immediately */ /* check socket for connect */
rc = waitconnect(conn, sockfd, 0); chk = checkconnect(sockfd);
if(WAITCONN_TIMEOUT == rc) { if(CHKCONN_IDLE == chk) {
if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
infof(data, "After %ldms connect time, move on!\n", infof(data, "After %ldms connect time, move on!\n",
conn->timeoutms_per_addr); conn->timeoutms_per_addr);
@ -726,7 +709,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return code; return code;
} }
if(WAITCONN_CONNECTED == rc) { if(CHKCONN_CONNECTED == chk) {
if(verifyconnect(sockfd, &error)) { if(verifyconnect(sockfd, &error)) {
/* we are connected with TCP, awesome! */ /* we are connected with TCP, awesome! */
@ -736,6 +719,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return code; return code;
conn->bits.tcpconnect[sockindex] = TRUE; conn->bits.tcpconnect[sockindex] = TRUE;
*connected = TRUE; *connected = TRUE;
if(sockindex == FIRSTSOCKET) if(sockindex == FIRSTSOCKET)
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
@ -748,7 +732,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
} }
else { else {
/* nope, not connected */ /* nope, not connected */
if(WAITCONN_FDSET_ERROR == rc) { if(CHKCONN_FDSET_ERROR == chk) {
(void)verifyconnect(sockfd, &error); (void)verifyconnect(sockfd, &error);
infof(data, "%s\n",Curl_strerror(conn, error)); infof(data, "%s\n",Curl_strerror(conn, error));
} }
@ -864,12 +848,11 @@ void Curl_sndbufset(curl_socket_t sockfd)
* CURL_SOCKET_BAD. Other errors will however return proper errors. * CURL_SOCKET_BAD. Other errors will however return proper errors.
* *
* singleipconnect() connects to the given IP only, and it may return without * singleipconnect() connects to the given IP only, and it may return without
* having connected if used from the multi interface. * having connected.
*/ */
static CURLcode static CURLcode
singleipconnect(struct connectdata *conn, singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai, const Curl_addrinfo *ai,
long timeout_ms,
curl_socket_t *sockp, curl_socket_t *sockp,
bool *connected) bool *connected)
{ {
@ -940,17 +923,25 @@ singleipconnect(struct connectdata *conn,
/* set socket non-blocking */ /* set socket non-blocking */
curlx_nonblock(sockfd, TRUE); curlx_nonblock(sockfd, TRUE);
conn->connecttime = Curl_tvnow();
if(conn->num_addr > 1)
Curl_expire(data, conn->timeoutms_per_addr);
/* Connect TCP sockets, bind UDP */ /* Connect TCP sockets, bind UDP */
if(!isconnected && (conn->socktype == SOCK_STREAM)) { if(!isconnected && (conn->socktype == SOCK_STREAM)) {
rc = connect(sockfd, &addr.sa_addr, addr.addrlen); rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
if(-1 == rc) if(-1 == rc)
error = SOCKERRNO; error = SOCKERRNO;
conn->connecttime = Curl_tvnow();
if(conn->num_addr > 1)
Curl_expire(data, conn->timeoutms_per_addr);
} }
else else {
rc = 0; rc = 0;
*sockp = sockfd;
return CURLE_OK;
}
#ifdef ENABLE_IPV6
conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
#endif
if(-1 == rc) { if(-1 == rc) {
switch (error) { switch (error) {
@ -965,54 +956,22 @@ singleipconnect(struct connectdata *conn,
case EAGAIN: case EAGAIN:
#endif #endif
#endif #endif
rc = waitconnect(conn, sockfd, timeout_ms); *sockp = sockfd;
if(WAITCONN_ABORTED == rc) { return CURLE_OK;
Curl_closesocket(conn, sockfd);
return CURLE_ABORTED_BY_CALLBACK;
}
break;
default: default:
/* unknown error, fallthrough and try another address! */ /* unknown error, fallthrough and try another address! */
failf(data, "Failed to connect to %s: %s", failf(data, "Failed to connect to %s: %s",
conn->ip_addr_str, Curl_strerror(conn,error)); conn->ip_addr_str, Curl_strerror(conn,error));
data->state.os_errno = error; data->state.os_errno = error;
/* connect failed */
Curl_closesocket(conn, sockfd);
break; 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) {
/* Timeout when running the multi interface */
*sockp = sockfd;
return CURLE_OK;
}
if(!isconnected)
isconnected = verifyconnect(sockfd, &error);
if(!rc && isconnected) {
/* we are connected, awesome! */
*connected = TRUE; /* this is a true connect */
infof(data, "connected\n");
#ifdef ENABLE_IPV6
conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
#endif
Curl_updateconninfo(conn, sockfd);
*sockp = sockfd;
return CURLE_OK;
}
else if(WAITCONN_TIMEOUT == rc)
infof(data, "Timeout\n");
else {
data->state.os_errno = error;
infof(data, "%s\n", Curl_strerror(conn, error));
}
/* connect failed or timed out */
Curl_closesocket(conn, sockfd);
return CURLE_OK; return CURLE_OK;
} }
@ -1073,7 +1032,6 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* start connecting to the IP curr_addr points to */ /* start connecting to the IP curr_addr points to */
res = singleipconnect(conn, curr_addr, res = singleipconnect(conn, curr_addr,
0, /* don't hang when doing multi */
&sockfd, connected); &sockfd, connected);
if(res) if(res)
return res; return res;