connect: connection close tweaks

- connclose/streamclose/connkeep() remove description string that was
  never used anywhere. Add trace statements where reasons for closing
  were not already traced and maybe not obvious.
- multi_remove_handle: only lookup former connection in pool when
  transfer is set to connect only
- test1554: adapt expectations now that pool is less often locked

Closes #22379
This commit is contained in:
Stefan Eissing 2026-07-23 14:17:13 +02:00 committed by Daniel Stenberg
parent a954d87f0b
commit e093c67f1c
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
26 changed files with 157 additions and 226 deletions

View file

@ -600,11 +600,9 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
{
struct Curl_cfilter *cf;
if(!CONN_SOCK_IDX_VALID(sockindex))
if(!conn || !CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
cf = conn ? conn->cfilter[sockindex] : NULL;
for(; cf; cf = cf->next) {
for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_MULTIPLEX)
return TRUE;
if(cf->cft->flags & (CF_TYPE_IP_CONNECT | CF_TYPE_SSL))

View file

@ -811,40 +811,6 @@ struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
return fctx.conn;
}
struct cpool_do_conn_ctx {
curl_off_t id;
Curl_cpool_conn_do_cb *cb;
void *cbdata;
};
static int cpool_do_conn(struct Curl_easy *data,
struct connectdata *conn, void *param)
{
struct cpool_do_conn_ctx *dctx = param;
if(conn->connection_id == dctx->id) {
dctx->cb(conn, data, dctx->cbdata);
return 1;
}
return 0;
}
void Curl_cpool_do_by_id(struct Curl_easy *data, curl_off_t conn_id,
Curl_cpool_conn_do_cb *cb, void *cbdata)
{
struct cpool *cpool = cpool_get_instance(data);
struct cpool_do_conn_ctx dctx;
if(!cpool)
return;
dctx.id = conn_id;
dctx.cb = cb;
dctx.cbdata = cbdata;
CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, &dctx, cpool_do_conn);
CPOOL_UNLOCK(cpool, data);
}
void Curl_cpool_do_locked(struct Curl_easy *data,
struct connectdata *conn,
Curl_cpool_conn_do_cb *cb, void *cbdata)

View file

@ -143,14 +143,6 @@ typedef void Curl_cpool_conn_do_cb(struct connectdata *conn,
struct Curl_easy *data,
void *cbdata);
/**
* Invoke the callback on the pool's connection with the
* given connection id (if it exists).
*/
void Curl_cpool_do_by_id(struct Curl_easy *data,
curl_off_t conn_id,
Curl_cpool_conn_do_cb *cb, void *cbdata);
/**
* Invoked the callback for the given data + connection under the
* connection pool's lock.

View file

@ -192,43 +192,41 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
if(!conn) {
data->state.lastconnect_id = -1;
if(connp)
*connp = NULL;
return CURL_SOCKET_BAD;
}
if(connp)
/* only store this if the caller cares for it */
*connp = conn;
return conn->sock[FIRSTSOCKET];
}
if(connp)
*connp = NULL;
return CURL_SOCKET_BAD;
}
/*
* Curl_conncontrol() marks streams or connection for closure.
*/
void Curl_conncontrol(struct connectdata *conn,
int ctrl /* see defines in header */
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
, const char *reason
#endif
)
void Curl_conncontrol(struct connectdata *conn, int ctrl)
{
/* close if a connection, or a stream that is not multiplexed. */
/* This function will be called both before and after this connection is
associated with a transfer. */
bool closeit, is_multiplex;
DEBUGASSERT(conn);
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
(void)reason; /* useful for debugging */
#endif
is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
closeit = (ctrl == CONNCTRL_CONNECTION) ||
((ctrl == CONNCTRL_STREAM) && !is_multiplex);
if((ctrl == CONNCTRL_STREAM) && is_multiplex)
; /* stream signal on multiplex conn never affects close state */
else if((curl_bit)closeit != conn->bits.close) {
conn->bits.close = closeit; /* the only place in the source code that
should assign this bit */
if(!conn) {
DEBUGASSERT(0);
return;
}
switch(ctrl) {
case CONNCTRL_CONN_KEEP:
conn->bits.close = FALSE;
break;
case CONNCTRL_CONN_CLOSE:
conn->bits.close = TRUE;
break;
case CONNCTRL_STREAM_CLOSE:
/* stream close when multiplexing does not affect connection */
if(!Curl_conn_is_multiplex(conn, FIRSTSOCKET))
conn->bits.close = TRUE;
break;
default:
DEBUGASSERT(0);
break;
}
}

View file

@ -70,37 +70,23 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
struct connectdata **connp);
/*
* Curl_conncontrol() marks the end of a connection/stream. The 'ctrl'
* argument specifies if it is the end of a connection or a stream.
*
* For stream-based protocols (such as HTTP/2), a stream close will not cause
* a connection close. Other protocols will close the connection for both
* cases.
*
* It sets the bit.close bit to TRUE (with an explanation for debug builds),
* when the connection will close.
* Curl_conncontrol() manipulates the `conn->bits.close` bit on
* a connection:
* - CONNCTRL_CONN_KEEP: clear the bit
* - CONNCTRL_CONN_CLOSE: set the bit
* - CONNCTRL_STREAM_CLOSE: set the bit when the connection is not
* multiplexed
* The call does *NOT* cause any immediate connection close.
*/
#define CONNCTRL_CONN_KEEP 0
#define CONNCTRL_CONN_CLOSE 1
#define CONNCTRL_STREAM_CLOSE 2
#define CONNCTRL_KEEP 0 /* undo a marked closure */
#define CONNCTRL_CONNECTION 1
#define CONNCTRL_STREAM 2
void Curl_conncontrol(struct connectdata *conn, int ctrl);
void Curl_conncontrol(struct connectdata *conn,
int ctrl
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
, const char *reason
#endif
);
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
#define streamclose(x, y) Curl_conncontrol(x, CONNCTRL_STREAM, y)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
#else /* !DEBUGBUILD || !CURLVERBOSE */
#define streamclose(x, y) Curl_conncontrol(x, CONNCTRL_STREAM)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP)
#endif
#define streamclose(x) Curl_conncontrol((x), CONNCTRL_STREAM_CLOSE)
#define connclose(x) Curl_conncontrol((x), CONNCTRL_CONN_CLOSE)
#define connkeep(x) Curl_conncontrol((x), CONNCTRL_CONN_KEEP)
/**
* Setup the cfilters at `sockindex` in connection `conn`.

View file

@ -758,13 +758,9 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* if the handle has a connection still attached (it is/was a connect-only
handle) then disconnect before performing */
if(data->conn) {
struct connectdata *c;
curl_socket_t s;
struct connectdata *conn = data->conn;
Curl_detach_connection(data);
s = Curl_getconnectinfo(data, &c);
if((s != CURL_SOCKET_BAD) && c) {
Curl_conn_terminate(data, c, TRUE);
}
Curl_conn_terminate(data, conn, TRUE);
DEBUGASSERT(!data->conn);
}

View file

@ -3610,7 +3610,7 @@ static CURLcode ftp_sendquote(struct Curl_easy *data,
return CURLE_OK;
}
static CURLcode ftp_done_status(struct connectdata *conn,
static CURLcode ftp_done_status(struct Curl_easy *data,
struct ftp_conn *ftpc, CURLcode status,
bool premature)
{
@ -3641,7 +3641,8 @@ static CURLcode ftp_done_status(struct connectdata *conn,
ftpc->ctl_valid = FALSE;
ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
current path, as this connection is going */
connclose(conn, "FTP ended with bad error code");
CURL_TRC_FTP(data, "FTP ended with bad error code");
connclose(data->conn);
return status; /* use the already set error code */
}
return CURLE_OK;
@ -3669,7 +3670,7 @@ static void ftp_done_path(struct Curl_easy *data, struct ftp_conn *ftpc,
/* We can limp along anyway (and should try to since we may already be in
* the error path) */
ftpc->ctl_valid = FALSE; /* mark control connection as bad */
connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
connclose(conn); /* mark for connection closure */
curlx_safefree(ftpc->prevpath); /* no path remembering */
}
else { /* remember working directory for connection reuse */
@ -3712,7 +3713,7 @@ static CURLcode ftp_done_secondary_socket(struct Curl_easy *data,
failf(data, "Failure sending ABOR command: %s",
curl_easy_strerror(result));
ftpc->ctl_valid = FALSE; /* mark control connection as bad */
connclose(conn, "ABOR command failed"); /* connection closure */
connclose(conn); /* connection closure */
}
}
@ -3744,7 +3745,7 @@ static CURLcode ftp_done_control_reply(struct Curl_easy *data,
if(!nread && (result == CURLE_OPERATION_TIMEDOUT)) {
failf(data, "control connection looks dead");
ftpc->ctl_valid = FALSE; /* mark control connection as bad */
connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
connclose(conn); /* close */
}
if(result)
@ -3754,7 +3755,7 @@ static CURLcode ftp_done_control_reply(struct Curl_easy *data,
/* we have sent ABOR and there is no reliable way to check if it was
* successful or not; we have to close the connection now */
infof(data, "partial download completed, closing connection");
connclose(conn, "Partial download with no ability to check");
connclose(conn);
return result;
}
@ -3838,7 +3839,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
if(!ftp || !ftpc)
return CURLE_OK;
result = ftp_done_status(data->conn, ftpc, status, premature);
result = ftp_done_status(data, ftpc, status, premature);
ftp_done_wildcard(data, ftpc);
ftp_done_path(data, ftpc, result);
@ -4299,7 +4300,7 @@ static CURLcode ftp_quit(struct Curl_easy *data,
failf(data, "Failure sending QUIT command: %s",
curl_easy_strerror(result));
ftpc->ctl_valid = FALSE; /* mark control connection as bad */
connclose(data->conn, "QUIT command failed"); /* mark for closure */
connclose(data->conn); /* mark for closure */
ftp_state(data, ftpc, FTP_STOP);
return result;
}

View file

@ -51,7 +51,7 @@ static CURLcode gopher_connecting(struct Curl_easy *data, bool *done)
result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
if(result)
connclose(conn, "Failed TLS connection");
connclose(conn);
*done = TRUE;
return result;
}

View file

@ -464,7 +464,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
ongoing_auth ? ongoing_auth : "",
ongoing_auth ? " send, " : "");
/* We decided to abort the ongoing transfer */
streamclose(conn, "Mid-auth HTTP and much data left to send");
streamclose(conn);
data->req.size = 0; /* do not download any more than 0 bytes */
data->req.http_bodyless = TRUE;
}
@ -577,7 +577,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
if(data->state.authhost.picked == CURLAUTH_NTLM &&
(data->req.httpversion_sent > 11)) {
infof(data, "Forcing HTTP/1.1 for NTLM");
connclose(conn, "Force HTTP/1.1 connection");
connclose(conn);
data->state.http_neg.wanted = CURL_HTTP_V1x;
data->state.http_neg.allowed = CURL_HTTP_V1x;
}
@ -1678,7 +1678,7 @@ CURLcode Curl_http_done(struct Curl_easy *data,
return an error here */
failf(data, "Empty reply from server");
/* Mark it as closed to avoid the "left intact" message */
streamclose(conn, "Empty reply from server");
streamclose(conn);
return CURLE_GOT_NOTHING;
}
@ -2711,7 +2711,7 @@ static CURLcode http_firstwrite(struct Curl_easy *data)
/* The resume point is at the end of file, consider this fine even if it
does not allow resume from here. */
infof(data, "The entire document is already downloaded");
streamclose(conn, "already downloaded");
streamclose(conn);
/* Abort download */
CURL_REQ_CLEAR_RECV(data);
k->done = TRUE;
@ -2739,7 +2739,7 @@ static CURLcode http_firstwrite(struct Curl_easy *data)
infof(data, "Simulate an HTTP 304 response");
/* we abort the transfer before it is completed == we ruin the
reuse ability. Close the connection */
streamclose(conn, "Simulated 304 handling");
streamclose(conn);
return CURLE_OK;
}
} /* we have a time condition */
@ -3272,7 +3272,7 @@ static CURLcode http_header_c(struct Curl_easy *data,
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
}
streamclose(conn, "overflow content-length");
streamclose(conn);
infof(data, "Overflow Content-Length: value");
return CURLE_OK;
}
@ -3333,7 +3333,7 @@ static CURLcode http_header_c(struct Curl_easy *data,
* the connection will close when this request has been
* served.
*/
connclose(conn, "Connection: close used");
connclose(conn);
return CURLE_OK;
}
if((k->httpversion == 10) &&
@ -3344,7 +3344,7 @@ static CURLcode http_header_c(struct Curl_easy *data,
* pleasure. Default action for 1.0 is to close.
*
* [RFC2068, section 19.7.1] */
connkeep(conn, "Connection keep-alive");
connkeep(conn);
infof(data, "HTTP/1.0 connection set to keep alive");
return CURLE_OK;
}
@ -3460,7 +3460,7 @@ static CURLcode http_header_p(struct Curl_easy *data,
* connection will be kept alive for our pleasure.
* Default action for 1.0 is to close.
*/
connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
connkeep(conn); /* do not close */
infof(data, "HTTP/1.0 proxy connection set to keep alive");
}
else if((k->httpversion == 11) && conn->http_proxy.peer &&
@ -3469,7 +3469,7 @@ static CURLcode http_header_p(struct Curl_easy *data,
* We get an HTTP/1.1 response from a proxy and it says it will
* close down after this transfer.
*/
connclose(conn, "Proxy-Connection: asked to close after done");
connclose(conn);
infof(data, "HTTP/1.1 proxy connection set close");
}
return CURLE_OK;
@ -3634,7 +3634,8 @@ static CURLcode http_header_t(struct Curl_easy *data,
/* if this is not chunked, only close can signal the end of this
* transfer as Content-Length is said not to be trusted for
* transfer-encoding! */
connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
CURL_TRC_M(data, "HTTP/1.1 transfer-encoding without chunks");
connclose(conn);
k->ignore_cl = TRUE;
}
return CURLE_OK;
@ -3780,7 +3781,7 @@ static CURLcode http_statusline(struct Curl_easy *data,
we get one of those fancy headers that tell us the
server keeps it open for us! */
infof(data, "HTTP 1.0, assume close after body");
connclose(conn, "HTTP/1.0 close after body");
connclose(conn);
}
k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
@ -4078,7 +4079,7 @@ static CURLcode http_handle_send_error(struct Curl_easy *data)
}
else {
infof(data, "Got HTTP failure 417 while sending data");
streamclose(conn, "Stop sending data before everything sent");
streamclose(conn);
result = http_perhapsrewind(data, conn);
if(result)
return result;
@ -4096,7 +4097,7 @@ static CURLcode http_handle_send_error(struct Curl_easy *data)
}
else {
infof(data, "HTTP error before end of send, stop sending");
streamclose(conn, "Stop sending data before everything sent");
streamclose(conn);
result = Curl_req_abort_sending(data);
if(result)
return result;
@ -4172,7 +4173,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
according to RFC2616 section 4.4 point 5, we assume that the server
will close the connection to signal the end of the document. */
infof(data, "no chunk, no close, no size. Assume close to signal end");
streamclose(conn, "HTTP: No end-of-message indicator");
streamclose(conn);
}
http_check_auth_closure(data, conn);
@ -4508,7 +4509,7 @@ static CURLcode http_parse_headers(struct Curl_easy *data,
/* this is not the beginning of a protocol first header line.
* Cannot be 0.9 if version was detected or connection was reused. */
k->header = FALSE;
streamclose(conn, "bad HTTP: No end-of-message indicator");
streamclose(conn);
if((k->httpversion >= 10) || conn->bits.reuse) {
failf(data, "Invalid status line");
return CURLE_WEIRD_SERVER_REPLY;
@ -4545,7 +4546,7 @@ static CURLcode http_parse_headers(struct Curl_easy *data,
/* the first read "header", the status line */
statusline st = checkprotoprefix(data, conn, hd, hlen);
if(st == STATUS_BAD) {
streamclose(conn, "bad HTTP: No end-of-message indicator");
streamclose(conn);
/* this is not the beginning of a protocol first header line.
* Cannot be 0.9 if version was detected or connection was reused. */
if((k->httpversion >= 10) || conn->bits.reuse) {

View file

@ -512,7 +512,8 @@ static CURLcode h2_process_pending_input(struct Curl_cfilter *cf,
the connection may not be reused. This is set when a
GOAWAY frame has been received or when the limit of stream
identifiers has been reached. */
connclose(cf->conn, "http/2: No new requests allowed");
CURL_TRC_M(data, "http/2: No new requests allowed");
connclose(cf->conn);
}
return CURLE_OK;
@ -1688,7 +1689,7 @@ static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf,
if(stream->error == NGHTTP2_REFUSED_STREAM) {
infof(data, "HTTP/2 stream %d refused by server, try again on a new "
"connection", stream->id);
connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
connclose(cf->conn); /* do not use this anymore */
data->state.refused_stream = TRUE;
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}
@ -1930,8 +1931,9 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
}
if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
connclose(cf->conn, ctx->rcvd_goaway ? "server closed with GOAWAY" :
"server closed abruptly");
CURL_TRC_CF(data, cf, "server closed %s",
ctx->rcvd_goaway ? "with GOAWAY" : "abruptly");
connclose(cf->conn);
}
CURL_TRC_CF(data, cf, "[0] ingress: done");

View file

@ -2010,7 +2010,8 @@ static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
return CURLE_OK;
if(status) {
connclose(conn, "IMAP done with bad status"); /* marked for closure */
CURL_TRC_M(data, "IMAP done with bad status");
connclose(conn); /* marked for closure */
result = status; /* use the already set error code */
}
else if(!data->set.connect_only &&

View file

@ -652,7 +652,7 @@ quit:
/* no data to transfer */
Curl_xfer_setup_nop(data);
connclose(conn, "LDAP connection always disable reuse");
connclose(conn);
return result;
}

View file

@ -975,7 +975,7 @@ static CURLcode mqtts_connecting(struct Curl_easy *data, bool *done)
result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
if(result)
connclose(conn, "Failed TLS connection");
connclose(conn);
return result;
}

View file

@ -78,7 +78,7 @@ static CURLMcode add_next_timeout(const struct curltime *pnow,
static void multi_timeout(struct Curl_multi *multi,
struct curltime *expire_time,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
static void multi_schedule_pending(struct Curl_multi *multi);
static void multi_xfer_bufs_free(struct Curl_multi *multi);
#ifdef DEBUGBUILD
static void multi_xfer_tbl_dump(struct Curl_multi *multi);
@ -666,14 +666,14 @@ static void multi_done_locked(struct connectdata *conn,
conn->connection_id, conn->destination,
data->set.reuse_forbid, conn->bits.close, mdctx->premature,
Curl_conn_is_multiplex(conn, FIRSTSOCKET));
connclose(conn, "disconnecting");
connclose(conn);
Curl_conn_terminate(data, conn, (bool)mdctx->premature);
}
else if(!Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) {
CURL_TRC_M(data, "multi_done, conn #%" FMT_OFF_T " to %s was shutdown"
" by server, not reusing", conn->connection_id,
conn->destination);
connclose(conn, "server shutdown");
connclose(conn);
Curl_conn_terminate(data, conn, (bool)mdctx->premature);
}
else {
@ -751,7 +751,7 @@ static CURLcode multi_done(struct Curl_easy *data,
if(conn)
Curl_conn_ev_data_done(data, premature);
process_pending_handles(data->multi); /* connection / multiplex */
multi_schedule_pending(data->multi); /* connection / multiplex */
if(!result)
result = Curl_req_done(&data->req, data, premature);
@ -771,16 +771,6 @@ static CURLcode multi_done(struct Curl_easy *data,
return result;
}
static void close_connect_only(struct connectdata *conn,
struct Curl_easy *data,
void *userdata)
{
(void)userdata;
(void)data;
if(conn->bits.connect_only)
connclose(conn, "Removing connect-only easy handle");
}
CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
struct Curl_easy *data)
{
@ -808,20 +798,14 @@ CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
premature = (data->mstate < MSTATE_COMPLETED);
/* If the 'state' is not INIT or COMPLETED, we might need to do something
nice to put the easy_handle in a good known state when this returns. */
if(data->conn &&
data->mstate > MSTATE_DO &&
data->mstate < MSTATE_COMPLETED) {
/* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
streamclose(data->conn, "Removed with partial response");
}
if(data->conn) {
/* If the 'state' is not INIT or COMPLETED, we might need to do something
nice to put the easy_handle in a good known state when this returns. */
if(premature && (data->mstate > MSTATE_DO))
streamclose(data->conn);
/* multi_done() clears the association between the easy handle and the
connection.
Note that this ignores the return code because there is
nothing really useful to do with it anyway! */
(void)multi_done(data, data->result, premature);
@ -835,6 +819,7 @@ CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
/* If in `msgsent`, it was deducted from `multi->xfers_alive` already. */
if(!Curl_uint32_bset_contains(&multi->msgsent, data->mid))
--multi->xfers_alive;
if(data->state.really_alive) {
data->state.really_alive = FALSE;
--multi->xfers_really_alive;
@ -852,26 +837,29 @@ CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
/* Tell event handling that this transfer is definitely going away */
Curl_multi_ev_xfer_done(multi, data);
if(data->set.connect_only && !data->multi_easy) {
/* This removes a handle that was part the multi interface that used
CONNECT_ONLY, that connection is now left alive but since this handle
has bits.close set nothing can use that transfer anymore and it is
forbidden from reuse. This easy handle cannot find the connection
anymore once removed from the multi handle
Better close the connection here, at once. */
struct connectdata *c;
curl_socket_t s;
s = Curl_getconnectinfo(data, &c);
if((s != CURL_SOCKET_BAD) && c) {
Curl_conn_terminate(data, c, TRUE);
if(data->set.connect_only) {
if(data->multi_easy) {
if(data->state.lastconnect_id != -1) {
/* Mark any connect-only connection for closure */
struct connectdata *conn;
(void)Curl_getconnectinfo(data, &conn);
if(conn && conn->bits.connect_only)
connclose(conn);
}
}
}
else {
/* This removes a handle that was part the multi interface that used
CONNECT_ONLY, that connection is now left alive but since this handle
has bits.close set nothing can use that connection anymore and it is
forbidden from reuse. This easy handle cannot find the connection
anymore once removed from the multi handle
if(data->state.lastconnect_id != -1) {
/* Mark any connect-only connection for closure */
Curl_cpool_do_by_id(data, data->state.lastconnect_id,
close_connect_only, NULL);
Better close the connection here, at once. */
struct connectdata *conn;
(void)Curl_getconnectinfo(data, &conn);
if(conn)
Curl_conn_terminate(data, conn, TRUE);
}
}
#ifdef USE_LIBPSL
@ -904,10 +892,8 @@ CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
data->mid = UINT32_MAX;
data->master_mid = UINT32_MAX;
/* NOTE NOTE NOTE
We do not touch the easy handle here! */
process_pending_handles(multi);
/* A pending transfer *might* be able to run now. */
multi_schedule_pending(multi);
mresult = Curl_update_timer(multi);
if(mresult)
return mresult;
@ -1872,7 +1858,7 @@ static bool multi_handle_timeout(struct Curl_easy *data,
if(data->conn) {
/* Force connection closed if the connection has indeed been used */
if(data->mstate > MSTATE_DO) {
streamclose(data->conn, "Disconnect due to timeout");
streamclose(data->conn);
*stream_error = TRUE;
}
(void)multi_done(data, *result, TRUE);
@ -2077,7 +2063,7 @@ static CURLMcode multistate_performing(struct Curl_easy *data,
if(!ret) {
infof(data, "Downgrades to HTTP/1.1");
streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
streamclose(data->conn);
data->state.http_neg.wanted = CURL_HTTP_V1x;
data->state.http_neg.allowed = CURL_HTTP_V1x;
/* clear the error message bit too as we ignore the one we got */
@ -2112,7 +2098,7 @@ static CURLMcode multistate_performing(struct Curl_easy *data,
if(!(data->conn->scheme->flags & PROTOPT_DUAL) &&
result != CURLE_HTTP2_STREAM)
streamclose(data->conn, "Transfer returned error");
streamclose(data->conn);
multi_posttransfer(data);
multi_done(data, result, TRUE);
@ -2323,7 +2309,7 @@ static CURLMcode multistate_ratelimiting(struct Curl_easy *data,
if(result) {
if(!(data->conn->scheme->flags & PROTOPT_DUAL) &&
result != CURLE_HTTP2_STREAM)
streamclose(data->conn, "Transfer returned error");
streamclose(data->conn);
multi_posttransfer(data);
multi_done(data, result, TRUE);
@ -2357,7 +2343,7 @@ static CURLMcode multistate_connect(struct Curl_multi *multi,
return mresult;
}
else
process_pending_handles(data->multi);
multi_schedule_pending(data->multi);
if(!result) {
/* after the connect has been sent off, go WAITCONNECT unless the
@ -2369,7 +2355,7 @@ static CURLMcode multistate_connect(struct Curl_multi *multi,
if(!data->conn->bits.reuse &&
Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
/* new connection, can multiplex, wake pending handles */
process_pending_handles(data->multi);
multi_schedule_pending(data->multi);
}
multistate(data, MSTATE_PROTOCONNECT);
}
@ -2398,7 +2384,7 @@ static CURLcode is_finished(struct Curl_multi *multi,
connection detach and termination happens only here */
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* connection */
multi_schedule_pending(multi); /* connection */
if(data->conn) {
if(stream_error) {
@ -2428,7 +2414,7 @@ static CURLcode is_finished(struct Curl_multi *multi,
if(result) {
/* aborted due to progress callback return code must close the
connection */
streamclose(data->conn, "Aborted by callback");
streamclose(data->conn);
/* if not yet in DONE state, go there, otherwise COMPLETED */
multistate(data, (data->mstate < MSTATE_DONE) ?
@ -2542,7 +2528,7 @@ static CURLMcode multistate_connecting(struct Curl_easy *data,
if(!data->conn->bits.reuse &&
Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
/* new connection, can multiplex, wake pending handles */
process_pending_handles(data->multi);
multi_schedule_pending(data->multi);
}
multistate(data, MSTATE_PROTOCONNECT);
return CURLM_CALL_MULTI_PERFORM;
@ -2678,7 +2664,7 @@ static CURLMcode multistate_did(struct Curl_multi *multi,
DEBUGASSERT(data->conn);
if(data->conn->bits.multiplex)
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* multiplexed */
multi_schedule_pending(multi); /* multiplexed */
/* Only perform the transfer if there is a good socket to work with.
Having both BAD is a signal to skip immediately to DONE */
@ -2770,7 +2756,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(multi_ischanged(multi, TRUE)) {
CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
process_pending_handles(multi); /* multiplexed */
multi_schedule_pending(multi); /* multiplexed */
}
if(data->mstate > MSTATE_CONNECT &&
@ -2923,7 +2909,7 @@ static CURLMcode multi_perform(struct Curl_multi *multi,
sigpipe_restore(&sigpipe_ctx);
if(multi_ischanged(multi, TRUE))
process_pending_handles(multi);
multi_schedule_pending(multi);
if(!returncode && CURL_MNTFY_HAS_ENTRIES(multi))
returncode = Curl_mntfy_dispatch_all(multi);
@ -3330,7 +3316,7 @@ out:
sigpipe_restore(&pipe_ctx);
if(multi_ischanged(multi, TRUE))
process_pending_handles(multi);
multi_schedule_pending(multi);
if(!mresult && CURL_MNTFY_HAS_ENTRIES(multi))
mresult = Curl_mntfy_dispatch_all(multi);
@ -3879,7 +3865,7 @@ static void move_pending_to_connect(struct Curl_multi *multi,
Curl_multi_mark_dirty(data); /* make it run */
}
/* process_pending_handles() moves a handle from PENDING back into the process
/* multi_schedule_pending() moves a handle from PENDING back into the process
list and change state to CONNECT.
We do not move all transfers because that can be a significant amount.
@ -3892,7 +3878,7 @@ static void move_pending_to_connect(struct Curl_multi *multi,
We could consider an improvement where we store the queue reason and allow
more pipewait rechecks than others. */
static void process_pending_handles(struct Curl_multi *multi)
static void multi_schedule_pending(struct Curl_multi *multi)
{
uint32_t mid = multi->last_pending_mid;

View file

@ -1478,7 +1478,8 @@ static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
return CURLE_OK;
if(status) {
connclose(data->conn, "POP3 done with bad status");
CURL_TRC_M(data, "POP3 done with bad status");
connclose(data->conn);
result = status; /* use the already set error code */
}

View file

@ -210,7 +210,7 @@ static CURLcode cw_download_write(struct Curl_easy *data,
if(data->req.no_body && nbytes > 0) {
/* BODY arrives although we want none, bail out */
streamclose(data->conn, "ignoring body");
streamclose(data->conn);
CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu), "
"did not want a BODY", (unsigned int)type, nbytes);
data->req.download_done = TRUE;
@ -277,7 +277,7 @@ static CURLcode cw_download_write(struct Curl_easy *data,
", bytecount = %" FMT_OFF_T,
excess_len, data->req.size, data->req.maxdownload,
data->req.bytecount);
connclose(data->conn, "excess found in a read");
connclose(data->conn);
}
}
else if((nwrite < nbytes) && !data->req.ignorebody) {

View file

@ -912,7 +912,8 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
result = smb_send_negotiate(data, smbc, req);
if(result) {
connclose(conn, "SMB: failed to send negotiate message");
CURL_TRC_M(data, "SMB: failed to send negotiate message");
connclose(conn);
return result;
}
@ -922,7 +923,8 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
/* Send the previous message and check for a response */
result = smb_send_and_recv(data, smbc, &msg);
if(result && result != CURLE_AGAIN) {
connclose(conn, "SMB: failed to communicate");
CURL_TRC_M(data, "SMB: failed to communicate");
connclose(conn);
return result;
}
@ -935,7 +937,8 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
case SMB_NEGOTIATE:
if((smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) ||
h->status) {
connclose(conn, "SMB: negotiation failed");
CURL_TRC_M(data, "SMB: negotiation failed");
connclose(conn);
return CURLE_COULDNT_CONNECT;
}
nrsp = msg;
@ -952,7 +955,8 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
smbc->session_key = smb_swap32(nrsp->session_key);
result = smb_send_setup(data);
if(result) {
connclose(conn, "SMB: failed to send setup message");
CURL_TRC_M(data, "SMB: failed to send setup message");
connclose(conn);
return result;
}
conn_state(data, smbc, SMB_SETUP);
@ -960,7 +964,8 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
case SMB_SETUP:
if(h->status) {
connclose(conn, "SMB: authentication failed");
CURL_TRC_M(data, "SMB: authentication failed");
connclose(conn);
return CURLE_LOGIN_DENIED;
}
smbc->uid = smb_swap16(h->uid);
@ -1025,7 +1030,8 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
if(req->state == SMB_REQUESTING) {
result = smb_send_tree_connect(data, smbc, req);
if(result) {
connclose(conn, "SMB: failed to send tree connect message");
CURL_TRC_M(data, "SMB: failed to send tree connect message");
connclose(conn);
return result;
}
@ -1035,7 +1041,8 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
/* Send the previous message and check for a response */
result = smb_send_and_recv(data, smbc, &msg);
if(result && result != CURLE_AGAIN) {
connclose(conn, "SMB: failed to communicate");
CURL_TRC_M(data, "SMB: failed to communicate");
connclose(conn);
return result;
}
@ -1180,7 +1187,8 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
}
if(result) {
connclose(conn, "SMB: failed to send message");
CURL_TRC_M(data, "SMB: failed to send message");
connclose(conn);
return result;
}

View file

@ -1739,7 +1739,8 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
curlx_safefree(smtp->custom);
if(status) {
connclose(conn, "SMTP done with bad status"); /* marked for closure */
CURL_TRC_M(data, "SMTP done with bad status");
connclose(conn); /* marked for closure */
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && data->set.mail_rcpt &&

View file

@ -942,7 +942,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
/* we do not keep TFTP connections up because there is none or little gain
* for UDP */
connclose(conn, "TFTP");
connclose(conn);
state->data = data;
state->sockfd = conn->sock[FIRSTSOCKET];

View file

@ -658,7 +658,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
if(!*url)
return CURLE_OUT_OF_MEMORY;
connclose(conn, "retry"); /* close this connection */
connclose(conn); /* close this connection */
conn->bits.retry = TRUE; /* mark this as a connection we are about to
retry. Marking it this way should prevent i.e
HTTP transfers to return error because nothing

View file

@ -665,7 +665,7 @@ static ssize_t cf_h3_proxy_recv_closed_stream(struct Curl_cfilter *cf,
if(stream->error3 == CURL_H3_ERR_REQUEST_REJECTED) {
infof(data, "HTTP/3 stream %" PRId64 " refused by server, try again "
"on a new connection", stream->id);
connclose(cf->conn, "REFUSED_STREAM");
connclose(cf->conn);
data->state.refused_stream = TRUE;
*err = CURLE_RECV_ERROR;
goto out;

View file

@ -449,7 +449,7 @@ static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
if(stream->error3 == CURL_H3_ERR_REQUEST_REJECTED) {
infof(data, "HTTP/3 stream %" PRId64 " refused by server, try again "
"on a new connection", stream->id);
connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
connclose(cf->conn); /* do not use this anymore */
data->state.refused_stream = TRUE;
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}

View file

@ -866,7 +866,7 @@ static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
if(stream->error3 == CURL_H3_ERR_REQUEST_REJECTED) {
infof(data, "HTTP/3 stream %" PRIu64 " refused by server, try again "
"on a new connection", stream->id);
connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
connclose(cf->conn); /* do not use this anymore */
data->state.refused_stream = TRUE;
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}

View file

@ -2238,7 +2238,7 @@ static CURLcode myssh_in_SESSION_FREE(struct Curl_easy *data,
/* the code we are about to return */
result = sshc->actualcode;
memset(sshc, 0, sizeof(struct ssh_conn));
connclose(data->conn, "SSH session free");
connclose(data->conn);
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
myssh_to(data, sshc, SSH_STOP);

View file

@ -2850,7 +2850,7 @@ static CURLcode ssh_state_session_free(struct Curl_easy *data,
if(result)
return result;
memset(sshc, 0, sizeof(struct ssh_conn));
connclose(conn, "SSH session free");
connclose(conn);
sshc->state = SSH_SESSION_FREE; /* current */
myssh_to(data, sshc, SSH_STOP);
return CURLE_OK;

View file

@ -33,8 +33,6 @@ run 1: foobar and so on fun!
run 1: foobar and so on fun!
-] Mutex lock CONNECT
[- Mutex unlock CONNECT
-] Mutex lock CONNECT
[- Mutex unlock CONNECT
-] Mutex lock SHARE
[- Mutex unlock SHARE
-] Mutex lock SHARE
@ -48,8 +46,6 @@ run 1: foobar and so on fun!
run 1: foobar and so on fun!
-] Mutex lock CONNECT
[- Mutex unlock CONNECT
-] Mutex lock CONNECT
[- Mutex unlock CONNECT
-] Mutex lock SHARE
[- Mutex unlock SHARE
-] Mutex lock SHARE
@ -63,8 +59,6 @@ run 1: foobar and so on fun!
run 1: foobar and so on fun!
-] Mutex lock CONNECT
[- Mutex unlock CONNECT
-] Mutex lock CONNECT
[- Mutex unlock CONNECT
-] Mutex lock SHARE
[- Mutex unlock SHARE
-] Mutex lock SHARE