connect: connection close tweaks
No binary (build failed)
—
(log yok)
| @@ -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)) | |
| @@ -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) | |
| @@ -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. | |
| @@ -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; |
| } | |
| } | |
| @@ -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 |
| + | |
| + | void Curl_conncontrol(struct connectdata *conn, int ctrl); |
| - | #define CONNCTRL_KEEP 0 /* undo a marked closure */ |
| - | #define CONNCTRL_CONNECTION 1 |
| - | #define CONNCTRL_STREAM 2 |
| - | |
| - | 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`. | |
| @@ -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); | |
| } | |
| @@ -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; | |
| } | |
| @@ -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; | |
| } | |
| @@ -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) { | |
| @@ -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"); | |
| @@ -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 && | |
| @@ -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; | |
| } | |
| @@ -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; | |
| } | |
| @@ -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 |
| + | |
| + | Better close the connection here, at once. */ |
| + | struct connectdata *conn; |
| + | (void)Curl_getconnectinfo(data, &conn); |
| + | if(conn) |
| + | Curl_conn_terminate(data, conn, TRUE); |
| } | |
| - | } |
| - | |
| - | 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); |
| } | |
| #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; | |
| @@ -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 */ | |
| } | |
| @@ -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) { | |
| @@ -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; | |
| } | |
| @@ -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 && | |
| @@ -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]; | |
| @@ -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 | |
| @@ -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; | |
| @@ -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 */ | |
| } | |
| @@ -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 */ | |
| } | |
| @@ -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); | |
| @@ -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; | |
| @@ -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 | |