summaryrefslogtreecommitdiff
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.c152
1 files changed, 97 insertions, 55 deletions
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 1b3e261c68..85097816db 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -169,7 +169,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
connection_id = data->conn->connection_id;
infof(data,
- "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
+ "STATE: %s => %s handle %p; line %d (connection #%ld)",
statename[oldstate], statename[data->mstate],
(void *)data, lineno, connection_id);
}
@@ -562,7 +562,7 @@ static CURLcode multi_done(struct Curl_easy *data,
struct connectdata *conn = data->conn;
unsigned int i;
- DEBUGF(infof(data, "multi_done\n"));
+ DEBUGF(infof(data, "multi_done"));
if(data->state.done)
/* Stop if multi_done() has already been called */
@@ -610,7 +610,7 @@ static CURLcode multi_done(struct Curl_easy *data,
/* Stop if still used. */
CONNCACHE_UNLOCK(data);
DEBUGF(infof(data, "Connection still in use %zu, "
- "no more multi_done now!\n",
+ "no more multi_done now!",
conn->easyq.size));
return CURLE_OK;
}
@@ -687,7 +687,7 @@ static CURLcode multi_done(struct Curl_easy *data,
if(Curl_conncache_return_conn(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect_id = conn->connection_id;
- infof(data, "%s\n", buffer);
+ infof(data, "%s", buffer);
}
else
data->state.lastconnect_id = -1;
@@ -709,7 +709,6 @@ static int close_connect_only(struct Curl_easy *data,
return 1;
connclose(conn, "Removing connect-only easy handle");
- conn->bits.connect_only = FALSE;
return 1;
}
@@ -1043,7 +1042,12 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
data = multi->easyp;
while(data) {
- int bitmap = multi_getsock(data, sockbunch);
+ int bitmap;
+#ifdef __clang_analyzer_
+ /* to prevent "The left operand of '>=' is a garbage value" warnings */
+ memset(sockbunch, 0, sizeof(sockbunch));
+#endif
+ bitmap = multi_getsock(data, sockbunch);
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
@@ -1096,6 +1100,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
WSANETWORKEVENTS wsa_events;
DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
#endif
+#ifndef ENABLE_WAKEUP
+ (void)use_wakeup;
+#endif
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -1176,7 +1183,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#ifdef USE_WINSOCK
long mask = 0;
#endif
- if(bitmap & GETSOCK_READSOCK(i)) {
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
s = sockbunch[i];
#ifdef USE_WINSOCK
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
@@ -1185,7 +1192,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
ufds[nfds].events = POLLIN;
++nfds;
}
- if(bitmap & GETSOCK_WRITESOCK(i)) {
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
s = sockbunch[i];
#ifdef USE_WINSOCK
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
@@ -1540,6 +1547,58 @@ static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
}
/*
+ * Check whether a timeout occurred, and handle it if it did
+ */
+static bool multi_handle_timeout(struct Curl_easy *data,
+ struct curltime *now,
+ bool *stream_error,
+ CURLcode *result,
+ bool connect_timeout)
+{
+ timediff_t timeout_ms;
+ timeout_ms = Curl_timeleft(data, now, connect_timeout);
+
+ if(timeout_ms < 0) {
+ /* Handle timed out */
+ if(data->mstate == MSTATE_RESOLVING)
+ failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
+ else if(data->mstate == MSTATE_CONNECTING)
+ failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
+ else {
+ 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 %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount, k->size);
+ }
+ else {
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+ " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount);
+ }
+ }
+
+ /* Force connection closed if the connection has indeed been used */
+ if(data->mstate > MSTATE_DO) {
+ streamclose(data->conn, "Disconnected with pending data");
+ *stream_error = TRUE;
+ }
+ *result = CURLE_OPERATION_TIMEDOUT;
+ (void)multi_done(data, *result, TRUE);
+ }
+
+ return (timeout_ms < 0);
+}
+
+/*
* We are doing protocol-specific connecting and this is being called over and
* over from the multi interface until the connection phase is done on
* protocol layer.
@@ -1670,7 +1729,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
timediff_t recv_timeout_ms;
timediff_t send_timeout_ms;
int control;
@@ -1685,7 +1743,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_OK;
if(multi_ischanged(multi, TRUE)) {
- DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+ DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!"));
process_pending_handles(multi); /* multiplexed */
}
@@ -1700,47 +1758,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->conn &&
(data->mstate >= MSTATE_CONNECT) &&
(data->mstate < MSTATE_COMPLETED)) {
+ /* Check for overall operation timeout here but defer handling the
+ * connection timeout to later, to allow for a connection to be set up
+ * in the window since we last checked timeout. This prevents us
+ * tearing down a completed connection in the case where we were slow
+ * to check the timeout (e.g. process descheduled during this loop).
+ * We set connect_timeout=FALSE to do this. */
+
/* 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, nowp,
- (data->mstate <= MSTATE_DO)?
- TRUE:FALSE);
-
- if(timeout_ms < 0) {
- /* Handle timed out */
- if(data->mstate == MSTATE_RESOLVING)
- failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*nowp, data->progress.t_startsingle));
- else if(data->mstate == MSTATE_CONNECTING)
- failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*nowp, data->progress.t_startsingle));
- else {
- 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 %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
- k->bytecount, k->size);
- }
- else {
- failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds with %" CURL_FORMAT_CURL_OFF_T
- " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
- k->bytecount);
- }
- }
-
- /* Force connection closed if the connection has indeed been used */
- if(data->mstate > MSTATE_DO) {
- streamclose(data->conn, "Disconnected with pending data");
- stream_error = TRUE;
- }
- result = CURLE_OPERATION_TIMEDOUT;
- (void)multi_done(data, result, TRUE);
+ if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
@@ -1792,7 +1819,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else if(data->state.previouslypending) {
/* this transfer comes from the pending queue so try move another */
- infof(data, "Transfer was pending, now try another\n");
+ infof(data, "Transfer was pending, now try another");
process_pending_handles(data->multi);
}
@@ -1847,7 +1874,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->state.async.done = TRUE;
#endif
result = CURLE_OK;
- infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
+ infof(data, "Hostname '%s' was found in DNS cache", hostname);
}
if(!dns)
@@ -2279,7 +2306,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLcode ret = Curl_retry_request(data, &newurl);
if(!ret) {
- infof(data, "Downgrades to HTTP/1.1!\n");
+ infof(data, "Downgrades to HTTP/1.1!");
streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
data->state.httpwant = CURL_HTTP_VERSION_1_1;
/* clear the error message bit too as we ignore the one we got */
@@ -2418,6 +2445,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
default:
return CURLM_INTERNAL_ERROR;
}
+
+ if(data->conn &&
+ data->mstate >= MSTATE_CONNECT &&
+ data->mstate < MSTATE_DO &&
+ rc != CURLM_CALL_MULTI_PERFORM &&
+ !multi_ischanged(multi, false)) {
+ /* We now handle stream timeouts if and only if this will be the last
+ * loop iteration. We only check this on the last iteration to ensure
+ * that if we know we have additional work to do immediately
+ * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
+ * declaring the connection timed out as we may almost have a completed
+ * connection. */
+ multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
+ }
+
statemachine_end:
if(data->mstate < MSTATE_COMPLETED) {
@@ -3339,7 +3381,7 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
rc = Curl_splayremove(multi->timetree, &data->state.timenode,
&multi->timetree);
if(rc)
- infof(data, "Internal error removing splay node = %d\n", rc);
+ infof(data, "Internal error removing splay node = %d", rc);
}
/* Indicate that we are in the splay tree and insert the new timer expiry
@@ -3386,7 +3428,7 @@ void Curl_expire_clear(struct Curl_easy *data)
rc = Curl_splayremove(multi->timetree, &data->state.timenode,
&multi->timetree);
if(rc)
- infof(data, "Internal error clearing splay node = %d\n", rc);
+ infof(data, "Internal error clearing splay node = %d", rc);
/* flush the timeout list too */
while(list->size > 0) {
@@ -3394,7 +3436,7 @@ void Curl_expire_clear(struct Curl_easy *data)
}
#ifdef DEBUGBUILD
- infof(data, "Expire cleared (transfer %p)\n", data);
+ infof(data, "Expire cleared (transfer %p)", data);
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;