summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/multi.c')
-rw-r--r--Utilities/cmcurl/lib/multi.c217
1 files changed, 107 insertions, 110 deletions
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 86e36be..85707a1 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * 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
@@ -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);
@@ -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 when the PERFORM state starts */
+static void init_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 */
@@ -136,10 +143,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL, /* DOING */
NULL, /* DO_MORE */
NULL, /* DO_DONE */
- NULL, /* PERFORM */
+ init_perform, /* PERFORM */
NULL, /* TOOFAST */
NULL, /* DONE */
- Curl_init_completed, /* COMPLETED */
+ init_completed, /* COMPLETED */
NULL /* MSGSENT */
};
@@ -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;
@@ -558,7 +565,7 @@ static CURLcode multi_done(struct Curl_easy *data,
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);
@@ -579,14 +586,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;
}
@@ -690,17 +697,13 @@ 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;
@@ -809,7 +812,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
@@ -938,27 +941,30 @@ static int waitproxyconnect_getsock(struct connectdata *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. */
@@ -971,10 +977,11 @@ 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 &&
@@ -988,30 +995,30 @@ static int multi_getsock(struct Curl_easy *data,
return 0;
case CURLM_STATE_WAITRESOLVE:
- return Curl_resolv_getsock(data->conn, socks);
+ return Curl_resolv_getsock(data, socks);
case CURLM_STATE_PROTOCONNECT:
case CURLM_STATE_SENDPROTOCONNECT:
- return protocol_getsock(data->conn, socks);
+ return protocol_getsock(data, conn, socks);
case CURLM_STATE_DO:
case CURLM_STATE_DOING:
- return doing_getsock(data->conn, socks);
+ return doing_getsock(data, conn, socks);
case CURLM_STATE_WAITPROXYCONNECT:
- return waitproxyconnect_getsock(data->conn, socks);
+ return waitproxyconnect_getsock(conn, socks);
case CURLM_STATE_WAITCONNECT:
- return waitconnect_getsock(data->conn, socks);
+ return waitconnect_getsock(conn, socks);
case CURLM_STATE_DO_MORE:
- return domore_getsock(data->conn, socks);
+ 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);
+ return Curl_single_getsock(data, conn, socks);
}
}
@@ -1067,13 +1074,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];
@@ -1281,8 +1288,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,
@@ -1291,8 +1298,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)
@@ -1319,7 +1326,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) {
@@ -1383,18 +1390,6 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
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;
@@ -1404,14 +1399,10 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
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;
}
@@ -1424,18 +1415,15 @@ 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;
}
@@ -1446,14 +1434,14 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete)
* 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;
@@ -1466,13 +1454,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;
@@ -1485,11 +1474,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);
@@ -1510,7 +1499,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;
@@ -1528,7 +1517,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;
@@ -1589,9 +1578,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
process_pending_handles(multi); /* multiplexed */
}
- if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
+ if(data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Make sure we set the connection's current owner */
+ DEBUGASSERT(data->conn);
+ if(!data->conn)
+ return CURLM_INTERNAL_ERROR;
data->conn->data = data;
}
@@ -1737,19 +1729,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);
}
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
@@ -1762,7 +1754,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
@@ -1796,7 +1788,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
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_connected);
+ result = Curl_http_connect(data, &protocol_connected);
#ifndef CURL_DISABLE_PROXY
if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1827,7 +1819,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);
+ result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
#ifndef CURL_DISABLE_HTTP
if(
@@ -1860,7 +1852,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case CURLM_STATE_SENDPROTOCONNECT:
- result = protocol_connect(data->conn, &protocol_connected);
+ result = protocol_connect(data, &protocol_connected);
if(!result && !protocol_connected)
/* switch to waiting state */
multistate(data, CURLM_STATE_PROTOCONNECT);
@@ -1879,7 +1871,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_PROTOCONNECT:
/* 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);
@@ -1916,7 +1908,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 ?
+ CURLM_STATE_DONE : CURLM_STATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
break;
}
@@ -1952,7 +1947,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;
@@ -2002,7 +1997,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 = 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 */
@@ -2025,7 +2020,7 @@ 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);
+ result = multi_do_more(data, &control);
if(!result) {
if(control) {
@@ -2074,12 +2069,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
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))
+ 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)
send_timeout_ms =
@@ -2151,7 +2154,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)
@@ -2166,7 +2169,7 @@ 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);
+ CURLcode ret = Curl_retry_request(data, &newurl);
if(!ret) {
infof(data, "Downgrades to HTTP/1.1!\n");
@@ -2203,7 +2206,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);
@@ -2211,6 +2213,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 */
@@ -2280,14 +2283,6 @@ 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
@@ -2357,7 +2352,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
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;
@@ -2458,7 +2453,7 @@ 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 */
data = multi->easyp;
@@ -3329,16 +3324,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)