pipelining: removed

As previously planned and documented in DEPRECATE.md, all pipelining
code is removed.

Closes #3651
This commit is contained in:
Daniel Stenberg 2019-04-05 16:38:36 +02:00
parent aba1c51553
commit 2f44e94efb
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
28 changed files with 190 additions and 1401 deletions

View file

@ -41,7 +41,6 @@
#include "speedcheck.h"
#include "conncache.h"
#include "multihandle.h"
#include "pipeline.h"
#include "sigpipe.h"
#include "vtls/vtls.h"
#include "connect.h"
@ -136,12 +135,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL, /* WAITPROXYCONNECT */
NULL, /* SENDPROTOCONNECT */
NULL, /* PROTOCONNECT */
NULL, /* WAITDO */
Curl_connect_free, /* DO */
NULL, /* DOING */
NULL, /* DO_MORE */
NULL, /* DO_DONE */
NULL, /* WAITPERFORM */
NULL, /* PERFORM */
NULL, /* TOOFAST */
NULL, /* DONE */
@ -349,9 +346,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_llist_init(&multi->msglist, multi_freeamsg);
Curl_llist_init(&multi->pending, multi_freeamsg);
multi->max_pipeline_length = 5;
multi->pipelining = CURLPIPE_MULTIPLEX;
/* -1 means it not set by user, use the default value */
multi->maxconnects = -1;
return multi;
@ -440,12 +434,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->psl = &multi->psl;
#endif
/* This adds the new entry at the 'end' of the doubly-linked circular
list of Curl_easy structs to try and maintain a FIFO queue so
the pipelined requests are in order. */
/* We add this new entry last in the list. */
/* We add the new entry last in the list. */
data->next = NULL; /* end of the line */
if(multi->easyp) {
struct Curl_easy *last = multi->easylp;
@ -538,8 +527,6 @@ static CURLcode multi_done(struct Curl_easy *data,
/* Stop the resolver and free its own resources (but not dns_entry yet). */
Curl_resolver_kill(conn);
Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */
Curl_safefree(data->req.newurl);
Curl_safefree(data->req.location);
@ -573,12 +560,12 @@ static CURLcode multi_done(struct Curl_easy *data,
process_pending_handles(data->multi); /* connection / multiplex */
if(conn->send_pipe.size || conn->recv_pipe.size) {
/* Stop if pipeline is not empty . */
detach_connnection(data);
DEBUGF(infof(data, "Connection still in use %zu/%zu, "
detach_connnection(data);
if(CONN_INUSE(conn)) {
/* Stop if still used. */
DEBUGF(infof(data, "Connection still in use %zu, "
"no more multi_done now!\n",
conn->send_pipe.size, conn->recv_pipe.size));
conn->easyq.size));
return CURLE_OK;
}
@ -652,7 +639,6 @@ static CURLcode multi_done(struct Curl_easy *data,
data->state.lastconnect = NULL;
}
detach_connnection(data);
Curl_free_request_state(data);
return result;
}
@ -698,9 +684,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
data->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->conn, "Removed with partial response");
easy_owns_conn = TRUE;
}
@ -723,9 +706,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
nothing really useful to do with it anyway! */
(void)multi_done(data, data->result, premature);
}
else
/* Clear connection pipelines, if multi_done above was not called */
Curl_getoff_all_pipelines(data, data->conn);
}
if(data->connect_queue.ptr)
@ -803,16 +783,19 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
return CURLM_OK;
}
/* Return TRUE if the application asked for a certain set of pipelining */
bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
/* Return TRUE if the application asked for multiplexing */
bool Curl_multiplex_wanted(const struct Curl_multi *multi)
{
return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
return (multi && (multi->multiplexing));
}
/* This is the only function that should clear data->conn. This will
occasionally be called with the pointer already cleared. */
static void detach_connnection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
if(conn)
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
data->conn = NULL;
}
@ -821,7 +804,10 @@ void Curl_attach_connnection(struct Curl_easy *data,
struct connectdata *conn)
{
DEBUGASSERT(!data->conn);
DEBUGASSERT(conn);
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
}
static int waitconnect_getsock(struct connectdata *conn,
@ -935,7 +921,6 @@ static int multi_getsock(struct Curl_easy *data,
to waiting for the same as the *PERFORM
states */
case CURLM_STATE_PERFORM:
case CURLM_STATE_WAITPERFORM:
return Curl_single_getsock(data->conn, socks, numsocks);
}
@ -1203,7 +1188,7 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
* 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 in the pipeline.
* before receiving any header data for the current request.
*/
static void do_complete(struct connectdata *conn)
{
@ -1216,6 +1201,9 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
DEBUGASSERT(conn);
DEBUGASSERT(conn->handler);
if(conn->handler->do_it) {
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->handler->do_it(conn, done);
@ -1266,7 +1254,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
struct SingleRequest *k;
timediff_t timeout_ms;
timediff_t recv_timeout_ms;
timediff_t send_timeout_ms;
@ -1293,7 +1280,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(multi_ischanged(multi, TRUE)) {
DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
process_pending_handles(multi); /* pipelined/multiplexed */
process_pending_handles(multi); /* multiplexed */
}
if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
@ -1308,7 +1295,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* 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, &now,
(data->mstate <= CURLM_STATE_WAITDO)?
(data->mstate <= CURLM_STATE_DO)?
TRUE:FALSE);
if(timeout_ms < 0) {
@ -1322,7 +1309,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
" milliseconds",
Curl_timediff(now, data->progress.t_startsingle));
else {
k = &data->req;
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 %"
@ -1392,31 +1379,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!result) {
/* Add this handle to the send or pend pipeline */
result = Curl_add_handle_to_pipeline(data, data->conn);
if(result)
stream_error = TRUE;
if(async)
/* We're now waiting for an asynchronous name lookup */
multistate(data, CURLM_STATE_WAITRESOLVE);
else {
if(async)
/* We're now waiting for an asynchronous name lookup */
multistate(data, CURLM_STATE_WAITRESOLVE);
else {
/* after the connect has been sent off, go WAITCONNECT unless the
protocol connect is already done and we can go directly to
WAITDO or DO! */
rc = CURLM_CALL_MULTI_PERFORM;
/* after the connect has been sent off, go WAITCONNECT unless the
protocol connect is already done and we can go directly to
WAITDO or DO! */
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connect)
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
else {
if(protocol_connect)
multistate(data, CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
if(Curl_connect_ongoing(data->conn))
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
else
if(Curl_connect_ongoing(data->conn))
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
else
#endif
multistate(data, CURLM_STATE_WAITCONNECT);
}
multistate(data, CURLM_STATE_WAITCONNECT);
}
}
}
@ -1429,6 +1409,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct connectdata *conn = data->conn;
const char *hostname;
DEBUGASSERT(conn);
if(conn->bits.httpproxy)
hostname = conn->http_proxy.host.name;
else if(conn->bits.conn_to_host)
@ -1472,8 +1453,7 @@ 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_connect)
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
multistate(data, CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
if(Curl_connect_ongoing(data->conn))
@ -1496,6 +1476,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_HTTP
case CURLM_STATE_WAITPROXYCONNECT:
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
DEBUGASSERT(data->conn);
result = Curl_http_connect(data->conn, &protocol_connect);
if(data->conn->bits.proxy_connect_closed) {
@ -1521,6 +1502,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_WAITCONNECT:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
#ifndef CURL_DISABLE_HTTP
@ -1552,8 +1534,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_PROTOCONNECT);
else if(!result) {
/* protocol connect has completed, go WAITDO or DO */
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
multistate(data, CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else if(result) {
@ -1569,8 +1550,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = Curl_protocol_connecting(data->conn, &protocol_connect);
if(!result && protocol_connect) {
/* after the connect has completed, go WAITDO or DO */
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
CURLM_STATE_WAITDO:CURLM_STATE_DO);
multistate(data, CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else if(result) {
@ -1581,15 +1561,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
case CURLM_STATE_WAITDO:
/* Wait for our turn to DO when we're pipelining requests */
if(Curl_pipeline_checkget_write(data, data->conn)) {
/* Grabbed the channel */
multistate(data, CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
break;
case CURLM_STATE_DO:
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
@ -1696,6 +1667,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_DOING:
/* we continue DOING until the DO phase is complete */
DEBUGASSERT(data->conn);
result = Curl_protocol_doing(data->conn,
&dophase_done);
if(!result) {
@ -1719,10 +1691,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/*
* When we are connected, DO MORE and then go DO_DONE
*/
DEBUGASSERT(data->conn);
result = multi_do_more(data->conn, &control);
/* No need to remove this handle from the send pipeline here since that
is done in multi_done() */
if(!result) {
if(control) {
/* if positive, advance to DO_DONE
@ -1745,38 +1716,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case CURLM_STATE_DO_DONE:
/* Move ourselves from the send to recv pipeline */
Curl_move_handle_from_send_to_recv_pipe(data, data->conn);
if(data->conn->bits.multiplex || data->conn->send_pipe.size)
DEBUGASSERT(data->conn);
if(data->conn->bits.multiplex)
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* pipelined/multiplexed */
process_pending_handles(multi); /* multiplexed */
/* Only perform the transfer if there's a good socket to work with.
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_WAITPERFORM);
multistate(data, CURLM_STATE_PERFORM);
else {
if(data->state.wildcardmatch &&
((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
data->wildcard.state = CURLWC_DONE;
data->wildcard.state = CURLWC_DONE;
}
multistate(data, CURLM_STATE_DONE);
}
rc = CURLM_CALL_MULTI_PERFORM;
break;
case CURLM_STATE_WAITPERFORM:
/* Wait for our turn to PERFORM */
if(Curl_pipeline_checkget_read(data, data->conn)) {
/* Grabbed the channel */
multistate(data, CURLM_STATE_PERFORM);
rc = CURLM_CALL_MULTI_PERFORM;
}
break;
case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
DEBUGASSERT(data->conn);
/* if both rates are within spec, resume transfer */
if(Curl_pgrsUpdate(data->conn))
result = CURLE_ABORTED_BY_CALLBACK;
@ -1850,18 +1811,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* read/write data if it is ready to do so */
result = Curl_readwrite(data->conn, data, &done, &comeback);
k = &data->req;
if(!(k->keepon & KEEP_RECV)) {
/* We're done receiving */
Curl_pipeline_leave_read(data->conn);
}
if(!(k->keepon & KEEP_SEND)) {
/* We're done sending */
Curl_pipeline_leave_write(data->conn);
}
if(done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
* condition and the server closed the re-used connection exactly when
@ -1924,13 +1873,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
/* we're no longer receiving */
Curl_removeHandleFromPipeline(data, &data->conn->recv_pipe);
/* expire the new receiving pipeline head */
if(data->conn->recv_pipe.head)
Curl_expire(data->conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
/* 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) {
@ -1988,12 +1930,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->conn) {
CURLcode res;
/* Remove ourselves from the receive pipeline, if we are there. */
Curl_removeHandleFromPipeline(data, &data->conn->recv_pipe);
if(data->conn->bits.multiplex || data->conn->send_pipe.size)
if(data->conn->bits.multiplex)
/* Check if we can move pending requests to connection */
process_pending_handles(multi); /* pipelined/multiplexing */
process_pending_handles(multi); /* multiplexing */
/* post-transfer command */
res = multi_done(data, result, FALSE);
@ -2003,7 +1942,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = res;
/*
* If there are other handles on the pipeline, multi_done won't set
* 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
@ -2052,12 +1991,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
process_pending_handles(multi); /* connection */
if(data->conn) {
/* if this has a connection, unsubscribe from the pipelines */
Curl_pipeline_leave_write(data->conn);
Curl_pipeline_leave_read(data->conn);
Curl_removeHandleFromPipeline(data, &data->conn->send_pipe);
Curl_removeHandleFromPipeline(data, &data->conn->recv_pipe);
if(stream_error) {
/* Don't attempt to send data over a connection that timed out */
bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
@ -2218,12 +2151,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
/* Free the blacklists by setting them to NULL */
(void)Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
(void)Curl_pipeline_set_server_blacklist(NULL,
&multi->pipelining_server_bl);
free(multi);
return CURLM_OK;
@ -2576,19 +2503,6 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
/* bad bad bad bad bad bad bad */
return CURLM_INTERNAL_ERROR;
/* If the pipeline is enabled, take the handle which is in the head of
the pipeline. If we should write into the socket, take the
send_pipe head. If we should read from the socket, take the
recv_pipe head. */
if(data->conn) {
if((ev_bitmask & CURL_POLL_OUT) &&
data->conn->send_pipe.head)
data = data->conn->send_pipe.head->ptr;
else if((ev_bitmask & CURL_POLL_IN) &&
data->conn->recv_pipe.head)
data = data->conn->recv_pipe.head->ptr;
}
if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
/* set socket event bitmask if they're not locked */
data->conn->cselect_bits = ev_bitmask;
@ -2695,7 +2609,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
multi->push_userp = va_arg(param, void *);
break;
case CURLMOPT_PIPELINING:
multi->pipelining = va_arg(param, long) & CURLPIPE_MULTIPLEX;
multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX;
break;
case CURLMOPT_TIMERFUNCTION:
multi->timer_cb = va_arg(param, curl_multi_timer_callback);
@ -2709,26 +2623,20 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
case CURLMOPT_MAX_HOST_CONNECTIONS:
multi->max_host_connections = va_arg(param, long);
break;
case CURLMOPT_MAX_PIPELINE_LENGTH:
multi->max_pipeline_length = va_arg(param, long);
break;
case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
multi->content_length_penalty_size = va_arg(param, long);
break;
case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
multi->chunk_length_penalty_size = va_arg(param, long);
break;
case CURLMOPT_PIPELINING_SITE_BL:
res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
&multi->pipelining_site_bl);
break;
case CURLMOPT_PIPELINING_SERVER_BL:
res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
&multi->pipelining_server_bl);
break;
case CURLMOPT_MAX_TOTAL_CONNECTIONS:
multi->max_total_connections = va_arg(param, long);
break;
/* options formerly used for pipelining */
case CURLMOPT_MAX_PIPELINE_LENGTH:
break;
case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
break;
case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
break;
case CURLMOPT_PIPELINING_SITE_BL:
break;
case CURLMOPT_PIPELINING_SERVER_BL:
break;
default:
res = CURLM_UNKNOWN_OPTION;
break;
@ -3080,26 +2988,6 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
return multi ? multi->max_total_connections : 0;
}
curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
{
return multi ? multi->content_length_penalty_size : 0;
}
curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
{
return multi ? multi->chunk_length_penalty_size : 0;
}
struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
{
return &multi->pipelining_site_bl;
}
struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
{
return &multi->pipelining_server_bl;
}
static void process_pending_handles(struct Curl_multi *multi)
{
struct curl_llist_element *e = multi->pending.head;