summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/multi.c')
-rw-r--r--libs/libcurl/src/multi.c134
1 files changed, 65 insertions, 69 deletions
diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c
index c1d48a3ed9..0caf94322b 100644
--- a/libs/libcurl/src/multi.c
+++ b/libs/libcurl/src/multi.c
@@ -107,6 +107,16 @@ 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)
+{
+ /* this is a completed transfer */
+
+ /* Important: reset the conn pointer so that we don't point to memory
+ that could be freed anytime */
+ data->easy_conn = NULL;
+ Curl_expire_clear(data); /* stop all timers */
+}
+
/* always use this function to change state, to make debugging easier */
static void mstate(struct Curl_easy *data, CURLMstate state
#ifdef DEBUGBUILD
@@ -116,17 +126,25 @@ static void mstate(struct Curl_easy *data, CURLMstate state
{
CURLMstate oldstate = data->mstate;
static const init_multistate_func finit[CURLM_STATE_LAST] = {
- NULL,
- NULL,
+ NULL, /* INIT */
+ NULL, /* CONNECT_PEND */
Curl_init_CONNECT, /* CONNECT */
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- Curl_connect_free /* DO */
- /* the rest is NULL too */
+ NULL, /* WAITRESOLVE */
+ NULL, /* WAITCONNECT */
+ 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 */
+ Curl_init_completed, /* COMPLETED */
+ NULL /* MSGSENT */
};
#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -574,6 +592,7 @@ static CURLcode multi_done(struct connectdata **connp,
conn->dns_entry = NULL;
}
Curl_hostcache_prune(data);
+ Curl_safefree(data->state.ulbuf);
/* if the transfer was completed in a paused state there can be buffered
data left to free */
@@ -604,7 +623,7 @@ static CURLcode multi_done(struct connectdata **connp,
#endif
) || conn->bits.close
|| (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
- CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
+ CURLcode res2 = Curl_disconnect(data, conn, premature);
/* If we had an error already, make sure we return that one. But
if we got a new error, return that. */
@@ -622,7 +641,7 @@ static CURLcode multi_done(struct connectdata **connp,
conn->bits.conn_to_host ? conn->conn_to_host.dispname :
conn->host.dispname);
- /* the connection is no longer in use */
+ /* the connection is no longer in use by this transfer */
if(Curl_conncache_return_conn(conn)) {
/* remember the most recently used connection */
data->state.lastconnect = conn;
@@ -856,12 +875,10 @@ static int multi_getsock(struct Curl_easy *data,
of sockets */
int numsocks)
{
- /* If the pipe broke, or if there's no connection left for this easy handle,
- then we MUST bail out now with no bitmask set. The no connection case can
- happen when this is called from curl_multi_remove_handle() =>
- singlesocket() => multi_getsock().
+ /* The no connection case can happen when this is called from
+ curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
- if(data->state.pipe_broke || !data->easy_conn)
+ if(!data->easy_conn)
return 0;
if(data->mstate > CURLM_STATE_CONNECT &&
@@ -1334,24 +1351,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool stream_error = FALSE;
rc = CURLM_OK;
- /* Handle the case when the pipe breaks, i.e., the connection
- we're using gets cleaned up and we're left with nothing. */
- if(data->state.pipe_broke) {
- infof(data, "Pipe broke: handle %p, url = %s\n",
- (void *)data, data->state.path);
-
- if(data->mstate < CURLM_STATE_COMPLETED) {
- /* Head back to the CONNECT state */
- multistate(data, CURLM_STATE_CONNECT);
- rc = CURLM_CALL_MULTI_PERFORM;
- result = CURLE_OK;
- }
-
- data->state.pipe_broke = FALSE;
- data->easy_conn = NULL;
- continue;
- }
-
if(!data->easy_conn &&
data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_DONE) {
@@ -1577,6 +1576,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_SENDPROTOCONNECT);
}
}
+ else if(result)
+ stream_error = TRUE;
break;
#endif
@@ -1931,6 +1932,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
if(!ret)
retry = (newurl)?TRUE:FALSE;
+ else if(!result)
+ result = ret;
if(retry) {
/* if we are to retry, set the result to OK and consider the
@@ -2062,16 +2065,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case CURLM_STATE_COMPLETED:
- /* this is a completed transfer, it is likely to still be connected */
-
- /* This node should be delinked from the list now and we should post
- an information message that we are complete. */
-
- /* Important: reset the conn pointer so that we don't point to memory
- that could be freed anytime */
- data->easy_conn = NULL;
-
- Curl_expire_clear(data); /* stop all timers */
break;
case CURLM_STATE_MSGSENT:
@@ -2093,8 +2086,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* NOTE: no attempt to disconnect connections must be made
in the case blocks above - cleanup happens only here */
- data->state.pipe_broke = FALSE;
-
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* connection */
@@ -2109,7 +2100,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Don't attempt to send data over a connection that timed out */
bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
/* disconnect properly */
- Curl_disconnect(data->easy_conn, dead_connection);
+ Curl_disconnect(data, data->easy_conn, dead_connection);
/* This is where we make sure that the easy_conn pointer is reset.
We don't have to do this in every case block above where a
@@ -2123,6 +2114,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
multistate(data, CURLM_STATE_COMPLETED);
+ rc = CURLM_CALL_MULTI_PERFORM;
}
/* if there's still a connection to use, call the progress function */
else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
@@ -2147,14 +2139,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
msg->extmsg.data.result = result;
rc = multi_addmsg(multi, msg);
-
+ DEBUGASSERT(!data->easy_conn);
multistate(data, CURLM_STATE_MSGSENT);
}
} while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
data->result = result;
-
-
return rc;
}
@@ -2471,20 +2461,23 @@ void Curl_updatesocket(struct Curl_easy *data)
void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
{
- struct Curl_multi *multi = conn->data->multi;
- if(multi) {
- /* this is set if this connection is part of a handle that is added to
- a multi handle, and only then this is necessary */
- struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
-
- if(entry) {
- if(multi->socket_cb)
- multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
- multi->socket_userp,
- entry->socketp);
+ if(conn->data) {
+ /* if there's still an easy handle associated with this connection */
+ struct Curl_multi *multi = conn->data->multi;
+ if(multi) {
+ /* this is set if this connection is part of a handle that is added to
+ a multi handle, and only then this is necessary */
+ struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
+
+ if(entry) {
+ if(multi->socket_cb)
+ multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
+ multi->socket_userp,
+ entry->socketp);
- /* now remove it from the socket hash */
- sh_delentry(&multi->sockhash, s);
+ /* now remove it from the socket hash */
+ sh_delentry(&multi->sockhash, s);
+ }
}
}
}
@@ -3135,12 +3128,15 @@ static void process_pending_handles(struct Curl_multi *multi)
}
}
-void Curl_set_in_callback(struct Curl_easy *easy, bool value)
+void Curl_set_in_callback(struct Curl_easy *data, bool value)
{
- if(easy->multi_easy)
- easy->multi_easy->in_callback = value;
- else if(easy->multi)
- easy->multi->in_callback = value;
+ /* might get called when there is no data pointer! */
+ if(data) {
+ if(data->multi_easy)
+ data->multi_easy->in_callback = value;
+ else if(data->multi)
+ data->multi->in_callback = value;
+ }
}
bool Curl_is_in_callback(struct Curl_easy *easy)