lib: connection shutdown, cleanup code
No binary (build failed)
—
(log yok)
| @@ -183,62 +183,6 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data, | |
| Curl_conn_cf_discard_chain(&conn->cfilter[sockindex], data); | |
| } | |
| - | CURLcode Curl_conn_shutdown(struct Curl_easy *data, |
| - | int8_t sockindex, bool *done) |
| - | { |
| - | struct Curl_cfilter *cf; |
| - | CURLcode result = CURLE_OK; |
| - | timediff_t timeout_ms; |
| - | |
| - | DEBUGASSERT(data->conn); |
| - | |
| - | if(!CONN_SOCK_IDX_VALID(sockindex)) |
| - | return CURLE_BAD_FUNCTION_ARGUMENT; |
| - | |
| - | /* Get the first connected filter that is not shut down already. */ |
| - | cf = data->conn->cfilter[sockindex]; |
| - | while(cf && (!cf->connected || cf->shutdown)) |
| - | cf = cf->next; |
| - | |
| - | if(!cf) { |
| - | *done = TRUE; |
| - | return CURLE_OK; |
| - | } |
| - | |
| - | *done = FALSE; |
| - | if(!Curl_shutdown_started(data->conn, sockindex)) { |
| - | Curl_shutdown_start(data, sockindex, 0); |
| - | } |
| - | else { |
| - | timeout_ms = Curl_shutdown_timeleft(data, data->conn, sockindex); |
| - | if(timeout_ms < 0) { |
| - | /* info message, since this might be regarded as acceptable */ |
| - | infof(data, "shutdown timeout"); |
| - | return CURLE_OPERATION_TIMEDOUT; |
| - | } |
| - | } |
| - | |
| - | while(cf) { |
| - | if(!cf->shutdown) { |
| - | bool cfdone = FALSE; |
| - | result = cf->cft->do_shutdown(cf, data, &cfdone); |
| - | if(result) { |
| - | CURL_TRC_CF(data, cf, "shut down failed with %d", (int)result); |
| - | return result; |
| - | } |
| - | else if(!cfdone) { |
| - | CURL_TRC_CF(data, cf, "shut down not done yet"); |
| - | return CURLE_OK; |
| - | } |
| - | CURL_TRC_CF(data, cf, "shut down successfully"); |
| - | cf->shutdown = TRUE; |
| - | } |
| - | cf = cf->next; |
| - | } |
| - | *done = (!result); |
| - | return result; |
| - | } |
| - | |
| CURLcode Curl_cf_recv(struct Curl_easy *data, int8_t sockindex, char *buf, | |
| size_t len, size_t *pnread) | |
| { | |
| @@ -776,7 +720,7 @@ CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data, | |
| for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) { | |
| if(conn->cfilter[i] && | |
| (want_io || !Curl_conn_is_connected(conn, i) || | |
| - | Curl_shutdown_started(conn, i))) |
| + | Curl_cshutdn_has_started(conn, i))) |
| result = Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps); | |
| } | |
| return result; | |
| @@ -438,14 +438,6 @@ void Curl_conn_cntrl_report_stats(struct Curl_easy *data, | |
| void Curl_conn_remove_setup_filters(struct Curl_easy *data, | |
| int8_t sockindex); | |
| - | /** |
| - | * Shutdown the connection at `sockindex` non-blocking, using timeout |
| - | * from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS. |
| - | * Return CURLE_OK and *done == FALSE if not finished. |
| - | */ |
| - | CURLcode Curl_conn_shutdown(struct Curl_easy *data, |
| - | int8_t sockindex, bool *done); |
| - | |
| /** | |
| * Return if data is pending in some connection filter at chain | |
| * `sockindex` for connection `data->conn`. | |
| @@ -209,11 +209,11 @@ static void cpool_discard_conn(struct cpool *cpool, | |
| done = TRUE; | |
| if(!done) { | |
| /* Attempt to shutdown the connection right away. */ | |
| - | Curl_conn_shutdown_once(admin, conn, &done); |
| + | Curl_cshutdn_try_once(admin, conn, &done); |
| } | |
| if(done || !data->multi) | |
| - | Curl_conn_terminate(admin, conn, FALSE); |
| + | Curl_cshutdn_terminate(admin, conn, FALSE); |
| else { | |
| struct Curl_multi *multi = data->multi; | |
| size_t max_shutdowns = multi->max_total_connections; | |
| @@ -417,7 +417,7 @@ static void cpool_conn_close(struct cpool *cpool, | |
| else { | |
| /* No multi available, terminate */ | |
| infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id); | |
| - | Curl_conn_terminate(admin, conn, !aborted); |
| + | Curl_cshutdn_terminate(admin, conn, !aborted); |
| } | |
| if(do_lock) | |
| @@ -442,7 +442,7 @@ static void cpool_evict_conn(struct cpool *cpool, | |
| { | |
| if(cpool->share) { | |
| cpool_remove_conn(cpool, conn); | |
| - | Curl_conn_terminate(admin, conn, TRUE); |
| + | Curl_cshutdn_terminate(admin, conn, TRUE); |
| } | |
| else | |
| cpool_conn_close(cpool, admin, conn, FALSE); | |
| @@ -552,7 +552,8 @@ out: | |
| } | |
| CURLcode Curl_cpool_add(struct Curl_easy *data, | |
| - | struct connectdata *conn) |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow) |
| { | |
| CURLcode result = CURLE_OK; | |
| struct cpool_bundle *bundle = NULL; | |
| @@ -563,6 +564,10 @@ CURLcode Curl_cpool_add(struct Curl_easy *data, | |
| if(!cpool) | |
| return CURLE_FAILED_INIT; | |
| + | conn->created = *pnow; |
| + | conn->shutdown.start_ms[FIRSTSOCKET] = |
| + | conn->shutdown.start_ms[SECONDARYSOCKET] = -1; |
| + | |
| CPOOL_LOCK(cpool, data); | |
| bundle = cpool_find_bundle(cpool, conn->destination); | |
| if(!bundle) { | |
| @@ -1006,6 +1011,22 @@ bool Curl_cpool_conn_seems_healthy(struct connectdata *conn, | |
| return healthy; | |
| } | |
| + | void Curl_cpool_conn_was_used(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow) |
| + | { |
| + | (void)data; |
| + | conn->lastupkeep_ms = curlx_ptimediff_ms(pnow, &conn->created); |
| + | } |
| + | |
| + | timediff_t Curl_cpool_conn_age_ms(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow) |
| + | { |
| + | (void)data; |
| + | return curlx_ptimediff_ms(pnow, &conn->created); |
| + | } |
| + | |
| #if 0 | |
| /* Useful for debugging the connection pool */ | |
| void Curl_cpool_print(struct cpool *cpool) | |
| @@ -82,7 +82,18 @@ struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data, | |
| /* Add the connection to the pool. */ | |
| CURLcode Curl_cpool_add(struct Curl_easy *data, | |
| - | struct connectdata *conn) WARN_UNUSED_RESULT; |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow) WARN_UNUSED_RESULT; |
| + | |
| + | /* Connection was used at the given time. */ |
| + | void Curl_cpool_conn_was_used(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow); |
| + | |
| + | /* Return connection age in milliseconds since its creation. */ |
| + | timediff_t Curl_cpool_conn_age_ms(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow); |
| /** | |
| * Return if the pool has reached its configured limits for adding | |
| @@ -73,8 +73,8 @@ UNITTEST timediff_t timeleft_now_ms(struct Curl_easy *data, | |
| timediff_t timeleft_ms = 0; | |
| timediff_t ctimeleft_ms = 0; | |
| - | if(data->conn && Curl_shutdown_started(data->conn, FIRSTSOCKET)) |
| - | return Curl_shutdown_timeleft(data, data->conn, FIRSTSOCKET); |
| + | if(data->conn && Curl_cshutdn_has_started(data->conn, FIRSTSOCKET)) |
| + | return Curl_cshutdn_timeleft_ms(data, data->conn, FIRSTSOCKET); |
| else if(Curl_is_connecting(data)) { | |
| timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ? | |
| data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT; | |
| @@ -112,67 +112,6 @@ timediff_t Curl_timeleft_now_ms(struct Curl_easy *data, | |
| return timeleft_now_ms(data, pnow); | |
| } | |
| - | void Curl_shutdown_start(struct Curl_easy *data, int8_t sockindex, |
| - | int timeout_ms) |
| - | { |
| - | struct connectdata *conn = data->conn; |
| - | const struct curltime *pnow = Curl_pgrs_now(data); |
| - | |
| - | DEBUGASSERT(conn); |
| - | conn->shutdown.start_ms[sockindex] = |
| - | curlx_ptimediff_ms(pnow, &conn->created); |
| - | conn->shutdown.timeout_ms = (timeout_ms > 0) ? |
| - | (timediff_t)timeout_ms : |
| - | ((data->set.shutdowntimeout > 0) ? |
| - | data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS); |
| - | /* Set a timer, unless we operate on the admin handle */ |
| - | if(data->mid) |
| - | Curl_expire_set(data, EXPIRE_SHUTDOWN, conn->shutdown.timeout_ms, pnow); |
| - | CURL_TRC_M(data, "shutdown start on%s connection", |
| - | sockindex ? " secondary" : ""); |
| - | } |
| - | |
| - | timediff_t Curl_shutdown_timeleft(struct Curl_easy *data, |
| - | struct connectdata *conn, |
| - | int8_t sockindex) |
| - | { |
| - | timediff_t left_ms; |
| - | |
| - | if(conn->shutdown.start_ms[sockindex] < 0) |
| - | return 0; /* not started or no limits */ |
| - | |
| - | left_ms = conn->shutdown.timeout_ms - |
| - | (curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->created) - |
| - | conn->shutdown.start_ms[sockindex]); |
| - | return left_ms ? left_ms : -1; |
| - | } |
| - | |
| - | timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data, |
| - | struct connectdata *conn) |
| - | { |
| - | timediff_t left_ms = 0, ms; |
| - | int8_t i; |
| - | |
| - | for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) { |
| - | if(conn->shutdown.start_ms[i] < 0) |
| - | continue; |
| - | ms = Curl_shutdown_timeleft(data, conn, i); |
| - | if(ms && (!left_ms || ms < left_ms)) |
| - | left_ms = ms; |
| - | } |
| - | return left_ms; |
| - | } |
| - | |
| - | void Curl_shutdown_clear(struct Curl_easy *data, int8_t sockindex) |
| - | { |
| - | data->conn->shutdown.start_ms[sockindex] = -1; |
| - | } |
| - | |
| - | bool Curl_shutdown_started(struct connectdata *conn, int8_t sockindex) |
| - | { |
| - | return conn->shutdown.start_ms[sockindex] >= 0; |
| - | } |
| - | |
| /* | |
| * Used to extract socket and connectdata struct for the most recent | |
| * transfer on the given Curl_easy. | |
| @@ -377,8 +316,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, | |
| * socket and ip related information. */ | |
| Curl_conn_cntrl_update_info(data, data->conn); | |
| conn_report_stats(data, sockindex); | |
| - | data->conn->lastupkeep_ms = |
| - | curlx_ptimediff_ms(Curl_pgrs_now(data), &data->conn->created); |
| + | Curl_cpool_conn_was_used(data, data->conn, Curl_pgrs_now(data)); |
| VERBOSE(result = conn_connect_trace(data, cf)); | |
| VERBOSE(Curl_conn_trc_filters(data, sockindex, "connected")); | |
| Curl_conn_remove_setup_filters(data, sockindex); | |
| @@ -41,27 +41,6 @@ timediff_t Curl_timeleft_now_ms(struct Curl_easy *data, | |
| #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ | |
| - | #define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000) |
| - | |
| - | void Curl_shutdown_start(struct Curl_easy *data, int8_t sockindex, |
| - | int timeout_ms); |
| - | |
| - | /* return how much time there is left to shutdown the connection at |
| - | * sockindex. Returns 0 if there is no limit or shutdown has not started. */ |
| - | timediff_t Curl_shutdown_timeleft(struct Curl_easy *data, |
| - | struct connectdata *conn, |
| - | int8_t sockindex); |
| - | |
| - | /* return how much time there is left to shutdown the connection. |
| - | * Returns 0 if there is no limit or shutdown has not started. */ |
| - | timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data, |
| - | struct connectdata *conn); |
| - | |
| - | void Curl_shutdown_clear(struct Curl_easy *data, int8_t sockindex); |
| - | |
| - | /* TRUE iff shutdown has been started */ |
| - | bool Curl_shutdown_started(struct connectdata *conn, int8_t sockindex); |
| - | |
| /* | |
| * Used to extract socket and connectdata struct for the most recent | |
| * transfer on the given Curl_easy. | |
| @@ -38,6 +38,69 @@ | |
| #include "curlx/strparse.h" | |
| + | #define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000) |
| + | |
| + | void Curl_cshutdn_start_timer(struct Curl_easy *data, int8_t sockindex, |
| + | int timeout_ms) |
| + | { |
| + | struct connectdata *conn = data->conn; |
| + | const struct curltime *pnow = Curl_pgrs_now(data); |
| + | |
| + | DEBUGASSERT(conn); |
| + | conn->shutdown.start_ms[sockindex] = |
| + | curlx_ptimediff_ms(pnow, &conn->created); |
| + | conn->shutdown.timeout_ms = (timeout_ms > 0) ? |
| + | (timediff_t)timeout_ms : |
| + | ((data->set.shutdowntimeout > 0) ? |
| + | data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS); |
| + | /* Set a timer, unless we operate on the admin handle */ |
| + | if(data->mid) |
| + | Curl_expire_set(data, EXPIRE_SHUTDOWN, conn->shutdown.timeout_ms, pnow); |
| + | CURL_TRC_M(data, "shutdown start on%s connection", |
| + | sockindex ? " secondary" : ""); |
| + | } |
| + | |
| + | timediff_t Curl_cshutdn_timeleft_ms(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | int8_t sockindex) |
| + | { |
| + | timediff_t left_ms; |
| + | |
| + | if(conn->shutdown.start_ms[sockindex] < 0) |
| + | return 0; /* not started or no limits */ |
| + | |
| + | left_ms = conn->shutdown.timeout_ms - |
| + | (curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->created) - |
| + | conn->shutdown.start_ms[sockindex]); |
| + | return left_ms ? left_ms : -1; |
| + | } |
| + | |
| + | static timediff_t cshutdn_conn_timeleft(struct Curl_easy *data, |
| + | struct connectdata *conn) |
| + | { |
| + | timediff_t left_ms = 0, ms; |
| + | int8_t i; |
| + | |
| + | for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) { |
| + | if(conn->shutdown.start_ms[i] < 0) |
| + | continue; |
| + | ms = Curl_cshutdn_timeleft_ms(data, conn, i); |
| + | if(ms && (!left_ms || ms < left_ms)) |
| + | left_ms = ms; |
| + | } |
| + | return left_ms; |
| + | } |
| + | |
| + | void Curl_cshutdn_clear_timer(struct Curl_easy *data, int8_t sockindex) |
| + | { |
| + | data->conn->shutdown.start_ms[sockindex] = -1; |
| + | } |
| + | |
| + | bool Curl_cshutdn_has_started(struct connectdata *conn, int8_t sockindex) |
| + | { |
| + | return conn->shutdown.start_ms[sockindex] >= 0; |
| + | } |
| + | |
| static void cshutdn_run_conn_handler(struct Curl_easy *data, | |
| struct connectdata *conn) | |
| { | |
| @@ -66,6 +129,62 @@ static void cshutdn_run_conn_handler(struct Curl_easy *data, | |
| } | |
| } | |
| + | CURLcode Curl_cshutdn_try_once_idx(struct Curl_easy *data, |
| + | int8_t sockindex, bool *done) |
| + | { |
| + | struct Curl_cfilter *cf; |
| + | CURLcode result = CURLE_OK; |
| + | timediff_t timeout_ms; |
| + | |
| + | DEBUGASSERT(data->conn); |
| + | |
| + | if(!CONN_SOCK_IDX_VALID(sockindex)) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | |
| + | /* Get the first connected filter that is not shut down already. */ |
| + | cf = data->conn->cfilter[sockindex]; |
| + | while(cf && (!cf->connected || cf->shutdown)) |
| + | cf = cf->next; |
| + | |
| + | if(!cf) { |
| + | *done = TRUE; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | *done = FALSE; |
| + | if(!Curl_cshutdn_has_started(data->conn, sockindex)) { |
| + | Curl_cshutdn_start_timer(data, sockindex, 0); |
| + | } |
| + | else { |
| + | timeout_ms = Curl_cshutdn_timeleft_ms(data, data->conn, sockindex); |
| + | if(timeout_ms < 0) { |
| + | /* info message, since this might be regarded as acceptable */ |
| + | infof(data, "shutdown timeout"); |
| + | return CURLE_OPERATION_TIMEDOUT; |
| + | } |
| + | } |
| + | |
| + | while(cf) { |
| + | if(!cf->shutdown) { |
| + | bool cfdone = FALSE; |
| + | result = cf->cft->do_shutdown(cf, data, &cfdone); |
| + | if(result) { |
| + | CURL_TRC_CF(data, cf, "shut down failed with %d", (int)result); |
| + | return result; |
| + | } |
| + | else if(!cfdone) { |
| + | CURL_TRC_CF(data, cf, "shut down not done yet"); |
| + | return CURLE_OK; |
| + | } |
| + | CURL_TRC_CF(data, cf, "shut down successfully"); |
| + | cf->shutdown = TRUE; |
| + | } |
| + | cf = cf->next; |
| + | } |
| + | *done = (!result); |
| + | return result; |
| + | } |
| + | |
| static void cshutdn_run_once(struct Curl_easy *data, | |
| struct connectdata *conn, | |
| bool *done) | |
| @@ -76,8 +195,8 @@ static void cshutdn_run_once(struct Curl_easy *data, | |
| /* We expect to be attached when called */ | |
| DEBUGASSERT(data->conn == conn); | |
| - | if(!Curl_shutdown_started(conn, FIRSTSOCKET)) { |
| - | Curl_shutdown_start(data, FIRSTSOCKET, 0); |
| + | if(!Curl_cshutdn_has_started(conn, FIRSTSOCKET)) { |
| + | Curl_cshutdn_start_timer(data, FIRSTSOCKET, 0); |
| } | |
| cshutdn_run_conn_handler(data, conn); | |
| @@ -88,14 +207,14 @@ static void cshutdn_run_once(struct Curl_easy *data, | |
| } | |
| if(!conn->bits.connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET)) | |
| - | r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1); |
| + | r1 = Curl_cshutdn_try_once_idx(data, FIRSTSOCKET, &done1); |
| else { | |
| r1 = CURLE_OK; | |
| done1 = TRUE; | |
| } | |
| if(!conn->bits.connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET)) | |
| - | r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2); |
| + | r2 = Curl_cshutdn_try_once_idx(data, SECONDARYSOCKET, &done2); |
| else { | |
| r2 = CURLE_OK; | |
| done2 = TRUE; | |
| @@ -107,7 +226,7 @@ static void cshutdn_run_once(struct Curl_easy *data, | |
| conn->bits.shutdown_filters = TRUE; | |
| } | |
| - | void Curl_conn_shutdown_once(struct Curl_easy *admin, |
| + | void Curl_cshutdn_try_once(struct Curl_easy *admin, |
| struct connectdata *conn, | |
| bool *done) | |
| { | |
| @@ -119,9 +238,9 @@ void Curl_conn_shutdown_once(struct Curl_easy *admin, | |
| Curl_detach_connection(admin); | |
| } | |
| - | void Curl_conn_terminate(struct Curl_easy *admin, |
| - | struct connectdata *conn, |
| - | bool do_shutdown) |
| + | void Curl_cshutdn_terminate(struct Curl_easy *admin, |
| + | struct connectdata *conn, |
| + | bool do_shutdown) |
| { | |
| bool done; | |
| @@ -179,7 +298,7 @@ static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn, | |
| Curl_node_remove(e); | |
| sigpipe_init(&sigpipe_ctx); | |
| sigpipe_apply(admin, &sigpipe_ctx); | |
| - | Curl_conn_terminate(admin, conn, FALSE); |
| + | Curl_cshutdn_terminate(admin, conn, FALSE); |
| sigpipe_restore(&sigpipe_ctx); | |
| return TRUE; | |
| } | |
| @@ -238,15 +357,15 @@ static void cshutdn_perform(struct cshutdn *cshutdn, | |
| while(e) { | |
| enext = Curl_node_next(e); | |
| conn = Curl_node_elem(e); | |
| - | Curl_conn_shutdown_once(admin, conn, &done); |
| + | Curl_cshutdn_try_once(admin, conn, &done); |
| if(done) { | |
| Curl_node_remove(e); | |
| - | Curl_conn_terminate(admin, conn, FALSE); |
| + | Curl_cshutdn_terminate(admin, conn, FALSE); |
| } | |
| else { | |
| /* idata has one timer list, but maybe more than one connection. | |
| * Set EXPIRE_SHUTDOWN to the smallest time left for all. */ | |
| - | ms = Curl_conn_shutdown_timeleft(admin, conn); |
| + | ms = cshutdn_conn_timeleft(admin, conn); |
| if(ms && (!next_expire_ms || (ms < next_expire_ms))) | |
| next_expire_ms = ms; | |
| } | |
| @@ -299,7 +418,7 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn, | |
| while(e) { | |
| struct connectdata *conn = Curl_node_elem(e); | |
| Curl_node_remove(e); | |
| - | Curl_conn_terminate(admin, conn, FALSE); |
| + | Curl_cshutdn_terminate(admin, conn, FALSE); |
| e = Curl_llist_head(&cshutdn->list); | |
| } | |
| DEBUGASSERT(!Curl_llist_count(&cshutdn->list)); | |
| @@ -389,7 +508,7 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn, | |
| if(multi->socket_cb && cshutdn_update_ev(multi, conn)) { | |
| CURL_TRC_M(admin, "[SHUTDOWN] update events failed, discarding #%" | |
| FMT_OFF_T, conn->connection_id); | |
| - | Curl_conn_terminate(admin, conn, FALSE); |
| + | Curl_cshutdn_terminate(admin, conn, FALSE); |
| return; | |
| } | |
| @@ -32,21 +32,44 @@ struct Curl_multi; | |
| struct Curl_share; | |
| struct Curl_sigpipe_ctx; | |
| - | /* Run the shutdown of the connection once. |
| + | |
| + | /* Terminates the connection, e.g. closes and destroys it. |
| + | * If `do_shutdown` is TRUE, the shutdown will be run once. |
| + | * Takes ownership of `conn`. `conn` MUST no longer be in |
| + | * a pool or on a shutdown list. */ |
| + | void Curl_cshutdn_terminate(struct Curl_easy *admin, |
| + | struct connectdata *conn, |
| + | bool do_shutdown); |
| + | |
| + | /* Start the shutdown timer, |
| + | * marks the connection sockindex as being shut down. */ |
| + | void Curl_cshutdn_start_timer(struct Curl_easy *data, int8_t sockindex, |
| + | int timeout_ms); |
| + | /* Clear the shutdown timer at sockindex again. */ |
| + | void Curl_cshutdn_clear_timer(struct Curl_easy *data, int8_t sockindex); |
| + | |
| + | /* return how much time there is left to shutdown the connection at |
| + | * sockindex. Returns 0 if there is no limit or shutdown has not started. */ |
| + | timediff_t Curl_cshutdn_timeleft_ms(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | int8_t sockindex); |
| + | |
| + | /* TRUE iff shutdown at sockindex has been started */ |
| + | bool Curl_cshutdn_has_started(struct connectdata *conn, int8_t sockindex); |
| + | |
| + | /* Shutdown the connection at `sockindex` non-blocking. |
| + | * Will start the shutdown timer if not already set. |
| + | * Return CURLE_OK and *done == FALSE if not finished. */ |
| + | CURLcode Curl_cshutdn_try_once_idx(struct Curl_easy *data, |
| + | int8_t sockindex, bool *done); |
| + | |
| + | /* Run the shutdown of the connection once non-blocking for both |
| + | * socket indices. Will start the shutdown timer if not already set. |
| * Shortly attach/detach the admin handle to `conn` while doing so. | |
| * `done` will be set TRUE if any error was encountered or if | |
| * the connection was shut down completely. */ | |
| - | void Curl_conn_shutdown_once(struct Curl_easy *admin, |
| - | struct connectdata *conn, |
| - | bool *done); |
| - | |
| - | /* Terminates the connection, e.g. closes and destroys it. |
| - | * If `do_shutdown` is TRUE, the shutdown will be run once before |
| - | * terminating it. |
| - | * Takes ownership of `conn`. */ |
| - | void Curl_conn_terminate(struct Curl_easy *admin, |
| - | struct connectdata *conn, |
| - | bool do_shutdown); |
| + | void Curl_cshutdn_try_once(struct Curl_easy *admin, |
| + | struct connectdata *conn, bool *done); |
| /* A `cshutdown` is always owned by a multi handle to maintain | |
| * the connections to be shut down. It registers timers and | |
| @@ -1414,9 +1414,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) | |
| } | |
| } /* switch */ | |
| - | if(data->set.timeout && |
| - | curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->created) >= |
| - | data->set.timeout) { |
| + | if(Curl_timeleft_ms(data) < 0) { |
| failf(data, "Time-out"); | |
| result = CURLE_OPERATION_TIMEDOUT; | |
| keepon = FALSE; | |
| @@ -1532,9 +1530,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) | |
| break; | |
| } /* poll switch statement */ | |
| - | if(data->set.timeout && |
| - | curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->created) >= |
| - | data->set.timeout) { |
| + | if(Curl_timeleft_ms(data) < 0) { |
| failf(data, "Time-out"); | |
| result = CURLE_OPERATION_TIMEDOUT; | |
| keepon = FALSE; | |
| @@ -147,21 +147,21 @@ static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done) | |
| { | |
| if(!data || !data->conn) | |
| return CURLE_FAILED_INIT; | |
| - | return Curl_conn_shutdown(data, data->conn->recv_idx, done); |
| + | return Curl_cshutdn_try_once_idx(data, data->conn->recv_idx, done); |
| } | |
| static bool xfer_recv_shutdown_started(struct Curl_easy *data) | |
| { | |
| if(!data || !data->conn) | |
| return FALSE; | |
| - | return Curl_shutdown_started(data->conn, data->conn->recv_idx); |
| + | return Curl_cshutdn_has_started(data->conn, data->conn->recv_idx); |
| } | |
| CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done) | |
| { | |
| if(!data || !data->conn) | |
| return CURLE_FAILED_INIT; | |
| - | return Curl_conn_shutdown(data, data->conn->send_idx, done); |
| + | return Curl_cshutdn_try_once_idx(data, data->conn->send_idx, done); |
| } | |
| /** | |
| @@ -1032,7 +1032,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) | |
| } | |
| if(m->data->set.conn_max_age_ms > 0) { | |
| - | timediff_t age_ms = curlx_ptimediff_ms(&m->now, &conn->created); |
| + | timediff_t age_ms = Curl_cpool_conn_age_ms(m->data, conn, &m->now); |
| if(age_ms > m->data->set.conn_max_age_ms) { | |
| /* Transfer is looking for a younger connection. */ | |
| if(!CONN_INUSE(conn)) | |
| @@ -1148,16 +1148,13 @@ static bool url_attach_existing(struct Curl_easy *data, | |
| /* | |
| * Allocate and initialize a new connectdata object. | |
| */ | |
| - | static struct connectdata *allocate_conn(struct Curl_easy *data, |
| - | const struct curltime *pnow) |
| + | static struct connectdata *allocate_conn(struct Curl_easy *data) |
| { | |
| struct connectdata *conn = curlx_calloc(1, sizeof(struct connectdata)); | |
| if(!conn) | |
| return NULL; | |
| /* and we setup a few fields in case we end up actually using this struct */ | |
| - | |
| - | conn->created = *pnow; |
| conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ | |
| conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ | |
| conn->recv_idx = 0; /* default for receiving transfer data */ | |
| @@ -1972,7 +1969,6 @@ static void conn_meta_freeentry(void *p) | |
| } | |
| static CURLcode url_create_needle(struct Curl_easy *data, | |
| - | const struct curltime *pnow, |
| struct connectdata **pneedle) | |
| { | |
| struct connectdata *needle = NULL; | |
| @@ -1981,7 +1977,7 @@ static CURLcode url_create_needle(struct Curl_easy *data, | |
| /* Allocate a temporary connection data struct (needle) and fill in for | |
| comparison purposes. */ | |
| - | needle = allocate_conn(data, pnow); |
| + | needle = allocate_conn(data); |
| if(!needle) { | |
| result = CURLE_OUT_OF_MEMORY; | |
| goto out; | |
| @@ -2221,7 +2217,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data, | |
| /* create the template connection for transfer data. Use this needle to | |
| * find an existing connection or, if none exists, convert needle | |
| * to a full connection and attach it to data. */ | |
| - | result = url_create_needle(data, pnow, &needle); |
| + | result = url_create_needle(data, &needle); |
| if(result) | |
| goto out; | |
| DEBUGASSERT(needle); | |
| @@ -2243,7 +2239,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data, | |
| goto out; | |
| /* Setup a "faked" transfer that will do nothing */ | |
| - | result = Curl_cpool_add(data, needle); |
| + | result = Curl_cpool_add(data, needle, pnow); |
| Curl_attach_connection(data, needle, TRUE); | |
| needle = NULL; | |
| if(!result) { | |
| @@ -2320,7 +2316,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data, | |
| goto out; | |
| } | |
| else { | |
| - | switch(Curl_cpool_check_limits(data, needle, &needle->created)) { |
| + | switch(Curl_cpool_check_limits(data, needle, pnow)) { |
| case CPOOL_LIMIT_DEST: | |
| infof(data, "No more connections allowed to host"); | |
| result = CURLE_NO_CONNECTION_AVAILABLE; | |
| @@ -2351,7 +2347,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data, | |
| /* Add needle to conn pool, which assigns the connection id. | |
| * Attach regardless of result, for correct handling. */ | |
| - | result = Curl_cpool_add(data, needle); |
| + | result = Curl_cpool_add(data, needle, pnow); |
| Curl_attach_connection(data, needle, TRUE); | |
| needle = NULL; | |
| if(result) | |
| @@ -950,8 +950,8 @@ clean_up: | |
| the time we spent until now! */ | |
| if(prev_alarm) { | |
| /* there was an alarm() set before us, now put it back */ | |
| - | timediff_t elapsed_secs = curlx_ptimediff_ms(Curl_pgrs_now(data), |
| - | &data->conn->created) / 1000; |
| + | timediff_t elapsed_secs = |
| + | Curl_cpool_conn_age_ms(data, data->conn, Curl_pgrs_now(data)) / 1000; |
| /* the alarm period is counted in even number of seconds */ | |
| unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs); | |
| @@ -1520,7 +1520,7 @@ static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf, | |
| *done = FALSE; | |
| while(!result && !*done && loop--) { | |
| - | timeout_ms = Curl_shutdown_timeleft(data, cf->conn, cf->sockindex); |
| + | timeout_ms = Curl_cshutdn_timeleft_ms(data, cf->conn, cf->sockindex); |
| if(timeout_ms < 0) { | |
| /* no need to continue if time is already up */ | |
| @@ -1567,9 +1567,9 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, | |
| if(cf->cft == &Curl_cft_ssl) { | |
| bool done; | |
| CURL_TRC_CF(data, cf, "shutdown and remove SSL, start"); | |
| - | Curl_shutdown_start(data, sockindex, 0); |
| + | Curl_cshutdn_start_timer(data, sockindex, 0); |
| result = vtls_shutdown_blocking(cf, data, send_shutdown, &done); | |
| - | Curl_shutdown_clear(data, sockindex); |
| + | Curl_cshutdn_clear_timer(data, sockindex); |
| if(!result && !done) /* blocking failed? */ | |
| result = CURLE_SSL_SHUTDOWN_FAILED; | |
| Curl_conn_cf_discard(&cf, data); | |