multi: turn Curl_done into file local multi_done

... as it now is used by multi.c only.
This commit is contained in:
Daniel Stenberg 2016-03-30 00:17:02 +02:00
parent 93935c08c1
commit 575e885db0
9 changed files with 201 additions and 224 deletions

View File

@ -3242,7 +3242,7 @@ static CURLcode ftp_connect(struct connectdata *conn,
* Input argument is already checked for validity.
*/
static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
bool premature)
bool premature)
{
struct SessionHandle *data = conn->data;
struct FTP *ftp = data->req.protop;
@ -3256,11 +3256,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
const char *path_to_use = data->state.path;
if(!ftp)
/* When the easy handle is removed from the multi while libcurl is still
* trying to resolve the host name, it seems that the ftp struct is not
* yet initialized, but the removal action calls Curl_done() which calls
* this function. So we simply return success if no ftp pointer is set.
*/
return CURLE_OK;
switch(status) {

View File

@ -1434,8 +1434,8 @@ static int https_getsock(struct connectdata *conn,
#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */
/*
* Curl_http_done() gets called from Curl_done() after a single HTTP request
* has been performed.
* Curl_http_done() gets called after a single HTTP request has been
* performed.
*/
CURLcode Curl_http_done(struct connectdata *conn,

View File

@ -1486,10 +1486,6 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
(void)premature;
if(!imap)
/* When the easy handle is removed from the multi interface while libcurl
is still trying to resolve the host name, the IMAP struct is not yet
initialized. However, the removal action calls Curl_done() which in
turn calls this function, so we simply return success. */
return CURLE_OK;
if(status) {
@ -1512,8 +1508,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
TODO: when the multi interface is used, this _really_ should be using
the imap_multi_statemach function but we have no general support for
non-blocking DONE operations, not in the multi state machine and with
Curl_done() invokes on several places in the code!
non-blocking DONE operations!
*/
if(!result)
result = imap_block_statemach(conn);

View File

@ -484,6 +484,167 @@ static void debug_print_sock_hash(void *p)
}
#endif
/* Mark the connection as 'idle', or close it if the cache is full.
Returns TRUE if the connection is kept, or FALSE if it was closed. */
static bool
ConnectionDone(struct SessionHandle *data, struct connectdata *conn)
{
/* data->multi->maxconnects can be negative, deal with it. */
size_t maxconnects =
(data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
data->multi->maxconnects;
struct connectdata *conn_candidate = NULL;
/* Mark the current connection as 'unused' */
conn->inuse = FALSE;
if(maxconnects > 0 &&
data->state.conn_cache->num_connections > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one.\n");
conn_candidate = Curl_oldest_idle_connection(data);
if(conn_candidate) {
/* Set the connection's owner correctly */
conn_candidate->data = data;
/* the winner gets the honour of being disconnected */
(void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
}
}
return (conn_candidate == conn) ? FALSE : TRUE;
}
static CURLcode multi_done(struct connectdata **connp,
CURLcode status, /* an error if this is called
after an error was detected */
bool premature)
{
CURLcode result;
struct connectdata *conn;
struct SessionHandle *data;
DEBUGASSERT(*connp);
conn = *connp;
data = conn->data;
DEBUGF(infof(data, "multi_done\n"));
if(data->state.done)
/* Stop if multi_done() has already been called */
return CURLE_OK;
Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */
free(data->req.newurl);
data->req.newurl = NULL;
free(data->req.location);
data->req.location = NULL;
switch(status) {
case CURLE_ABORTED_BY_CALLBACK:
case CURLE_READ_ERROR:
case CURLE_WRITE_ERROR:
/* When we're aborted due to a callback return code it basically have to
be counted as premature as there is trouble ahead if we don't. We have
many callbacks and protocols work differently, we could potentially do
this more fine-grained in the future. */
premature = TRUE;
default:
break;
}
/* this calls the protocol-specific function pointer previously set */
if(conn->handler->done)
result = conn->handler->done(conn, 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);
if(!result && rc)
result = CURLE_ABORTED_BY_CALLBACK;
}
if((!premature &&
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
connection. */
DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n"));
return CURLE_OK;
}
data->state.done = TRUE; /* called just now! */
Curl_resolver_cancel(conn);
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
conn->dns_entry = NULL;
}
/* 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;
/* 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
place in a NTLM authentication handshake
if conn->bits.close is TRUE, it means that the connection should be
closed in spite of all our efforts to be nice, due to protocol
restrictions in our or the server's end
if premature is TRUE, it means this connection was said to be DONE before
the entire request operation is complete and thus we can't know in what
state it is for re-using, so we're forced to close it. In a perfect world
we can add code that keep track of if we really must close it here or not,
but currently we have no such detail knowledge.
*/
if((data->set.reuse_forbid
#if defined(USE_NTLM)
&& !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
conn->proxyntlm.state == NTLMSTATE_TYPE2)
#endif
) || conn->bits.close || premature) {
CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
/* If we had an error already, make sure we return that one. But
if we got a new error, return that. */
if(!result && res2)
result = res2;
}
else {
/* the connection is no longer in use */
if(ConnectionDone(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect = conn;
infof(data, "Connection #%ld to host %s left intact\n",
conn->connection_id,
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
}
else
data->state.lastconnect = NULL;
}
*connp = NULL; /* to make the caller of this function better detect that
this was either closed or handed over to the connection
cache here, and therefore cannot be used from this point on
*/
Curl_free_request_state(data);
return result;
}
CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
CURL *curl_handle)
{
@ -529,8 +690,8 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
request but not received its response yet, we need to close
connection. */
connclose(data->easy_conn, "Removed with partial response");
/* Set connection owner so that Curl_done() closes it.
We can safely do this here since connection is killed. */
/* 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;
}
@ -548,26 +709,26 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
if(data->easy_conn) {
/* we must call Curl_done() here (if we still "own it") so that we don't
leave a half-baked one around */
/* 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) {
/* Curl_done() clears the conn->data field to lose the association
/* multi_done() clears the conn->data field to lose 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)Curl_done(&data->easy_conn, data->result, premature);
(void)multi_done(&data->easy_conn, data->result, premature);
}
else
/* Clear connection pipelines, if Curl_done above was not called */
/* Clear connection pipelines, if multi_done above was not called */
Curl_getoff_all_pipelines(data, data->easy_conn);
}
Curl_wildcard_dtor(&data->wildcard);
/* destroy the timeout list that is held in the easy handle, do this *after*
Curl_done() as that may actuall call Curl_expire that uses this */
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;
@ -1005,18 +1166,16 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
infof(data, "Re-used connection seems dead, get a new one\n");
connclose(conn, "Reconnect dead connection"); /* enforce close */
result = Curl_done(&conn, result, FALSE); /* we are so done with this */
result = multi_done(&conn, result, FALSE); /* we are so done with this */
/* conn may no longer be a good pointer, clear it to avoid mistakes by
parent functions */
*connp = NULL;
/*
* According to bug report #1330310. We need to check for CURLE_SEND_ERROR
* here as well. I figure this could happen when the request failed on a FTP
* connection and thus Curl_done() itself tried to use the connection
* (again). Slight Lack of feedback in the report, but I don't think this
* extra check can do much harm.
* We need to check for CURLE_SEND_ERROR here as well. This could happen
* when the request failed on a FTP connection and thus multi_done() itself
* tried to use the connection (again).
*/
if(!result || (CURLE_SEND_ERROR == result)) {
bool async;
@ -1227,7 +1386,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
disconnect_conn = TRUE;
}
result = CURLE_OPERATION_TIMEDOUT;
(void)Curl_done(&data->easy_conn, result, TRUE);
(void)multi_done(&data->easy_conn, result, TRUE);
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
@ -1372,7 +1531,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;
/* connect back to proxy again */
result = CURLE_OK;
Curl_done(&data->easy_conn, CURLE_OK, FALSE);
multi_done(&data->easy_conn, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_CONNECT);
}
else if(!result) {
@ -1416,7 +1575,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(result) {
/* failure detected */
Curl_posttransfer(data);
Curl_done(&data->easy_conn, result, TRUE);
multi_done(&data->easy_conn, result, TRUE);
disconnect_conn = TRUE;
}
break;
@ -1433,7 +1592,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(result) {
/* failure detected */
Curl_posttransfer(data);
Curl_done(&data->easy_conn, result, TRUE);
multi_done(&data->easy_conn, result, TRUE);
disconnect_conn = TRUE;
}
break;
@ -1468,7 +1627,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct WildcardData *wc = &data->wildcard;
if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
/* skip some states if it is important */
Curl_done(&data->easy_conn, CURLE_OK, FALSE);
multi_done(&data->easy_conn, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
break;
@ -1515,7 +1674,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
retry = (newurl)?TRUE:FALSE;
Curl_posttransfer(data);
drc = Curl_done(&data->easy_conn, result, FALSE);
drc = multi_done(&data->easy_conn, result, FALSE);
/* When set to retry the connection, we must to go back to
* the CONNECT state */
@ -1550,7 +1709,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* failure detected */
Curl_posttransfer(data);
if(data->easy_conn)
Curl_done(&data->easy_conn, result, FALSE);
multi_done(&data->easy_conn, result, FALSE);
disconnect_conn = TRUE;
}
}
@ -1572,7 +1731,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
Curl_done(&data->easy_conn, result, FALSE);
multi_done(&data->easy_conn, result, FALSE);
disconnect_conn = TRUE;
}
break;
@ -1584,7 +1743,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = multi_do_more(data->easy_conn, &control);
/* No need to remove this handle from the send pipeline here since that
is done in Curl_done() */
is done in multi_done() */
if(!result) {
if(control) {
/* if positive, advance to DO_DONE
@ -1601,7 +1760,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
Curl_done(&data->easy_conn, result, FALSE);
multi_done(&data->easy_conn, result, FALSE);
disconnect_conn = TRUE;
}
break;
@ -1725,7 +1884,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
connclose(data->easy_conn, "Transfer returned error");
Curl_posttransfer(data);
Curl_done(&data->easy_conn, result, FALSE);
multi_done(&data->easy_conn, result, FALSE);
}
else if(done) {
followtype follow=FOLLOW_NONE;
@ -1756,7 +1915,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else
follow = FOLLOW_RETRY;
result = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
result = multi_done(&data->easy_conn, CURLE_OK, FALSE);
if(!result) {
result = Curl_follow(data, newurl, follow);
if(!result) {
@ -1806,14 +1965,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_multi_process_pending_handles(multi);
/* post-transfer command */
res = Curl_done(&data->easy_conn, result, FALSE);
res = multi_done(&data->easy_conn, result, FALSE);
/* allow a previously set error code take precedence */
if(!result)
result = res;
/*
* If there are other handles on the pipeline, Curl_done won't set
* If there are other handles on the pipeline, multi_done won't set
* easy_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
@ -1832,7 +1991,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* after we have DONE what we're supposed to do, go COMPLETED, and
it doesn't matter what the Curl_done() returned! */
it doesn't matter what the multi_done() returned! */
multistate(data, CURLM_STATE_COMPLETED);
break;

View File

@ -1166,10 +1166,6 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
(void)premature;
if(!pop3)
/* When the easy handle is removed from the multi interface while libcurl
is still trying to resolve the host name, the POP3 struct is not yet
initialized. However, the removal action calls Curl_done() which in
turn calls this function, so we simply return success. */
return CURLE_OK;
if(status) {

View File

@ -1204,10 +1204,6 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
(void)premature;
if(!smtp || !pp->conn)
/* When the easy handle is removed from the multi interface while libcurl
is still trying to resolve the host name, the SMTP struct is not yet
initialized. However, the removal action calls Curl_done() which in
turn calls this function, so we simply return success. */
return CURLE_OK;
if(status) {
@ -1262,8 +1258,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
TODO: when the multi interface is used, this _really_ should be using
the smtp_multi_statemach function but we have no general support for
non-blocking DONE operations, not in the multi state machine and with
Curl_done() invokes on several places in the code!
non-blocking DONE operations!
*/
result = smtp_block_statemach(conn);
}

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, 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
@ -3068,8 +3068,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
TODO: when the multi interface is used, this _really_ should be using
the ssh_multi_statemach function but we have no general support for
non-blocking DONE operations, not in the multi state machine and with
Curl_done() invokes on several places in the code!
non-blocking DONE operations!
*/
result = ssh_block_statemach(conn, FALSE);
}

171
lib/url.c
View File

@ -137,8 +137,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
/* Local static prototypes */
static struct connectdata *
find_oldest_idle_connection(struct SessionHandle *data);
static struct connectdata *
find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
struct connectbundle *bundle);
static void conn_free(struct connectdata *conn);
@ -2960,8 +2958,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
* Returns the pointer to the oldest idle connection, or NULL if none was
* found.
*/
static struct connectdata *
find_oldest_idle_connection(struct SessionHandle *data)
struct connectdata *
Curl_oldest_idle_connection(struct SessionHandle *data)
{
struct conncache *bc = data->state.conn_cache;
struct curl_hash_iterator iter;
@ -3493,38 +3491,6 @@ ConnectionExists(struct SessionHandle *data,
return FALSE; /* no matching connecting exists */
}
/* Mark the connection as 'idle', or close it if the cache is full.
Returns TRUE if the connection is kept, or FALSE if it was closed. */
static bool
ConnectionDone(struct SessionHandle *data, struct connectdata *conn)
{
/* data->multi->maxconnects can be negative, deal with it. */
size_t maxconnects =
(data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
data->multi->maxconnects;
struct connectdata *conn_candidate = NULL;
/* Mark the current connection as 'unused' */
conn->inuse = FALSE;
if(maxconnects > 0 &&
data->state.conn_cache->num_connections > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one.\n");
conn_candidate = find_oldest_idle_connection(data);
if(conn_candidate) {
/* Set the connection's owner correctly */
conn_candidate->data = data;
/* the winner gets the honour of being disconnected */
(void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
}
}
return (conn_candidate == conn) ? FALSE : TRUE;
}
/* after a TCP connection to the proxy has been verified, this function does
the next magic step.
@ -5891,7 +5857,7 @@ static CURLcode create_conn(struct SessionHandle *data,
struct connectdata *conn_candidate;
/* The cache is full. Let's see if we can kill a connection. */
conn_candidate = find_oldest_idle_connection(data);
conn_candidate = Curl_oldest_idle_connection(data);
if(conn_candidate) {
/* Set the connection's owner correctly, then kill it */
@ -6103,135 +6069,6 @@ CURLcode Curl_connect(struct SessionHandle *data,
return result;
}
CURLcode Curl_done(struct connectdata **connp,
CURLcode status, /* an error if this is called after an
error was detected */
bool premature)
{
CURLcode result;
struct connectdata *conn;
struct SessionHandle *data;
DEBUGASSERT(*connp);
conn = *connp;
data = conn->data;
DEBUGF(infof(data, "Curl_done\n"));
if(data->state.done)
/* Stop if Curl_done() has already been called */
return CURLE_OK;
Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */
free(data->req.newurl);
data->req.newurl = NULL;
free(data->req.location);
data->req.location = NULL;
switch(status) {
case CURLE_ABORTED_BY_CALLBACK:
case CURLE_READ_ERROR:
case CURLE_WRITE_ERROR:
/* When we're aborted due to a callback return code it basically have to
be counted as premature as there is trouble ahead if we don't. We have
many callbacks and protocols work differently, we could potentially do
this more fine-grained in the future. */
premature = TRUE;
default:
break;
}
/* this calls the protocol-specific function pointer previously set */
if(conn->handler->done)
result = conn->handler->done(conn, 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);
if(!result && rc)
result = CURLE_ABORTED_BY_CALLBACK;
}
if((!premature &&
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
connection. */
DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n"));
return CURLE_OK;
}
data->state.done = TRUE; /* called just now! */
Curl_resolver_cancel(conn);
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
conn->dns_entry = NULL;
}
/* 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;
/* 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
place in a NTLM authentication handshake
if conn->bits.close is TRUE, it means that the connection should be
closed in spite of all our efforts to be nice, due to protocol
restrictions in our or the server's end
if premature is TRUE, it means this connection was said to be DONE before
the entire request operation is complete and thus we can't know in what
state it is for re-using, so we're forced to close it. In a perfect world
we can add code that keep track of if we really must close it here or not,
but currently we have no such detail knowledge.
*/
if((data->set.reuse_forbid
#if defined(USE_NTLM)
&& !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
conn->proxyntlm.state == NTLMSTATE_TYPE2)
#endif
) || conn->bits.close || premature) {
CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
/* If we had an error already, make sure we return that one. But
if we got a new error, return that. */
if(!result && res2)
result = res2;
}
else {
/* the connection is no longer in use */
if(ConnectionDone(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect = conn;
infof(data, "Connection #%ld to host %s left intact\n",
conn->connection_id,
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
}
else
data->state.lastconnect = NULL;
}
*connp = NULL; /* to make the caller of this function better detect that
this was either closed or handed over to the connection
cache here, and therefore cannot be used from this point on
*/
Curl_free_request_state(data);
return result;
}
/*
* Curl_init_do() inits the readwrite session. This is inited each time (in
* the DO function before the protocol-specific DO functions are invoked) for
@ -6250,7 +6087,7 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
* use */
data->state.done = FALSE; /* Curl_done() is not called yet */
data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
if(data->set.opt_no_body)

View File

@ -37,7 +37,6 @@ void Curl_freeset(struct SessionHandle * data);
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
bool *async, bool *protocol_connect);
CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
CURLcode Curl_disconnect(struct connectdata *, bool dead_connection);
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
@ -58,6 +57,8 @@ CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle,
struct curl_llist *pipeline);
int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
struct curl_llist *pipeline);
struct connectdata *
Curl_oldest_idle_connection(struct SessionHandle *data);
/* remove the specified connection from all (possible) pipelines and related
queues */
void Curl_getoff_all_pipelines(struct SessionHandle *data,