summaryrefslogtreecommitdiffstats
path: root/lib/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/multi.c')
-rw-r--r--lib/multi.c257
1 files changed, 133 insertions, 124 deletions
diff --git a/lib/multi.c b/lib/multi.c
index 950b600..b24ce19 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -280,7 +280,7 @@ static int sh_init(struct curl_hash *hash, int hashsize)
static CURLMcode multi_addmsg(struct Curl_multi *multi,
struct Curl_message *msg)
{
- if(!Curl_llist_insert_next(multi->msglist, multi->msglist->tail, msg))
+ if(!Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg))
return CURLM_OUT_OF_MEMORY;
return CURLM_OK;
@@ -316,13 +316,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
if(Curl_conncache_init(&multi->conn_cache, chashsize))
goto error;
- multi->msglist = Curl_llist_alloc(multi_freeamsg);
- if(!multi->msglist)
- goto error;
-
- multi->pending = Curl_llist_alloc(multi_freeamsg);
- if(!multi->pending)
- goto error;
+ Curl_llist_init(&multi->msglist, multi_freeamsg);
+ Curl_llist_init(&multi->pending, multi_freeamsg);
/* allocate a new easy handle to use when closing cached connections */
multi->closure_handle = curl_easy_init();
@@ -345,8 +340,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_conncache_destroy(&multi->conn_cache);
Curl_close(multi->closure_handle);
multi->closure_handle = NULL;
- Curl_llist_destroy(multi->msglist, NULL);
- Curl_llist_destroy(multi->pending, NULL);
+ Curl_llist_destroy(&multi->msglist, NULL);
+ Curl_llist_destroy(&multi->pending, NULL);
free(multi);
return NULL;
@@ -361,8 +356,6 @@ struct Curl_multi *curl_multi_init(void)
CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
struct Curl_easy *data)
{
- struct curl_llist *timeoutlist;
-
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -376,10 +369,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
if(data->multi)
return CURLM_ADDED_ALREADY;
- /* Allocate and initialize timeout list for easy handle */
- timeoutlist = Curl_llist_alloc(multi_freetimeout);
- if(!timeoutlist)
- return CURLM_OUT_OF_MEMORY;
+ /* Initialize timeout list for this handle */
+ Curl_llist_init(&data->state.timeoutlist, multi_freetimeout);
/*
* No failure allowed in this function beyond this point. And no
@@ -388,10 +379,6 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
* function no matter what.
*/
- /* Make easy handle use timeout list initialized above */
- data->state.timeoutlist = timeoutlist;
- timeoutlist = NULL;
-
/* set the easy handle */
multistate(data, CURLM_STATE_INIT);
@@ -532,6 +519,7 @@ static CURLcode multi_done(struct connectdata **connp,
CURLcode result;
struct connectdata *conn;
struct Curl_easy *data;
+ unsigned int i;
DEBUGASSERT(*connp);
@@ -579,7 +567,7 @@ static CURLcode multi_done(struct connectdata **connp,
result = CURLE_ABORTED_BY_CALLBACK;
}
- if(conn->send_pipe->size + conn->recv_pipe->size != 0 &&
+ if(conn->send_pipe.size + conn->recv_pipe.size != 0 &&
!data->set.reuse_forbid &&
!conn->bits.close) {
/* Stop if pipeline is not empty and we do not have to close
@@ -598,9 +586,11 @@ static CURLcode multi_done(struct connectdata **connp,
}
/* if the transfer was completed in a paused state there can be buffered
- data left to write and then kill */
- free(data->state.tempwrite);
- data->state.tempwrite = NULL;
+ data left to free */
+ for(i=0; i < data->state.tempcount; i++) {
+ free(data->state.tempwrite[i].buf);
+ }
+ data->state.tempcount = 0;
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
forced us to close this connection. This is ignored for requests taking
@@ -638,7 +628,10 @@ static CURLcode multi_done(struct connectdata **connp,
infof(data, "Connection #%ld to host %s left intact\n",
conn->connection_id,
- conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+ conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
+ conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+ conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+ conn->host.dispname);
}
else
data->state.lastconnect = NULL;
@@ -692,13 +685,13 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
if(data->easy_conn &&
data->mstate > CURLM_STATE_DO &&
data->mstate < CURLM_STATE_COMPLETED) {
+ /* Set connection owner so that the DONE function closes it. We can
+ safely do this here since connection is killed. */
+ data->easy_conn->data = easy;
/* If the handle is in a pipeline and has started sending off its
request but not received its response yet, we need to close
connection. */
streamclose(data->easy_conn, "Removed with partial response");
- /* Set connection owner so that the DONE function closes it. We can
- safely do this here since connection is killed. */
- data->easy_conn->data = easy;
easy_owns_conn = TRUE;
}
@@ -735,10 +728,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* destroy the timeout list that is held in the easy handle, do this *after*
multi_done() as that may actually call Curl_expire that uses this */
- if(data->state.timeoutlist) {
- Curl_llist_destroy(data->state.timeoutlist, NULL);
- data->state.timeoutlist = NULL;
- }
+ Curl_llist_destroy(&data->state.timeoutlist, NULL);
/* as this was using a shared connection cache we clear the pointer to that
since we're not part of that multi handle anymore */
@@ -761,11 +751,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* make sure there's no pending message in the queue sent from this easy
handle */
- for(e = multi->msglist->head; e; e = e->next) {
+ for(e = multi->msglist.head; e; e = e->next) {
struct Curl_message *msg = e->ptr;
if(msg->extmsg.easy_handle == easy) {
- Curl_llist_remove(multi->msglist, e, NULL);
+ Curl_llist_remove(&multi->msglist, e, NULL);
/* there can only be one from this specific handle */
break;
}
@@ -956,10 +946,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
if(s == CURL_SOCKET_BAD)
/* this socket is unused, break out of loop */
break;
- else {
- if((int)s > this_max_fd)
- this_max_fd = (int)s;
- }
+ if((int)s > this_max_fd)
+ this_max_fd = (int)s;
}
data = data->next; /* check next handle */
@@ -970,6 +958,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
return CURLM_OK;
}
+#define NUM_POLLS_ON_STACK 10
+
CURLMcode curl_multi_wait(struct Curl_multi *multi,
struct curl_waitfd extra_fds[],
unsigned int extra_nfds,
@@ -983,8 +973,10 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
unsigned int nfds = 0;
unsigned int curlfds;
struct pollfd *ufds = NULL;
+ bool ufds_malloc = FALSE;
long timeout_internal;
int retcode = 0;
+ struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -1024,9 +1016,14 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
nfds += extra_nfds; /* add the externally provided ones */
if(nfds || extra_nfds) {
- ufds = malloc(nfds * sizeof(struct pollfd));
- if(!ufds)
- return CURLM_OUT_OF_MEMORY;
+ if(nfds > NUM_POLLS_ON_STACK) {
+ ufds = malloc(nfds * sizeof(struct pollfd));
+ if(!ufds)
+ return CURLM_OUT_OF_MEMORY;
+ ufds_malloc = TRUE;
+ }
+ else
+ ufds = &a_few_on_stack[0];
}
nfds = 0;
@@ -1104,7 +1101,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
}
}
- free(ufds);
+ if(ufds_malloc)
+ free(ufds);
if(ret)
*ret = retcode;
return CURLM_OK;
@@ -1307,6 +1305,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLcode result = CURLE_OK;
struct SingleRequest *k;
time_t timeout_ms;
+ time_t recv_timeout_ms;
+ time_t send_timeout_ms;
int control;
if(!GOOD_EASY_HANDLE(data))
@@ -1432,7 +1432,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_CONNECT_PEND);
/* add this handle to the list of connect-pending handles */
- if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data))
+ if(!Curl_llist_insert_next(&multi->pending, multi->pending.tail, data))
result = CURLE_OUT_OF_MEMORY;
else
result = CURLE_OK;
@@ -1477,8 +1477,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct connectdata *conn = data->easy_conn;
const char *hostname;
- if(conn->bits.proxy)
- hostname = conn->proxy.name;
+ if(conn->bits.httpproxy)
+ hostname = conn->http_proxy.host.name;
else if(conn->bits.conn_to_host)
hostname = conn->conn_to_host.name;
else
@@ -1826,19 +1826,30 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else
result = Curl_speedcheck(data, now);
- if(( (data->set.max_send_speed == 0) ||
- (Curl_pgrsLimitWaitTime(data->progress.uploaded,
- data->progress.ul_limit_size,
- data->set.max_send_speed,
- data->progress.ul_limit_start,
- now) <= 0)) &&
- ( (data->set.max_recv_speed == 0) ||
- (Curl_pgrsLimitWaitTime(data->progress.downloaded,
- data->progress.dl_limit_size,
- data->set.max_recv_speed,
- data->progress.dl_limit_start,
- now) <= 0)))
- multistate(data, CURLM_STATE_PERFORM);
+ if(!result) {
+ send_timeout_ms = 0;
+ if(data->set.max_send_speed > 0)
+ send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
+ data->set.max_send_speed,
+ data->progress.ul_limit_start,
+ now);
+
+ recv_timeout_ms = 0;
+ if(data->set.max_recv_speed > 0)
+ recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
+ data->set.max_recv_speed,
+ data->progress.dl_limit_start,
+ now);
+
+ if(send_timeout_ms <= 0 && recv_timeout_ms <= 0)
+ multistate(data, CURLM_STATE_PERFORM);
+ else if(send_timeout_ms >= recv_timeout_ms)
+ Curl_expire_latest(data, send_timeout_ms);
+ else
+ Curl_expire_latest(data, recv_timeout_ms);
+ }
break;
case CURLM_STATE_PERFORM:
@@ -1848,31 +1859,30 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool comeback = FALSE;
/* check if over send speed */
- if(data->set.max_send_speed > 0) {
- timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
- data->progress.ul_limit_size,
- data->set.max_send_speed,
- data->progress.ul_limit_start,
- now);
- if(timeout_ms > 0) {
- multistate(data, CURLM_STATE_TOOFAST);
- Curl_expire_latest(data, timeout_ms);
- break;
- }
- }
+ send_timeout_ms = 0;
+ if(data->set.max_send_speed > 0)
+ send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
+ data->set.max_send_speed,
+ data->progress.ul_limit_start,
+ now);
/* check if over recv speed */
- if(data->set.max_recv_speed > 0) {
- timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
- data->progress.dl_limit_size,
- data->set.max_recv_speed,
- data->progress.dl_limit_start,
- now);
- if(timeout_ms > 0) {
- multistate(data, CURLM_STATE_TOOFAST);
- Curl_expire_latest(data, timeout_ms);
- break;
- }
+ recv_timeout_ms = 0;
+ if(data->set.max_recv_speed > 0)
+ recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
+ data->set.max_recv_speed,
+ data->progress.dl_limit_start,
+ now);
+
+ if(send_timeout_ms > 0 || recv_timeout_ms > 0) {
+ multistate(data, CURLM_STATE_TOOFAST);
+ if(send_timeout_ms >= recv_timeout_ms)
+ Curl_expire_latest(data, send_timeout_ms);
+ else
+ Curl_expire_latest(data, recv_timeout_ms);
+ break;
}
/* read/write data if it is ready to do so */
@@ -1928,11 +1938,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_posttransfer(data);
/* we're no longer receiving */
- Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
/* expire the new receiving pipeline head */
- if(data->easy_conn->recv_pipe->head)
- Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 0);
+ if(data->easy_conn->recv_pipe.head)
+ Curl_expire_latest(data->easy_conn->recv_pipe.head->ptr, 0);
/* Check if we can move pending requests to send pipe */
Curl_multi_process_pending_handles(multi);
@@ -1997,7 +2007,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLcode res;
/* Remove ourselves from the receive pipeline, if we are there. */
- Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
/* Check if we can move pending requests to send pipe */
Curl_multi_process_pending_handles(multi);
@@ -2073,8 +2083,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* if this has a connection, unsubscribe from the pipelines */
Curl_pipeline_leave_write(data->easy_conn);
Curl_pipeline_leave_read(data->easy_conn);
- Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe);
- Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->send_pipe);
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
if(stream_error) {
/* Don't attempt to send data over a connection that timed out */
@@ -2229,8 +2239,8 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_hash_destroy(&multi->sockhash);
Curl_conncache_destroy(&multi->conn_cache);
- Curl_llist_destroy(multi->msglist, NULL);
- Curl_llist_destroy(multi->pending, NULL);
+ Curl_llist_destroy(&multi->msglist, NULL);
+ Curl_llist_destroy(&multi->pending, NULL);
/* remove all easy handles */
data = multi->easyp;
@@ -2262,8 +2272,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
return CURLM_OK;
}
- else
- return CURLM_BAD_HANDLE;
+ return CURLM_BAD_HANDLE;
}
/*
@@ -2282,24 +2291,23 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
*msgs_in_queue = 0; /* default to none */
- if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) {
+ if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(&multi->msglist)) {
/* there is one or more messages in the list */
struct curl_llist_element *e;
/* extract the head of the list to return */
- e = multi->msglist->head;
+ e = multi->msglist.head;
msg = e->ptr;
/* remove the extracted entry */
- Curl_llist_remove(multi->msglist, e, NULL);
+ Curl_llist_remove(&multi->msglist, e, NULL);
- *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist));
+ *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
return &msg->extmsg;
}
- else
- return NULL;
+ return NULL;
}
/*
@@ -2394,7 +2402,7 @@ static void singlesocket(struct Curl_multi *multi,
removed. */
struct connectdata *easy_conn = data->easy_conn;
if(easy_conn) {
- if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
+ if(easy_conn->recv_pipe.size > 1) {
/* the handle should not be removed from the pipe yet */
remove_sock_from_hash = FALSE;
@@ -2403,12 +2411,12 @@ static void singlesocket(struct Curl_multi *multi,
isn't already) */
if(entry->easy == data) {
if(Curl_recvpipe_head(data, easy_conn))
- entry->easy = easy_conn->recv_pipe->head->next->ptr;
+ entry->easy = easy_conn->recv_pipe.head->next->ptr;
else
- entry->easy = easy_conn->recv_pipe->head->ptr;
+ entry->easy = easy_conn->recv_pipe.head->ptr;
}
}
- if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) {
+ if(easy_conn->send_pipe.size > 1) {
/* the handle should not be removed from the pipe yet */
remove_sock_from_hash = FALSE;
@@ -2417,9 +2425,9 @@ static void singlesocket(struct Curl_multi *multi,
isn't already) */
if(entry->easy == data) {
if(Curl_sendpipe_head(data, easy_conn))
- entry->easy = easy_conn->send_pipe->head->next->ptr;
+ entry->easy = easy_conn->send_pipe.head->next->ptr;
else
- entry->easy = easy_conn->send_pipe->head->ptr;
+ entry->easy = easy_conn->send_pipe.head->ptr;
}
}
/* Don't worry about overwriting recv_pipe head with send_pipe_head,
@@ -2494,7 +2502,7 @@ static CURLMcode add_next_timeout(struct timeval now,
struct Curl_easy *d)
{
struct timeval *tv = &d->state.expiretime;
- struct curl_llist *list = d->state.timeoutlist;
+ struct curl_llist *list = &d->state.timeoutlist;
struct curl_llist_element *e;
/* move over the timeout list for this specific handle and remove all
@@ -2560,7 +2568,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
/* or should we fall-through and do the timer-based stuff? */
return result;
}
- else if(s != CURL_SOCKET_TIMEOUT) {
+ if(s != CURL_SOCKET_TIMEOUT) {
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
@@ -2585,13 +2593,11 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
head. If we should read from the socket, take the recv_pipe head. */
if(data->easy_conn) {
if((ev_bitmask & CURL_POLL_OUT) &&
- data->easy_conn->send_pipe &&
- data->easy_conn->send_pipe->head)
- data = data->easy_conn->send_pipe->head->ptr;
+ data->easy_conn->send_pipe.head)
+ data = data->easy_conn->send_pipe.head->ptr;
else if((ev_bitmask & CURL_POLL_IN) &&
- data->easy_conn->recv_pipe &&
- data->easy_conn->recv_pipe->head)
- data = data->easy_conn->recv_pipe->head->ptr;
+ data->easy_conn->recv_pipe.head)
+ data = data->easy_conn->recv_pipe.head->ptr;
}
if(data->easy_conn &&
@@ -2928,7 +2934,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli)
set = Curl_tvnow();
set.tv_sec += (long)(milli/1000);
- set.tv_usec += (milli%1000)*1000;
+ set.tv_usec += (long)(milli%1000)*1000;
if(set.tv_usec >= 1000000) {
set.tv_sec++;
@@ -2943,13 +2949,13 @@ void Curl_expire(struct Curl_easy *data, time_t milli)
if(diff > 0) {
/* the new expire time was later so just add it to the queue
and get out */
- multi_addtimeout(data->state.timeoutlist, &set);
+ multi_addtimeout(&data->state.timeoutlist, &set);
return;
}
/* the new time is newer than the presently set one, so add the current
to the queue and update the head */
- multi_addtimeout(data->state.timeoutlist, nowp);
+ multi_addtimeout(&data->state.timeoutlist, nowp);
/* Since this is an updated time, we must remove the previous entry from
the splay tree first and then re-add the new value */
@@ -2985,7 +2991,7 @@ void Curl_expire_latest(struct Curl_easy *data, time_t milli)
set = Curl_tvnow();
set.tv_sec += (long)(milli / 1000);
- set.tv_usec += (milli % 1000) * 1000;
+ set.tv_usec += (long)(milli % 1000) * 1000;
if(set.tv_usec >= 1000000) {
set.tv_sec++;
@@ -2995,11 +3001,14 @@ void Curl_expire_latest(struct Curl_easy *data, time_t milli)
if(expire->tv_sec || expire->tv_usec) {
/* This means that the struct is added as a node in the splay tree.
Compare if the new time is earlier, and only remove-old/add-new if it
- is. */
+ is. */
time_t diff = curlx_tvdiff(set, *expire);
- if(diff > 0)
- /* the new expire time was later than the top time, so just skip this */
+ if((diff > 0) && (diff < milli)) {
+ /* if the new expire time is later than the top time, skip it, but not
+ if the diff is larger than the new offset since then the previous
+ time is already expired! */
return;
+ }
}
/* Just add the timeout like normal */
@@ -3026,7 +3035,7 @@ void Curl_expire_clear(struct Curl_easy *data)
if(nowp->tv_sec || nowp->tv_usec) {
/* Since this is an cleared time, we must remove the previous entry from
the splay tree */
- struct curl_llist *list = data->state.timeoutlist;
+ struct curl_llist *list = &data->state.timeoutlist;
rc = Curl_splayremovebyaddr(multi->timetree,
&data->state.timenode,
@@ -3086,17 +3095,17 @@ curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
{
- return multi->pipelining_site_bl;
+ return &multi->pipelining_site_bl;
}
struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
{
- return multi->pipelining_server_bl;
+ return &multi->pipelining_server_bl;
}
void Curl_multi_process_pending_handles(struct Curl_multi *multi)
{
- struct curl_llist_element *e = multi->pending->head;
+ struct curl_llist_element *e = multi->pending.head;
while(e) {
struct Curl_easy *data = e->ptr;
@@ -3106,7 +3115,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi)
multistate(data, CURLM_STATE_CONNECT);
/* Remove this node from the list */
- Curl_llist_remove(multi->pending, e, NULL);
+ Curl_llist_remove(&multi->pending, e, NULL);
/* Make sure that the handle will be processed soonish. */
Curl_expire_latest(data, 0);