aboutsummaryrefslogtreecommitdiff
path: root/lib/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/multi.c')
-rw-r--r--lib/multi.c860
1 files changed, 445 insertions, 415 deletions
diff --git a/lib/multi.c b/lib/multi.c
index 4cc7c5ae6..f307d63b9 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -5,11 +5,11 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
- * are also available at https://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
@@ -69,7 +69,7 @@
#define CURL_MULTI_HANDLE 0x000bab1e
#define GOOD_MULTI_HANDLE(x) \
- ((x) && (x)->type == CURL_MULTI_HANDLE)
+ ((x) && (x)->magic == CURL_MULTI_HANDLE)
static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data);
@@ -83,19 +83,19 @@ static void process_pending_handles(struct Curl_multi *multi);
#ifdef DEBUGBUILD
static const char * const statename[]={
"INIT",
- "CONNECT_PEND",
+ "PENDING",
"CONNECT",
- "WAITRESOLVE",
- "WAITCONNECT",
- "WAITPROXYCONNECT",
- "SENDPROTOCONNECT",
+ "RESOLVING",
+ "CONNECTING",
+ "TUNNELING",
"PROTOCONNECT",
+ "PROTOCONNECTING",
"DO",
"DOING",
- "DO_MORE",
- "DO_DONE",
- "PERFORM",
- "TOOFAST",
+ "DOING_MORE",
+ "DID",
+ "PERFORMING",
+ "RATELIMITING",
"DONE",
"COMPLETED",
"MSGSENT",
@@ -105,7 +105,14 @@ static const char * const statename[]={
/* function pointer called once when switching TO a state */
typedef void (*init_multistate_func)(struct Curl_easy *data);
-static void Curl_init_completed(struct Curl_easy *data)
+/* called in DID state, before PERFORMING state */
+static void before_perform(struct Curl_easy *data)
+{
+ data->req.chunk = FALSE;
+ Curl_pgrsTime(data, TIMER_PRETRANSFER);
+}
+
+static void init_completed(struct Curl_easy *data)
{
/* this is a completed transfer */
@@ -123,23 +130,23 @@ static void mstate(struct Curl_easy *data, CURLMstate state
)
{
CURLMstate oldstate = data->mstate;
- static const init_multistate_func finit[CURLM_STATE_LAST] = {
+ static const init_multistate_func finit[MSTATE_LAST] = {
NULL, /* INIT */
- NULL, /* CONNECT_PEND */
+ NULL, /* PENDING */
Curl_init_CONNECT, /* CONNECT */
- NULL, /* WAITRESOLVE */
- NULL, /* WAITCONNECT */
- NULL, /* WAITPROXYCONNECT */
- NULL, /* SENDPROTOCONNECT */
+ NULL, /* RESOLVING */
+ NULL, /* CONNECTING */
+ NULL, /* TUNNELING */
NULL, /* PROTOCONNECT */
+ NULL, /* PROTOCONNECTING */
Curl_connect_free, /* DO */
NULL, /* DOING */
- NULL, /* DO_MORE */
- NULL, /* DO_DONE */
- NULL, /* PERFORM */
- NULL, /* TOOFAST */
+ NULL, /* DOING_MORE */
+ before_perform, /* DID */
+ NULL, /* PERFORMING */
+ NULL, /* RATELIMITING */
NULL, /* DONE */
- Curl_init_completed, /* COMPLETED */
+ init_completed, /* COMPLETED */
NULL /* MSGSENT */
};
@@ -154,21 +161,21 @@ static void mstate(struct Curl_easy *data, CURLMstate state
data->mstate = state;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
- data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate >= MSTATE_PENDING &&
+ data->mstate < MSTATE_COMPLETED) {
long connection_id = -5000;
if(data->conn)
connection_id = data->conn->connection_id;
infof(data,
- "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
+ "STATE: %s => %s handle %p; line %d (connection #%ld)",
statename[oldstate], statename[data->mstate],
(void *)data, lineno, connection_id);
}
#endif
- if(state == CURLM_STATE_COMPLETED) {
+ if(state == MSTATE_COMPLETED) {
/* changing to COMPLETED means there's one less easy handle 'alive' */
DEBUGASSERT(data->multi->num_alive > 0);
data->multi->num_alive--;
@@ -193,8 +200,8 @@ struct Curl_sh_entry {
struct Curl_hash transfers; /* hash of transfers using this socket */
unsigned int action; /* what combined action READ/WRITE this socket waits
for */
- void *socketp; /* settable by users with curl_multi_assign() */
unsigned int users; /* number of transfers using this */
+ void *socketp; /* settable by users with curl_multi_assign() */
unsigned int readers; /* this many transfers want to read */
unsigned int writers; /* this many transfers want to write */
};
@@ -353,7 +360,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
if(!multi)
return NULL;
- multi->type = CURL_MULTI_HANDLE;
+ multi->magic = CURL_MULTI_HANDLE;
if(Curl_mk_dnscache(&multi->hostcache))
goto error;
@@ -446,7 +453,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->set.errorbuffer[0] = 0;
/* set the easy handle */
- multistate(data, CURLM_STATE_INIT);
+ multistate(data, MSTATE_INIT);
/* for multi interface connections, we share DNS cache automatically if the
easy handle's one is currently not set. */
@@ -555,16 +562,14 @@ static CURLcode multi_done(struct Curl_easy *data,
struct connectdata *conn = data->conn;
unsigned int i;
- DEBUGF(infof(data, "multi_done\n"));
+ DEBUGF(infof(data, "multi_done"));
if(data->state.done)
/* Stop if multi_done() has already been called */
return CURLE_OK;
- conn->data = data; /* ensure the connection uses this transfer now */
-
/* Stop the resolver and free its own resources (but not dns_entry yet). */
- Curl_resolver_kill(conn);
+ Curl_resolver_kill(data);
/* Cleanup possible redirect junk */
Curl_safefree(data->req.newurl);
@@ -585,14 +590,14 @@ static CURLcode multi_done(struct Curl_easy *data,
/* this calls the protocol-specific function pointer previously set */
if(conn->handler->done)
- result = conn->handler->done(conn, status, premature);
+ result = conn->handler->done(data, status, premature);
else
result = status;
if(CURLE_ABORTED_BY_CALLBACK != result) {
/* avoid this if we already aborted by callback to avoid this calling
another callback */
- CURLcode rc = Curl_pgrsDone(conn);
+ CURLcode rc = Curl_pgrsDone(data);
if(!result && rc)
result = CURLE_ABORTED_BY_CALLBACK;
}
@@ -603,16 +608,13 @@ static CURLcode multi_done(struct Curl_easy *data,
Curl_detach_connnection(data);
if(CONN_INUSE(conn)) {
/* Stop if still used. */
- /* conn->data must not remain pointing to this transfer since it is going
- away! Find another to own it! */
- conn->data = conn->easyq.head->ptr;
CONNCACHE_UNLOCK(data);
DEBUGF(infof(data, "Connection still in use %zu, "
- "no more multi_done now!\n",
+ "no more multi_done now!",
conn->easyq.size));
return CURLE_OK;
}
- conn->data = NULL; /* the connection now has no owner */
+
data->state.done = TRUE; /* called just now! */
if(conn->dns_entry) {
@@ -685,7 +687,7 @@ static CURLcode multi_done(struct Curl_easy *data,
if(Curl_conncache_return_conn(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect_id = conn->connection_id;
- infof(data, "%s\n", buffer);
+ infof(data, "%s", buffer);
}
else
data->state.lastconnect_id = -1;
@@ -696,22 +698,17 @@ static CURLcode multi_done(struct Curl_easy *data,
return result;
}
-static int close_connect_only(struct connectdata *conn, void *param)
+static int close_connect_only(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
{
- struct Curl_easy *data = param;
-
+ (void)param;
if(data->state.lastconnect_id != conn->connection_id)
return 0;
- if(conn->data != data)
- return 1;
- conn->data = NULL;
-
if(!conn->bits.connect_only)
return 1;
connclose(conn, "Removing connect-only easy handle");
- conn->bits.connect_only = FALSE;
return 1;
}
@@ -721,7 +718,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
{
struct Curl_easy *easy = data;
bool premature;
- bool easy_owns_conn;
struct Curl_llist_element *e;
/* First, make some basic checks that the CURLM handle is a good handle */
@@ -743,9 +739,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
- easy_owns_conn = (data->conn && (data->conn->data == easy)) ?
- TRUE : FALSE;
+ premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE;
/* If the 'state' is not INIT or COMPLETED, we might need to do something
nice to put the easy_handle in a good known state when this returns. */
@@ -756,28 +750,20 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
}
if(data->conn &&
- data->mstate > CURLM_STATE_DO &&
- data->mstate < CURLM_STATE_COMPLETED) {
+ data->mstate > MSTATE_DO &&
+ data->mstate < MSTATE_COMPLETED) {
/* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
- data->conn->data = easy;
streamclose(data->conn, "Removed with partial response");
- easy_owns_conn = TRUE;
}
if(data->conn) {
+ /* multi_done() clears the association between the easy handle and the
+ connection.
- /* we must call multi_done() here (if we still own the connection) so that
- we don't leave a half-baked one around */
- if(easy_owns_conn) {
-
- /* multi_done() clears the association between the easy handle and the
- connection.
-
- Note that this ignores the return code simply because there's
- nothing really useful to do with it anyway! */
- (void)multi_done(data, data->result, premature);
- }
+ Note that this ignores the return code simply because there's
+ nothing really useful to do with it anyway! */
+ (void)multi_done(data, data->result, premature);
}
/* The timer must be shut down before data->multi is set to NULL, else the
@@ -805,7 +791,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* change state without using multistate(), only to make singlesocket() do
what we want */
- data->mstate = CURLM_STATE_COMPLETED;
+ data->mstate = MSTATE_COMPLETED;
singlesocket(multi, easy); /* to let the application know what sockets that
vanish with this handle */
@@ -815,7 +801,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
if(data->state.lastconnect_id != -1) {
/* Mark any connect-only connection for closure */
Curl_conncache_foreach(data, data->state.conn_cache,
- data, &close_connect_only);
+ NULL, close_connect_only);
}
#ifdef USE_LIBPSL
@@ -843,6 +829,17 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
}
}
+ /* Remove from the pending list if it is there. Otherwise this will
+ remain on the pending list forever due to the state change. */
+ for(e = multi->pending.head; e; e = e->next) {
+ struct Curl_easy *curr_data = e->ptr;
+
+ if(curr_data == data) {
+ Curl_llist_remove(&multi->pending, e, NULL);
+ break;
+ }
+ }
+
/* make the previous node point to our next */
if(data->prev)
data->prev->next = data->next;
@@ -859,6 +856,8 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
We do not touch the easy handle here! */
multi->num_easy--; /* one less to care about now */
+ process_pending_handles(multi);
+
Curl_update_timer(multi);
return CURLM_OK;
}
@@ -878,8 +877,10 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi)
void Curl_detach_connnection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
- if(conn)
+ if(conn) {
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
+ Curl_ssl_detach_conn(data, conn);
+ }
data->conn = NULL;
}
@@ -896,6 +897,9 @@ void Curl_attach_connnection(struct Curl_easy *data,
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
+ if(conn->handler->attach)
+ conn->handler->attach(data, conn);
+ Curl_ssl_associate_conn(data, conn);
}
static int waitconnect_getsock(struct connectdata *conn,
@@ -908,7 +912,7 @@ static int waitconnect_getsock(struct connectdata *conn,
#ifdef USE_SSL
#ifndef CURL_DISABLE_PROXY
if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- return Curl_ssl_getsock(conn, sock);
+ return Curl_ssl->getsock(conn, sock);
#endif
#endif
@@ -936,35 +940,36 @@ static int waitproxyconnect_getsock(struct connectdata *conn,
{
sock[0] = conn->sock[FIRSTSOCKET];
- /* 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->connect_state)
- return GETSOCK_READSOCK(0);
+ return Curl_connect_getsock(conn);
return GETSOCK_WRITESOCK(0);
}
-static int domore_getsock(struct connectdata *conn,
+static int domore_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
curl_socket_t *socks)
{
if(conn && conn->handler->domore_getsock)
- return conn->handler->domore_getsock(conn, socks);
+ return conn->handler->domore_getsock(data, conn, socks);
return GETSOCK_BLANK;
}
-static int doing_getsock(struct connectdata *conn,
+static int doing_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
curl_socket_t *socks)
{
if(conn && conn->handler->doing_getsock)
- return conn->handler->doing_getsock(conn, socks);
+ return conn->handler->doing_getsock(data, conn, socks);
return GETSOCK_BLANK;
}
-static int protocol_getsock(struct connectdata *conn,
+static int protocol_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
curl_socket_t *socks)
{
if(conn->handler->proto_getsock)
- return conn->handler->proto_getsock(conn, socks);
+ return conn->handler->proto_getsock(data, conn, socks);
/* Backup getsock logic. Since there is a live socket in use, we must wait
for it or it will be removed from watching when the multi_socket API is
used. */
@@ -977,47 +982,41 @@ static int protocol_getsock(struct connectdata *conn,
static int multi_getsock(struct Curl_easy *data,
curl_socket_t *socks)
{
+ struct connectdata *conn = data->conn;
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
- if(!data->conn)
+ if(!conn)
return 0;
- if(data->mstate > CURLM_STATE_CONNECT &&
- data->mstate < CURLM_STATE_COMPLETED) {
- /* Set up ownership correctly */
- data->conn->data = data;
- }
-
switch(data->mstate) {
default:
return 0;
- case CURLM_STATE_WAITRESOLVE:
- return Curl_resolv_getsock(data->conn, socks);
+ case MSTATE_RESOLVING:
+ return Curl_resolv_getsock(data, socks);
- case CURLM_STATE_PROTOCONNECT:
- case CURLM_STATE_SENDPROTOCONNECT:
- return protocol_getsock(data->conn, socks);
+ case MSTATE_PROTOCONNECTING:
+ case MSTATE_PROTOCONNECT:
+ return protocol_getsock(data, conn, socks);
- case CURLM_STATE_DO:
- case CURLM_STATE_DOING:
- return doing_getsock(data->conn, socks);
+ case MSTATE_DO:
+ case MSTATE_DOING:
+ return doing_getsock(data, conn, socks);
- case CURLM_STATE_WAITPROXYCONNECT:
- return waitproxyconnect_getsock(data->conn, socks);
+ case MSTATE_TUNNELING:
+ return waitproxyconnect_getsock(conn, socks);
- case CURLM_STATE_WAITCONNECT:
- return waitconnect_getsock(data->conn, socks);
+ case MSTATE_CONNECTING:
+ return waitconnect_getsock(conn, socks);
- case CURLM_STATE_DO_MORE:
- return domore_getsock(data->conn, socks);
+ case MSTATE_DOING_MORE:
+ return domore_getsock(data, conn, socks);
- case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
- to waiting for the same as the *PERFORM
- states */
- case CURLM_STATE_PERFORM:
- return Curl_single_getsock(data->conn, socks);
+ case MSTATE_DID: /* since is set after DO is completed, we switch to
+ waiting for the same as the PERFORMING state */
+ case MSTATE_PERFORMING:
+ return Curl_single_getsock(data, conn, socks);
}
}
@@ -1043,16 +1042,27 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
data = multi->easyp;
while(data) {
- int bitmap = multi_getsock(data, sockbunch);
+ int bitmap;
+#ifdef __clang_analyzer_
+ /* to prevent "The left operand of '>=' is a garbage value" warnings */
+ memset(sockbunch, 0, sizeof(sockbunch));
+#endif
+ bitmap = multi_getsock(data, sockbunch);
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
- if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK(sockbunch[i])) {
+ if(!FDSET_SOCK(sockbunch[i]))
+ /* pretend it doesn't exist */
+ continue;
FD_SET(sockbunch[i], read_fd_set);
s = sockbunch[i];
}
- if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK(sockbunch[i])) {
+ if(!FDSET_SOCK(sockbunch[i]))
+ /* pretend it doesn't exist */
+ continue;
FD_SET(sockbunch[i], write_fd_set);
s = sockbunch[i];
}
@@ -1073,13 +1083,13 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
#define NUM_POLLS_ON_STACK 10
-static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
- struct curl_waitfd extra_fds[],
- unsigned int extra_nfds,
- int timeout_ms,
- int *ret,
- bool extrawait, /* when no socket, wait */
- bool use_wakeup)
+static CURLMcode multi_wait(struct Curl_multi *multi,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret,
+ bool extrawait, /* when no socket, wait */
+ bool use_wakeup)
{
struct Curl_easy *data;
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
@@ -1089,15 +1099,16 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
unsigned int curlfds;
long timeout_internal;
int retcode = 0;
-#ifndef USE_WINSOCK
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct pollfd *ufds = &a_few_on_stack[0];
bool ufds_malloc = FALSE;
-#else
- struct pollfd pre_poll;
+#ifdef USE_WINSOCK
WSANETWORKEVENTS wsa_events;
DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
#endif
+#ifndef ENABLE_WAKEUP
+ (void)use_wakeup;
+#endif
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -1116,11 +1127,11 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
- if(bitmap & GETSOCK_READSOCK(i)) {
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
++nfds;
s = sockbunch[i];
}
- if(bitmap & GETSOCK_WRITESOCK(i)) {
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
++nfds;
s = sockbunch[i];
}
@@ -1152,7 +1163,6 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
}
#endif
-#ifndef USE_WINSOCK
if(nfds > NUM_POLLS_ON_STACK) {
/* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
big, so at 2^29 sockets this value might wrap. When a process gets
@@ -1163,9 +1173,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
return CURLM_OUT_OF_MEMORY;
ufds_malloc = TRUE;
}
-
nfds = 0;
-#endif
/* only do the second loop if we found descriptors in the first stage run
above */
@@ -1181,36 +1189,36 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
#ifdef USE_WINSOCK
long mask = 0;
#endif
- if(bitmap & GETSOCK_READSOCK(i)) {
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ s = sockbunch[i];
#ifdef USE_WINSOCK
- if(timeout_ms && SOCKET_READABLE(sockbunch[i], 0) > 0)
- timeout_ms = 0;
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
-#else
- ufds[nfds].fd = sockbunch[i];
+#endif
+ ufds[nfds].fd = s;
ufds[nfds].events = POLLIN;
++nfds;
-#endif
- s = sockbunch[i];
}
- if(bitmap & GETSOCK_WRITESOCK(i)) {
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ s = sockbunch[i];
#ifdef USE_WINSOCK
- if(timeout_ms && SOCKET_WRITABLE(sockbunch[i], 0) > 0)
- timeout_ms = 0;
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
-#else
- ufds[nfds].fd = sockbunch[i];
+ send(s, NULL, 0, 0); /* reset FD_WRITE */
+#endif
+ ufds[nfds].fd = s;
ufds[nfds].events = POLLOUT;
++nfds;
-#endif
- s = sockbunch[i];
}
+ /* s is only set if either being readable or writable is checked */
if(s == CURL_SOCKET_BAD) {
+ /* break on entry not checked for being readable or writable */
break;
}
#ifdef USE_WINSOCK
- if(WSAEventSelect(s, multi->wsa_event, mask) != 0)
+ if(WSAEventSelect(s, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
return CURLM_INTERNAL_ERROR;
+ }
#endif
}
@@ -1222,35 +1230,20 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
for(i = 0; i < extra_nfds; i++) {
#ifdef USE_WINSOCK
long mask = 0;
- extra_fds[i].revents = 0;
- pre_poll.fd = extra_fds[i].fd;
- pre_poll.events = 0;
- pre_poll.revents = 0;
- if(extra_fds[i].events & CURL_WAIT_POLLIN) {
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
- pre_poll.events |= POLLIN;
- }
- if(extra_fds[i].events & CURL_WAIT_POLLPRI) {
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
mask |= FD_OOB;
- pre_poll.events |= POLLPRI;
- }
if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
- pre_poll.events |= POLLOUT;
+ send(extra_fds[i].fd, NULL, 0, 0); /* reset FD_WRITE */
}
- if(Curl_poll(&pre_poll, 1, 0) > 0) {
- if(pre_poll.revents & POLLIN)
- extra_fds[i].revents |= CURL_WAIT_POLLIN;
- if(pre_poll.revents & POLLPRI)
- extra_fds[i].revents |= CURL_WAIT_POLLPRI;
- if(pre_poll.revents & POLLOUT)
- extra_fds[i].revents |= CURL_WAIT_POLLOUT;
- if(extra_fds[i].revents)
- timeout_ms = 0;
- }
- if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0)
+ if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
return CURLM_INTERNAL_ERROR;
-#else
+ }
+#endif
ufds[nfds].fd = extra_fds[i].fd;
ufds[nfds].events = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN)
@@ -1260,7 +1253,6 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
if(extra_fds[i].events & CURL_WAIT_POLLOUT)
ufds[nfds].events |= POLLOUT;
++nfds;
-#endif
}
#ifdef ENABLE_WAKEUP
@@ -1273,53 +1265,59 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
#endif
#endif
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+ if(nfds || use_wakeup) {
+#else
if(nfds) {
- /* wait... */
+#endif
+ int pollrc;
#ifdef USE_WINSOCK
- WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
+ if(nfds)
+ pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
+ else
+ pollrc = 0;
+ if(pollrc <= 0) /* now wait... if not ready during the pre-check above */
+ WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
#else
- int pollrc = Curl_poll(ufds, nfds, timeout_ms);
+ pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
#endif
-#ifdef USE_WINSOCK
- /* With Winsock, we have to run this unconditionally to call
- WSAEventSelect(fd, event, 0) on all the sockets */
- {
- retcode = 0;
-#else
if(pollrc > 0) {
retcode = pollrc;
+#ifdef USE_WINSOCK
+ }
+ /* With WinSock, we have to run the following section unconditionally
+ to call WSAEventSelect(fd, event, 0) on all the sockets */
+ {
#endif
/* copy revents results from the poll to the curl_multi_wait poll
struct, the bit values of the actual underlying poll() implementation
may not be the same as the ones in the public libcurl API! */
for(i = 0; i < extra_nfds; i++) {
+ unsigned r = ufds[curlfds + i].revents;
unsigned short mask = 0;
#ifdef USE_WINSOCK
wsa_events.lNetworkEvents = 0;
- mask = extra_fds[i].revents;
- if(WSAEnumNetworkEvents(extra_fds[i].fd, multi->wsa_event,
- &wsa_events) == 0) {
+ if(WSAEnumNetworkEvents(extra_fds[i].fd, NULL, &wsa_events) == 0) {
if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
mask |= CURL_WAIT_POLLIN;
if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
mask |= CURL_WAIT_POLLOUT;
if(wsa_events.lNetworkEvents & FD_OOB)
mask |= CURL_WAIT_POLLPRI;
- if(ret && wsa_events.lNetworkEvents != 0)
+ if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
retcode++;
}
WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0);
-#else
- unsigned r = ufds[curlfds + i].revents;
-
+ if(pollrc <= 0)
+ continue;
+#endif
if(r & POLLIN)
mask |= CURL_WAIT_POLLIN;
if(r & POLLOUT)
mask |= CURL_WAIT_POLLOUT;
if(r & POLLPRI)
mask |= CURL_WAIT_POLLPRI;
-#endif
extra_fds[i].revents = mask;
}
@@ -1334,23 +1332,16 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) {
wsa_events.lNetworkEvents = 0;
- if(WSAEnumNetworkEvents(sockbunch[i], multi->wsa_event,
- &wsa_events) == 0) {
- if(ret && wsa_events.lNetworkEvents != 0)
- retcode++;
- }
- if(ret && !timeout_ms && wsa_events.lNetworkEvents == 0) {
- if((bitmap & GETSOCK_READSOCK(i)) &&
- SOCKET_READABLE(sockbunch[i], 0) > 0)
- retcode++;
- else if((bitmap & GETSOCK_WRITESOCK(i)) &&
- SOCKET_WRITABLE(sockbunch[i], 0) > 0)
+ if(WSAEnumNetworkEvents(sockbunch[i], NULL, &wsa_events) == 0) {
+ if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
retcode++;
}
WSAEventSelect(sockbunch[i], multi->wsa_event, 0);
}
- else
+ else {
+ /* break on entry not checked for being readable or writable */
break;
+ }
}
data = data->next;
@@ -1385,16 +1376,15 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
}
}
-#ifndef USE_WINSOCK
if(ufds_malloc)
free(ufds);
-#endif
if(ret)
*ret = retcode;
- if(!extrawait || nfds)
- /* if any socket was checked */
- ;
- else {
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+ if(extrawait && !nfds && !use_wakeup) {
+#else
+ if(extrawait && !nfds) {
+#endif
long sleep_ms = 0;
/* Avoid busy-looping when there's nothing particular to wait for */
@@ -1418,8 +1408,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
int timeout_ms,
int *ret)
{
- return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
- FALSE);
+ return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
+ FALSE);
}
CURLMcode curl_multi_poll(struct Curl_multi *multi,
@@ -1428,8 +1418,8 @@ CURLMcode curl_multi_poll(struct Curl_multi *multi,
int timeout_ms,
int *ret)
{
- return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
- TRUE);
+ return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
+ TRUE);
}
CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
@@ -1460,7 +1450,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
The write socket is set to non-blocking, this way this function
cannot block, making it safe to call even from the same thread
- that will call Curl_multi_wait(). If swrite() returns that it
+ that will call curl_multi_wait(). If swrite() returns that it
would block, it's considered successful because it means that
previous calls to this function will wake up the poll(). */
if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
@@ -1518,25 +1508,13 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
Curl_init_do(data, NULL);
/* take this handle to the perform state right away */
- multistate(data, CURLM_STATE_PERFORM);
+ multistate(data, MSTATE_PERFORMING);
Curl_attach_connnection(data, conn);
k->keepon |= KEEP_RECV; /* setup to receive! */
}
return rc;
}
-/*
- * do_complete is called when the DO actions are complete.
- *
- * We init chunking and trailer bits to their default values here immediately
- * before receiving any header data for the current request.
- */
-static void do_complete(struct connectdata *conn)
-{
- conn->data->req.chunk = FALSE;
- Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
-}
-
static CURLcode multi_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
@@ -1544,16 +1522,11 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
DEBUGASSERT(conn);
DEBUGASSERT(conn->handler);
- DEBUGASSERT(conn->data == data);
- if(conn->handler->do_it) {
+ if(conn->handler->do_it)
/* generic protocol-specific function pointer set in curl_connect() */
- result = conn->handler->do_it(conn, done);
+ result = conn->handler->do_it(data, done);
- if(!result && *done)
- /* do_complete must be called after the protocol-specific DO function */
- do_complete(conn);
- }
return result;
}
@@ -1566,36 +1539,85 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
* DOING state there's more work to do!
*/
-static CURLcode multi_do_more(struct connectdata *conn, int *complete)
+static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
{
CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
*complete = 0;
if(conn->handler->do_more)
- result = conn->handler->do_more(conn, complete);
-
- if(!result && (*complete == 1))
- /* do_complete must be called after the protocol-specific DO function */
- do_complete(conn);
+ result = conn->handler->do_more(data, complete);
return result;
}
/*
+ * Check whether a timeout occurred, and handle it if it did
+ */
+static bool multi_handle_timeout(struct Curl_easy *data,
+ struct curltime *now,
+ bool *stream_error,
+ CURLcode *result,
+ bool connect_timeout)
+{
+ timediff_t timeout_ms;
+ timeout_ms = Curl_timeleft(data, now, connect_timeout);
+
+ if(timeout_ms < 0) {
+ /* Handle timed out */
+ if(data->mstate == MSTATE_RESOLVING)
+ failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
+ else if(data->mstate == MSTATE_CONNECTING)
+ failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
+ else {
+ struct SingleRequest *k = &data->req;
+ if(k->size != -1) {
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount, k->size);
+ }
+ else {
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+ " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount);
+ }
+ }
+
+ /* Force connection closed if the connection has indeed been used */
+ if(data->mstate > MSTATE_DO) {
+ streamclose(data->conn, "Disconnected with pending data");
+ *stream_error = TRUE;
+ }
+ *result = CURLE_OPERATION_TIMEDOUT;
+ (void)multi_done(data, *result, TRUE);
+ }
+
+ return (timeout_ms < 0);
+}
+
+/*
* We are doing protocol-specific connecting and this is being called over and
* over from the multi interface until the connection phase is done on
* protocol layer.
*/
-static CURLcode protocol_connecting(struct connectdata *conn,
- bool *done)
+static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
if(conn && conn->handler->connecting) {
*done = FALSE;
- result = conn->handler->connecting(conn, done);
+ result = conn->handler->connecting(data, done);
}
else
*done = TRUE;
@@ -1608,13 +1630,14 @@ static CURLcode protocol_connecting(struct connectdata *conn,
* until the DOING phase is done on protocol layer.
*/
-static CURLcode protocol_doing(struct connectdata *conn, bool *done)
+static CURLcode protocol_doing(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
if(conn && conn->handler->doing) {
*done = FALSE;
- result = conn->handler->doing(conn, done);
+ result = conn->handler->doing(data, done);
}
else
*done = TRUE;
@@ -1627,11 +1650,11 @@ static CURLcode protocol_doing(struct connectdata *conn, bool *done)
* proceed with some action.
*
*/
-static CURLcode protocol_connect(struct connectdata *conn,
+static CURLcode protocol_connect(struct Curl_easy *data,
bool *protocol_done)
{
CURLcode result = CURLE_OK;
-
+ struct connectdata *conn = data->conn;
DEBUGASSERT(conn);
DEBUGASSERT(protocol_done);
@@ -1652,7 +1675,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
if(!conn->bits.protoconnstart) {
#ifndef CURL_DISABLE_PROXY
- result = Curl_proxy_connect(conn, FIRSTSOCKET);
+ result = Curl_proxy_connect(data, FIRSTSOCKET);
if(result)
return result;
@@ -1670,7 +1693,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
/* is there a protocol-specific connect() procedure? */
/* Call the protocol-specific connect function */
- result = conn->handler->connect_it(conn, protocol_done);
+ result = conn->handler->connect_it(data, protocol_done);
}
else
*protocol_done = TRUE;
@@ -1712,7 +1735,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
timediff_t recv_timeout_ms;
timediff_t send_timeout_ms;
int control;
@@ -1727,84 +1749,55 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_OK;
if(multi_ischanged(multi, TRUE)) {
- DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+ DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!"));
process_pending_handles(multi); /* multiplexed */
}
- if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
- data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate > MSTATE_CONNECT &&
+ data->mstate < MSTATE_COMPLETED) {
/* Make sure we set the connection's current owner */
- data->conn->data = data;
+ DEBUGASSERT(data->conn);
+ if(!data->conn)
+ return CURLM_INTERNAL_ERROR;
}
if(data->conn &&
- (data->mstate >= CURLM_STATE_CONNECT) &&
- (data->mstate < CURLM_STATE_COMPLETED)) {
+ (data->mstate >= MSTATE_CONNECT) &&
+ (data->mstate < MSTATE_COMPLETED)) {
+ /* Check for overall operation timeout here but defer handling the
+ * connection timeout to later, to allow for a connection to be set up
+ * in the window since we last checked timeout. This prevents us
+ * tearing down a completed connection in the case where we were slow
+ * to check the timeout (e.g. process descheduled during this loop).
+ * We set connect_timeout=FALSE to do this. */
+
/* we need to wait for the connect state as only then is the start time
stored, but we must not check already completed handles */
- timeout_ms = Curl_timeleft(data, nowp,
- (data->mstate <= CURLM_STATE_DO)?
- TRUE:FALSE);
-
- if(timeout_ms < 0) {
- /* Handle timed out */
- if(data->mstate == CURLM_STATE_WAITRESOLVE)
- failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*nowp, data->progress.t_startsingle));
- else if(data->mstate == CURLM_STATE_WAITCONNECT)
- failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*nowp, data->progress.t_startsingle));
- else {
- struct SingleRequest *k = &data->req;
- if(k->size != -1) {
- failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
- k->bytecount, k->size);
- }
- else {
- failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds with %" CURL_FORMAT_CURL_OFF_T
- " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
- k->bytecount);
- }
- }
-
- /* Force connection closed if the connection has indeed been used */
- if(data->mstate > CURLM_STATE_DO) {
- streamclose(data->conn, "Disconnected with pending data");
- stream_error = TRUE;
- }
- result = CURLE_OPERATION_TIMEDOUT;
- (void)multi_done(data, result, TRUE);
+ if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
}
switch(data->mstate) {
- case CURLM_STATE_INIT:
+ case MSTATE_INIT:
/* init this transfer. */
result = Curl_pretransfer(data);
if(!result) {
/* after init, go CONNECT */
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
*nowp = Curl_pgrsTime(data, TIMER_STARTOP);
rc = CURLM_CALL_MULTI_PERFORM;
}
break;
- case CURLM_STATE_CONNECT_PEND:
+ case MSTATE_PENDING:
/* We will stay here until there is a connection available. Then
- we try again in the CURLM_STATE_CONNECT state. */
+ we try again in the MSTATE_CONNECT state. */
break;
- case CURLM_STATE_CONNECT:
+ case MSTATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. */
/* init this transfer. */
result = Curl_preconnect(data);
@@ -1822,7 +1815,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
- multistate(data, CURLM_STATE_CONNECT_PEND);
+ multistate(data, MSTATE_PENDING);
/* add this handle to the list of connect-pending handles */
Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
@@ -1832,14 +1825,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else if(data->state.previouslypending) {
/* this transfer comes from the pending queue so try move another */
- infof(data, "Transfer was pending, now try another\n");
+ infof(data, "Transfer was pending, now try another");
process_pending_handles(data->multi);
}
if(!result) {
if(async)
/* We're now waiting for an asynchronous name lookup */
- multistate(data, CURLM_STATE_WAITRESOLVE);
+ multistate(data, MSTATE_RESOLVING);
else {
/* after the connect has been sent off, go WAITCONNECT unless the
protocol connect is already done and we can go directly to
@@ -1847,20 +1840,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connected)
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
if(Curl_connect_ongoing(data->conn))
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ multistate(data, MSTATE_TUNNELING);
else
#endif
- multistate(data, CURLM_STATE_WAITCONNECT);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
break;
- case CURLM_STATE_WAITRESOLVE:
+ case MSTATE_RESOLVING:
/* awaiting an asynch name resolve to complete */
{
struct Curl_dns_entry *dns = NULL;
@@ -1879,19 +1872,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
hostname = conn->host.name;
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+ dns = Curl_fetch_addr(data, hostname, (int)conn->port);
if(dns) {
#ifdef CURLRES_ASYNCH
- conn->async.dns = dns;
- conn->async.done = TRUE;
+ data->state.async.dns = dns;
+ data->state.async.done = TRUE;
#endif
result = CURLE_OK;
- infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
+ infof(data, "Hostname '%s' was found in DNS cache", hostname);
}
if(!dns)
- result = Curl_resolv_check(data->conn, &dns);
+ result = Curl_resolv_check(data, &dns);
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
@@ -1904,7 +1897,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
- result = Curl_once_resolved(data->conn, &protocol_connected);
+ result = Curl_once_resolved(data, &protocol_connected);
if(result)
/* if Curl_once_resolved() returns failure, the connection struct
@@ -1914,14 +1907,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connected)
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
if(Curl_connect_ongoing(data->conn))
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ multistate(data, MSTATE_TUNNELING);
else
#endif
- multistate(data, CURLM_STATE_WAITCONNECT);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
@@ -1935,17 +1928,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
#ifndef CURL_DISABLE_HTTP
- case CURLM_STATE_WAITPROXYCONNECT:
+ case MSTATE_TUNNELING:
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
DEBUGASSERT(data->conn);
- result = Curl_http_connect(data->conn, &protocol_connected);
+ result = Curl_http_connect(data, &protocol_connected);
#ifndef CURL_DISABLE_PROXY
if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
/* connect back to proxy again */
result = CURLE_OK;
multi_done(data, CURLE_OK, FALSE);
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
}
else
#endif
@@ -1958,7 +1951,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_connect_complete(data->conn)) {
rc = CURLM_CALL_MULTI_PERFORM;
/* initiate protocol connect phase */
- multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ multistate(data, MSTATE_PROTOCONNECT);
}
}
else
@@ -1966,10 +1959,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
#endif
- case CURLM_STATE_WAITCONNECT:
+ case MSTATE_CONNECTING:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
- result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
+ result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
#ifndef CURL_DISABLE_HTTP
if(
@@ -1978,7 +1971,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
!data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
#endif
Curl_connect_ongoing(data->conn)) {
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ multistate(data, MSTATE_TUNNELING);
break;
}
#endif
@@ -1986,10 +1979,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_PROXY
multistate(data,
data->conn->bits.tunnel_proxy?
- CURLM_STATE_WAITPROXYCONNECT:
- CURLM_STATE_SENDPROTOCONNECT);
+ MSTATE_TUNNELING : MSTATE_PROTOCONNECT);
#else
- multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ multistate(data, MSTATE_PROTOCONNECT);
#endif
}
else if(result) {
@@ -2001,14 +1993,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_SENDPROTOCONNECT:
- result = protocol_connect(data->conn, &protocol_connected);
+ case MSTATE_PROTOCONNECT:
+ result = protocol_connect(data, &protocol_connected);
if(!result && !protocol_connected)
/* switch to waiting state */
- multistate(data, CURLM_STATE_PROTOCONNECT);
+ multistate(data, MSTATE_PROTOCONNECTING);
else if(!result) {
/* protocol connect has completed, go WAITDO or DO */
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else {
@@ -2019,12 +2011,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_PROTOCONNECT:
+ case MSTATE_PROTOCONNECTING:
/* protocol-specific connect phase */
- result = protocol_connecting(data->conn, &protocol_connected);
+ result = protocol_connecting(data, &protocol_connected);
if(!result && protocol_connected) {
/* after the connect has completed, go WAITDO or DO */
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else if(result) {
@@ -2035,11 +2027,33 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DO:
+ case MSTATE_DO:
+ if(data->set.fprereq) {
+ int prereq_rc;
+
+ /* call the prerequest callback function */
+ Curl_set_in_callback(data, true);
+ prereq_rc = data->set.fprereq(data->set.prereq_userp,
+ data->info.conn_primary_ip,
+ data->info.conn_local_ip,
+ data->info.conn_primary_port,
+ data->info.conn_local_port);
+ Curl_set_in_callback(data, false);
+ if(prereq_rc != CURL_PREREQFUNC_OK) {
+ failf(data, "operation aborted by pre-request callback");
+ /* failure in pre-request callback - don't do any other processing */
+ result = CURLE_ABORTED_BY_CALLBACK;
+ Curl_posttransfer(data);
+ multi_done(data, result, FALSE);
+ stream_error = TRUE;
+ break;
+ }
+ }
+
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
connkeep(data->conn, "CONNECT_ONLY");
- multistate(data, CURLM_STATE_DONE);
+ multistate(data, MSTATE_DONE);
result = CURLE_OK;
rc = CURLM_CALL_MULTI_PERFORM;
}
@@ -2058,7 +2072,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
/* skip some states if it is important */
multi_done(data, CURLE_OK, FALSE);
- multistate(data, CURLM_STATE_DONE);
+
+ /* if there's no connection left, skip the DONE state */
+ multistate(data, data->conn ?
+ MSTATE_DONE : MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
break;
}
@@ -2066,7 +2083,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#endif
/* DO was not completed in one function call, we must continue
DOING... */
- multistate(data, CURLM_STATE_DOING);
+ multistate(data, MSTATE_DOING);
rc = CURLM_OK;
}
@@ -2074,12 +2091,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(data->conn->bits.do_more) {
/* we're supposed to do more, but we need to sit down, relax
and wait a little while first */
- multistate(data, CURLM_STATE_DO_MORE);
+ multistate(data, MSTATE_DOING_MORE);
rc = CURLM_OK;
}
else {
- /* we're done with the DO, now DO_DONE */
- multistate(data, CURLM_STATE_DO_DONE);
+ /* we're done with the DO, now DID */
+ multistate(data, MSTATE_DID);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
@@ -2094,7 +2111,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
followtype follow = FOLLOW_NONE;
CURLcode drc;
- drc = Curl_retry_request(data->conn, &newurl);
+ drc = Curl_retry_request(data, &newurl);
if(drc) {
/* a failure here pretty much implies an out of memory */
result = drc;
@@ -2111,7 +2128,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
if(!drc) {
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
rc = CURLM_CALL_MULTI_PERFORM;
result = CURLE_OK;
}
@@ -2141,16 +2158,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DOING:
+ case MSTATE_DOING:
/* we continue DOING until the DO phase is complete */
DEBUGASSERT(data->conn);
- result = protocol_doing(data->conn, &dophase_done);
+ result = protocol_doing(data, &dophase_done);
if(!result) {
if(dophase_done) {
/* after DO, go DO_DONE or DO_MORE */
multistate(data, data->conn->bits.do_more?
- CURLM_STATE_DO_MORE:
- CURLM_STATE_DO_DONE);
+ MSTATE_DOING_MORE : MSTATE_DID);
rc = CURLM_CALL_MULTI_PERFORM;
} /* dophase_done */
}
@@ -2162,20 +2178,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DO_MORE:
+ case MSTATE_DOING_MORE:
/*
- * When we are connected, DO MORE and then go DO_DONE
+ * When we are connected, DOING MORE and then go DID
*/
DEBUGASSERT(data->conn);
- result = multi_do_more(data->conn, &control);
+ result = multi_do_more(data, &control);
if(!result) {
if(control) {
/* if positive, advance to DO_DONE
if negative, go back to DOING */
multistate(data, control == 1?
- CURLM_STATE_DO_DONE:
- CURLM_STATE_DOING);
+ MSTATE_DID : MSTATE_DOING);
rc = CURLM_CALL_MULTI_PERFORM;
}
else
@@ -2190,7 +2205,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DO_DONE:
+ case MSTATE_DID:
DEBUGASSERT(data->conn);
if(data->conn->bits.multiplex)
/* Check if we can move pending requests to send pipe */
@@ -2200,7 +2215,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Having both BAD is a signal to skip immediately to DONE */
if((data->conn->sockfd != CURL_SOCKET_BAD) ||
(data->conn->writesockfd != CURL_SOCKET_BAD))
- multistate(data, CURLM_STATE_PERFORM);
+ multistate(data, MSTATE_PERFORMING);
else {
#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch &&
@@ -2208,22 +2223,30 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->wildcard.state = CURLWC_DONE;
}
#endif
- multistate(data, CURLM_STATE_DONE);
+ multistate(data, MSTATE_DONE);
}
rc = CURLM_CALL_MULTI_PERFORM;
break;
- case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
+ case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
DEBUGASSERT(data->conn);
/* if both rates are within spec, resume transfer */
- if(Curl_pgrsUpdate(data->conn))
+ if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
result = Curl_speedcheck(data, *nowp);
- if(!result) {
+ if(result) {
+ if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+ result != CURLE_HTTP2_STREAM)
+ streamclose(data->conn, "Transfer returned error");
+
+ Curl_posttransfer(data);
+ multi_done(data, result, TRUE);
+ }
+ else {
send_timeout_ms = 0;
- if(data->set.max_send_speed > 0)
+ if(data->set.max_send_speed)
send_timeout_ms =
Curl_pgrsLimitWaitTime(data->progress.uploaded,
data->progress.ul_limit_size,
@@ -2232,7 +2255,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
*nowp);
recv_timeout_ms = 0;
- if(data->set.max_recv_speed > 0)
+ if(data->set.max_recv_speed)
recv_timeout_ms =
Curl_pgrsLimitWaitTime(data->progress.downloaded,
data->progress.dl_limit_size,
@@ -2241,7 +2264,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
*nowp);
if(!send_timeout_ms && !recv_timeout_ms) {
- multistate(data, CURLM_STATE_PERFORM);
+ multistate(data, MSTATE_PERFORMING);
Curl_ratelimit(data, *nowp);
}
else if(send_timeout_ms >= recv_timeout_ms)
@@ -2251,7 +2274,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_PERFORM:
+ case MSTATE_PERFORMING:
{
char *newurl = NULL;
bool retry = FALSE;
@@ -2259,7 +2282,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
- if(data->set.max_send_speed > 0)
+ if(data->set.max_send_speed)
send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
data->progress.ul_limit_size,
data->set.max_send_speed,
@@ -2268,7 +2291,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* check if over recv speed */
recv_timeout_ms = 0;
- if(data->set.max_recv_speed > 0)
+ if(data->set.max_recv_speed)
recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
data->progress.dl_limit_size,
data->set.max_recv_speed,
@@ -2277,7 +2300,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(send_timeout_ms || recv_timeout_ms) {
Curl_ratelimit(data, *nowp);
- multistate(data, CURLM_STATE_TOOFAST);
+ multistate(data, MSTATE_RATELIMITING);
if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
else
@@ -2293,7 +2316,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* condition and the server closed the re-used connection exactly when
* we wanted to use it, so figure out if that is indeed the case.
*/
- CURLcode ret = Curl_retry_request(data->conn, &newurl);
+ CURLcode ret = Curl_retry_request(data, &newurl);
if(!ret)
retry = (newurl)?TRUE:FALSE;
else if(!result)
@@ -2307,17 +2330,18 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else if((CURLE_HTTP2_STREAM == result) &&
- Curl_h2_http_1_1_error(data->conn)) {
- CURLcode ret = Curl_retry_request(data->conn, &newurl);
+ Curl_h2_http_1_1_error(data)) {
+ CURLcode ret = Curl_retry_request(data, &newurl);
if(!ret) {
- infof(data, "Downgrades to HTTP/1.1!\n");
- data->set.httpversion = CURL_HTTP_VERSION_1_1;
+ infof(data, "Downgrades to HTTP/1.1!");
+ streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
+ data->state.httpwant = CURL_HTTP_VERSION_1_1;
/* clear the error message bit too as we ignore the one we got */
data->state.errorbuf = FALSE;
if(!newurl)
/* typically for HTTP_1_1_REQUIRED error on first flight */
- newurl = strdup(data->change.url);
+ newurl = strdup(data->state.url);
/* if we are to retry, set the result to OK and consider the request
as done */
retry = TRUE;
@@ -2345,7 +2369,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multi_done(data, result, TRUE);
}
else if(done) {
- followtype follow = FOLLOW_NONE;
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
@@ -2353,6 +2376,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* When we follow redirects or is set to retry the connection, we must
to go back to the CONNECT state */
if(data->req.newurl || retry) {
+ followtype follow = FOLLOW_NONE;
if(!retry) {
/* if the URL is a follow-location and not just a retried request
then figure out the URL here */
@@ -2367,7 +2391,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* multi_done() might return CURLE_GOT_NOTHING */
result = Curl_follow(data, newurl, follow);
if(!result) {
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
rc = CURLM_CALL_MULTI_PERFORM;
}
free(newurl);
@@ -2390,7 +2414,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!result) {
- multistate(data, CURLM_STATE_DONE);
+ multistate(data, MSTATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
@@ -2405,7 +2429,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
}
- case CURLM_STATE_DONE:
+ case MSTATE_DONE:
/* this state is highly transient, so run another loop after this */
rc = CURLM_CALL_MULTI_PERFORM;
@@ -2422,44 +2446,51 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* allow a previously set error code take precedence */
if(!result)
result = res;
-
- /*
- * If there are other handles on the connection, multi_done won't set
- * conn to NULL. In such a case, curl_multi_remove_handle() can
- * access free'd data, if the connection is free'd and the handle
- * removed before we perform the processing in CURLM_STATE_COMPLETED
- */
- Curl_detach_connnection(data);
}
#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch) {
if(data->wildcard.state != CURLWC_DONE) {
/* if a wildcard is set and we are not ending -> lets start again
- with CURLM_STATE_INIT */
- multistate(data, CURLM_STATE_INIT);
+ with MSTATE_INIT */
+ multistate(data, MSTATE_INIT);
break;
}
}
#endif
/* after we have DONE what we're supposed to do, go COMPLETED, and
it doesn't matter what the multi_done() returned! */
- multistate(data, CURLM_STATE_COMPLETED);
+ multistate(data, MSTATE_COMPLETED);
break;
- case CURLM_STATE_COMPLETED:
+ case MSTATE_COMPLETED:
break;
- case CURLM_STATE_MSGSENT:
+ case MSTATE_MSGSENT:
data->result = result;
return CURLM_OK; /* do nothing */
default:
return CURLM_INTERNAL_ERROR;
}
+
+ if(data->conn &&
+ data->mstate >= MSTATE_CONNECT &&
+ data->mstate < MSTATE_DO &&
+ rc != CURLM_CALL_MULTI_PERFORM &&
+ !multi_ischanged(multi, false)) {
+ /* We now handle stream timeouts if and only if this will be the last
+ * loop iteration. We only check this on the last iteration to ensure
+ * that if we know we have additional work to do immediately
+ * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
+ * declaring the connection timed out as we may almost have a completed
+ * connection. */
+ multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
+ }
+
statemachine_end:
- if(data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate < MSTATE_COMPLETED) {
if(result) {
/*
* If an error was returned, and we aren't in completed state now,
@@ -2490,29 +2521,29 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_disconnect(data, conn, dead_connection);
}
}
- else if(data->mstate == CURLM_STATE_CONNECT) {
+ else if(data->mstate == MSTATE_CONNECT) {
/* Curl_connect() failed */
(void)Curl_posttransfer(data);
}
- multistate(data, CURLM_STATE_COMPLETED);
+ multistate(data, MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
}
/* if there's still a connection to use, call the progress function */
- else if(data->conn && Curl_pgrsUpdate(data->conn)) {
+ else if(data->conn && Curl_pgrsUpdate(data)) {
/* aborted due to progress callback return code must close the
connection */
result = CURLE_ABORTED_BY_CALLBACK;
streamclose(data->conn, "Aborted by callback");
/* if not yet in DONE state, go there, otherwise COMPLETED */
- multistate(data, (data->mstate < CURLM_STATE_DONE)?
- CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
+ multistate(data, (data->mstate < MSTATE_DONE)?
+ MSTATE_DONE: MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
- if(CURLM_STATE_COMPLETED == data->mstate) {
+ if(MSTATE_COMPLETED == data->mstate) {
if(data->set.fmultidone) {
/* signal via callback instead */
data->set.fmultidone(data, result);
@@ -2528,7 +2559,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = multi_addmsg(multi, msg);
DEBUGASSERT(!data->conn);
}
- multistate(data, CURLM_STATE_MSGSENT);
+ multistate(data, MSTATE_MSGSENT);
}
} while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
@@ -2600,9 +2631,9 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- multi->type = 0; /* not good anymore */
+ multi->magic = 0; /* not good anymore */
- /* Firsrt remove all remaining easy handles */
+ /* First remove all remaining easy handles */
data = multi->easyp;
while(data) {
nextdata = data->next;
@@ -2705,7 +2736,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
curl_socket_t s;
int num;
unsigned int curraction;
- int actions[MAX_SOCKSPEREASYHANDLE];
+ unsigned char actions[MAX_SOCKSPEREASYHANDLE];
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
socks[i] = CURL_SOCKET_BAD;
@@ -2722,9 +2753,9 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
(curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
i++) {
- unsigned int action = CURL_POLL_NONE;
- unsigned int prevaction = 0;
- unsigned int comboaction;
+ unsigned char action = CURL_POLL_NONE;
+ unsigned char prevaction = 0;
+ int comboaction;
bool sincebefore = FALSE;
s = socks[i];
@@ -2782,10 +2813,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
}
comboaction = (entry->writers? CURL_POLL_OUT : 0) |
- (entry->readers ? CURL_POLL_IN : 0);
+ (entry->readers ? CURL_POLL_IN : 0);
/* socket existed before and has the same action set as before */
- if(sincebefore && (entry->action == comboaction))
+ if(sincebefore && ((int)entry->action == comboaction))
/* same, continue */
continue;
@@ -2818,7 +2849,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
/* if this is NULL here, the socket has been closed and notified so
already by Curl_multi_closed() */
if(entry) {
- int oldactions = data->actions[i];
+ unsigned char oldactions = data->actions[i];
/* this socket has been removed. Decrease user count */
entry->users--;
if(oldactions & CURL_POLL_OUT)
@@ -2843,7 +2874,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
} /* for loop over numsocks */
memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
- memcpy(data->actions, actions, num*sizeof(int));
+ memcpy(data->actions, actions, num*sizeof(char));
data->numsocks = num;
return CURLM_OK;
}
@@ -3158,7 +3189,6 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
}
CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
-
{
CURLMcode result;
if(multi->in_callback)
@@ -3172,7 +3202,7 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms)
{
- static struct curltime tv_zero = {0, 0};
+ static const struct curltime tv_zero = {0, 0};
if(multi->timetree) {
/* we have a tree of expire times */
@@ -3376,11 +3406,10 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
/* Since this is an updated time, we must remove the previous entry from
the splay tree first and then re-add the new value */
- rc = Curl_splayremovebyaddr(multi->timetree,
- &data->state.timenode,
- &multi->timetree);
+ rc = Curl_splayremove(multi->timetree, &data->state.timenode,
+ &multi->timetree);
if(rc)
- infof(data, "Internal error removing splay node = %d\n", rc);
+ infof(data, "Internal error removing splay node = %d", rc);
}
/* Indicate that we are in the splay tree and insert the new timer expiry
@@ -3424,11 +3453,10 @@ void Curl_expire_clear(struct Curl_easy *data)
struct Curl_llist *list = &data->state.timeoutlist;
int rc;
- rc = Curl_splayremovebyaddr(multi->timetree,
- &data->state.timenode,
- &multi->timetree);
+ rc = Curl_splayremove(multi->timetree, &data->state.timenode,
+ &multi->timetree);
if(rc)
- infof(data, "Internal error clearing splay node = %d\n", rc);
+ infof(data, "Internal error clearing splay node = %d", rc);
/* flush the timeout list too */
while(list->size > 0) {
@@ -3436,7 +3464,7 @@ void Curl_expire_clear(struct Curl_easy *data)
}
#ifdef DEBUGBUILD
- infof(data, "Expire cleared (transfer %p)\n", data);
+ infof(data, "Expire cleared (transfer %p)", data);
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;
@@ -3478,16 +3506,18 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
* When information about a connection has appeared, call this!
*/
-void Curl_multiuse_state(struct connectdata *conn,
+void Curl_multiuse_state(struct Curl_easy *data,
int bundlestate) /* use BUNDLE_* defines */
{
+ struct connectdata *conn;
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->multi);
+ conn = data->conn;
DEBUGASSERT(conn);
DEBUGASSERT(conn->bundle);
- DEBUGASSERT(conn->data);
- DEBUGASSERT(conn->data->multi);
conn->bundle->multiuse = bundlestate;
- process_pending_handles(conn->data->multi);
+ process_pending_handles(data->multi);
}
static void process_pending_handles(struct Curl_multi *multi)
@@ -3496,9 +3526,9 @@ static void process_pending_handles(struct Curl_multi *multi)
if(e) {
struct Curl_easy *data = e->ptr;
- DEBUGASSERT(data->mstate == CURLM_STATE_CONNECT_PEND);
+ DEBUGASSERT(data->mstate == MSTATE_PENDING);
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
/* Remove this node from the list */
Curl_llist_remove(&multi->pending, e, NULL);
@@ -3536,7 +3566,7 @@ void Curl_multi_dump(struct Curl_multi *multi)
fprintf(stderr, "* Multi status: %d handles, %d alive\n",
multi->num_easy, multi->num_alive);
for(data = multi->easyp; data; data = data->next) {
- if(data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate < MSTATE_COMPLETED) {
/* only display handles that are not completed */
fprintf(stderr, "handle %p, state %s, %d sockets\n",
(void *)data,