← Commit list

7103a93b05

Stefan Eissing
Stefan Eissing
2026-08-14
SUCCESS Duration: 430s

Subject

connections: use admin handles only for maintenance

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/conncache.c+174 -141
@@ -42,7 +42,7 @@
do { \
if(c) { \
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
- Curl_share_lock((d), CURL_LOCK_DATA_CONNECT, \
+ Curl_share_lock_share((c)->share, (d), CURL_LOCK_DATA_CONNECT, \
CURL_LOCK_ACCESS_SINGLE); \
DEBUGASSERT(!(c)->locked); \
(c)->locked = TRUE; \
@@ -55,7 +55,7 @@
DEBUGASSERT((c)->locked); \
(c)->locked = FALSE; \
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
- Curl_share_unlock((d), CURL_LOCK_DATA_CONNECT); \
+ Curl_share_unlock_share((c)->share, (d), CURL_LOCK_DATA_CONNECT); \
} \
} while(0)
@@ -111,16 +111,12 @@ static void cpool_bundle_free_entry(void *freethis)
}
void Curl_cpool_init(struct cpool *cpool,
- struct Curl_easy *idata,
struct Curl_share *share,
size_t size)
{
Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
curlx_str_key_compare, cpool_bundle_free_entry);
- DEBUGASSERT(idata);
-
- cpool->idata = idata;
cpool->share = share;
cpool->initialized = TRUE;
}
@@ -186,6 +182,8 @@ static void cpool_discard_conn(struct cpool *cpool,
struct connectdata *conn,
bool aborted)
{
+ struct cshutdn *cshutdn;
+ struct Curl_easy *admin;
bool done = FALSE;
DEBUGASSERT(data);
@@ -193,12 +191,13 @@ static void cpool_discard_conn(struct cpool *cpool,
DEBUGASSERT(cpool);
DEBUGASSERT(!conn->bits.in_cpool);
+ admin = Curl_get_admin(data);
/*
* If this connection is not marked to force-close, leave it open if there
* are other users of it
*/
if(CONN_INUSE(conn) && !aborted) {
- CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
+ CURL_TRC_M(admin, "[CPOOL] not discarding #%" FMT_OFF_T
" still in use by %u transfers", conn->connection_id,
conn->attached_xfers);
return;
@@ -219,35 +218,36 @@ static void cpool_discard_conn(struct cpool *cpool,
done = TRUE;
if(!done) {
/* Attempt to shutdown the connection right away. */
- Curl_cshutdn_run_once(cpool->idata, conn, &done);
+ Curl_conn_shutdown_once(admin, conn, &done);
}
- if(done || !data->multi)
- Curl_cshutdn_terminate(cpool->idata, conn, FALSE);
+ cshutdn = Curl_cshutdn_get(data);
+ if(done || !cshutdn)
+ Curl_conn_terminate(admin, conn, FALSE);
else
- Curl_cshutdn_add(&data->multi->cshutdn, conn, cpool->num_conn);
+ Curl_cshutdn_add(cshutdn, conn, cpool->num_conn);
}
-void Curl_cpool_destroy(struct cpool *cpool)
+void Curl_cpool_destroy(struct cpool *cpool, struct Curl_easy *admin)
{
- if(cpool && cpool->initialized && cpool->idata) {
+ if(cpool && cpool->initialized && admin) {
struct connectdata *conn;
struct Curl_sigpipe_ctx pipe_ctx;
- CURL_TRC_M(cpool->idata, "%s[CPOOL] destroy, %zu connections",
+ CURL_TRC_M(admin, "%s[CPOOL] destroy, %zu connections",
cpool->share ? "[SHARE] " : "", cpool->num_conn);
/* Move all connections to the shutdown list */
sigpipe_init(&pipe_ctx);
- CPOOL_LOCK(cpool, cpool->idata);
+ CPOOL_LOCK(cpool, admin);
conn = cpool_get_first(cpool);
if(conn)
- sigpipe_apply(cpool->idata, &pipe_ctx);
+ sigpipe_apply(admin, &pipe_ctx);
while(conn) {
cpool_remove_conn(cpool, conn);
- cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
+ cpool_discard_conn(cpool, admin, conn, FALSE);
conn = cpool_get_first(cpool);
}
- CPOOL_UNLOCK(cpool, cpool->idata);
+ CPOOL_UNLOCK(cpool, admin);
sigpipe_restore(&pipe_ctx);
Curl_hash_destroy(&cpool->dest2bundle);
}
@@ -255,17 +255,22 @@ void Curl_cpool_destroy(struct cpool *cpool)
static struct cpool *cpool_get_instance(struct Curl_easy *data)
{
- if(data) {
- if(CURL_SHARE_KEEP_CONNECT(data->share))
- return &data->share->cpool;
- else if(data->multi_easy)
- return &data->multi_easy->cpool;
- else if(data->multi)
- return &data->multi->cpool;
- }
+ /* admin handles do not necessarily find the correct pool */
+ DEBUGASSERT(data->mid);
+ if(CURL_SHARE_KEEP_CONNECT(data->share))
+ return &data->share->cpool;
+ else if(data->multi_easy)
+ return &data->multi_easy->cpool;
+ else if(data->multi)
+ return &data->multi->cpool;
return NULL;
}
+struct cpool *Curl_cpool_get_instance(struct Curl_easy *data)
+{
+ return cpool_get_instance(data);
+}
+
void Curl_cpool_xfer_init(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
@@ -367,26 +372,90 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
return oldest_idle;
}
+static void cpool_conn_close(struct cpool *cpool,
+ struct Curl_easy *data,
+ struct connectdata *conn,
+ bool aborted)
+{
+ struct Curl_easy *admin;
+ bool do_lock;
+
+ DEBUGASSERT(cpool);
+ DEBUGASSERT(data && !data->conn);
+ if(!cpool)
+ return;
+
+ /* If this connection is not marked to force-close, leave it open if there
+ * are other users of it */
+ if(CONN_INUSE(conn) && !aborted) {
+ DEBUGASSERT(0); /* does this ever happen? */
+ DEBUGF(infof(data, "conn terminate when inuse: %u", conn->attached_xfers));
+ return;
+ }
+
+ /* This method may be called while we are under lock, e.g. from a
+ * user callback in find. */
+ admin = Curl_get_admin(data);
+ do_lock = !CPOOL_IS_LOCKED(cpool);
+ if(do_lock)
+ CPOOL_LOCK(cpool, admin);
+
+ if(conn->bits.in_cpool) {
+ cpool_remove_conn(cpool, conn);
+ DEBUGASSERT(!conn->bits.in_cpool);
+ }
+
+ /* treat the connection as aborted in CONNECT_ONLY situations,
+ * so no graceful shutdown is attempted. */
+ if(conn->bits.connect_only)
+ aborted = TRUE;
+
+ if(data->multi) {
+ /* Add it to the multi's cpool for shutdown handling */
+ infof(data, "%s connection #%" FMT_OFF_T,
+ aborted ? "closing" : "shutting down", conn->connection_id);
+ cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
+ }
+ else {
+ /* No multi available, terminate */
+ infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
+ Curl_conn_terminate(admin, conn, !aborted);
+ }
+
+ if(do_lock)
+ CPOOL_UNLOCK(cpool, admin);
+}
+
+void Curl_conn_close(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool aborted)
+{
+ struct cpool *cpool = cpool_get_instance(data);
+ cpool_conn_close(cpool, data, conn, aborted);
+}
+
/* Evict an idle connection to make room in the pool. A pool owned by
* a share has no multi that could perform a controlled shutdown of the
* connection; terminate it right away. Otherwise, hand it to the
* transfer's multi for shutdown. Expects the pool to be locked. */
static void cpool_evict_conn(struct cpool *cpool,
- struct Curl_easy *data,
+ struct Curl_easy *admin,
struct connectdata *conn)
{
if(cpool->share) {
cpool_remove_conn(cpool, conn);
- Curl_cshutdn_terminate(cpool->idata, conn, TRUE);
+ Curl_conn_terminate(admin, conn, TRUE);
}
else
- Curl_conn_terminate(data, conn, FALSE);
+ cpool_conn_close(cpool, admin, conn, FALSE);
}
int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *conn)
{
struct cpool *cpool = cpool_get_instance(data);
+ struct cshutdn *cshutdn = Curl_cshutdn_get(data);
+ struct Curl_easy *admin;
struct cpool_bundle *bundle;
size_t dest_limit = 0;
size_t total_limit = 0;
@@ -405,17 +474,18 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!dest_limit && !total_limit)
return CPOOL_LIMIT_OK;
- CPOOL_LOCK(cpool, cpool->idata);
+ admin = Curl_get_admin(data);
+ CPOOL_LOCK(cpool, admin);
if(dest_limit) {
size_t live;
bundle = cpool_find_bundle(cpool, conn);
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
- shutdowns = Curl_cshutdn_dest_count(data, conn->destination);
+ shutdowns = Curl_cshutdn_dest_count(cshutdn, conn->destination);
while((live + shutdowns) >= dest_limit) {
if(shutdowns) {
/* close one connection in shutdown right away, if we can */
- if(!Curl_cshutdn_close_oldest(data, conn->destination))
+ if(!Curl_cshutdn_close_oldest(cshutdn, conn->destination))
break;
}
else if(!bundle)
@@ -429,17 +499,17 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
- CURL_TRC_M(data, "Discarding connection #%" FMT_OFF_T
+ CURL_TRC_M(admin, "Discarding connection #%" FMT_OFF_T
" from %zu to reach destination limit of %zu",
oldest_idle->connection_id,
Curl_llist_count(&bundle->conns), dest_limit);
- cpool_evict_conn(cpool, data, oldest_idle);
+ cpool_evict_conn(cpool, admin, oldest_idle);
/* in case the bundle was destroyed in disconnect, look it up again */
bundle = cpool_find_bundle(cpool, conn);
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
}
- shutdowns = Curl_cshutdn_dest_count(data, conn->destination);
+ shutdowns = Curl_cshutdn_dest_count(cshutdn, conn->destination);
}
if((live + shutdowns) >= dest_limit) {
res = CPOOL_LIMIT_DEST;
@@ -448,11 +518,11 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
if(total_limit) {
- shutdowns = Curl_cshutdn_count(data);
+ shutdowns = Curl_cshutdn_count(cshutdn);
while((cpool->num_conn + shutdowns) >= total_limit) {
if(shutdowns) {
/* close one connection in shutdown right away, if we can */
- if(!Curl_cshutdn_close_oldest(data, NULL))
+ if(!Curl_cshutdn_close_oldest(cshutdn, NULL))
break;
}
else {
@@ -461,13 +531,13 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
- CURL_TRC_M(data, "Discarding connection #%"
+ CURL_TRC_M(admin, "Discarding connection #%"
FMT_OFF_T " from %zu to reach total "
"limit of %zu",
oldest_idle->connection_id, cpool->num_conn, total_limit);
- cpool_evict_conn(cpool, data, oldest_idle);
+ cpool_evict_conn(cpool, admin, oldest_idle);
}
- shutdowns = Curl_cshutdn_count(data);
+ shutdowns = Curl_cshutdn_count(cshutdn);
}
if((cpool->num_conn + shutdowns) >= total_limit) {
res = CPOOL_LIMIT_TOTAL;
@@ -476,7 +546,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
out:
- CPOOL_UNLOCK(cpool, cpool->idata);
+ CPOOL_UNLOCK(cpool, admin);
return res;
}
@@ -529,7 +599,8 @@ out:
static bool cpool_foreach(struct Curl_easy *data,
struct cpool *cpool,
void *param,
- int (*func)(struct Curl_easy *data,
+ int (*func)(struct cpool *cpool,
+ struct Curl_easy *data,
struct connectdata *conn, void *param))
{
struct Curl_hash_iterator iter;
@@ -553,7 +624,7 @@ static bool cpool_foreach(struct Curl_easy *data,
struct connectdata *conn = Curl_node_elem(curr);
curr = Curl_node_next(curr);
- if(func(data, conn, param) == 1) {
+ if(func(cpool, data, conn, param) == 1) {
return TRUE;
}
}
@@ -573,6 +644,7 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
unsigned int maxconnects;
struct connectdata *oldest_idle = NULL;
struct cpool *cpool = cpool_get_instance(data);
+ struct Curl_easy *admin;
bool kept = TRUE;
if(!data || !data->multi)
@@ -590,8 +662,10 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
if(cpool && maxconnects) {
/* may be called form a callback already under lock */
bool do_lock = !CPOOL_IS_LOCKED(cpool);
+
+ admin = Curl_get_admin(data);
if(do_lock)
- CPOOL_LOCK(cpool, data);
+ CPOOL_LOCK(cpool, admin);
if(cpool->num_conn > maxconnects) {
infof(data, "Connection pool is full, closing the oldest of %zu/%u",
cpool->num_conn, maxconnects);
@@ -599,11 +673,11 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
oldest_idle = cpool_get_oldest_idle(cpool, Curl_pgrs_now(data));
kept = (oldest_idle != conn);
if(oldest_idle) {
- cpool_evict_conn(cpool, data, oldest_idle);
+ cpool_evict_conn(cpool, admin, oldest_idle);
}
}
if(do_lock)
- CPOOL_UNLOCK(cpool, data);
+ CPOOL_UNLOCK(cpool, admin);
}
return kept;
@@ -649,74 +723,23 @@ bool Curl_cpool_find(struct Curl_easy *data,
return found;
}
-void Curl_conn_terminate(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted)
-{
- struct cpool *cpool = cpool_get_instance(data);
- bool do_lock;
-
- DEBUGASSERT(cpool);
- DEBUGASSERT(data && !data->conn);
- if(!cpool)
- return;
-
- /* If this connection is not marked to force-close, leave it open if there
- * are other users of it */
- if(CONN_INUSE(conn) && !aborted) {
- DEBUGASSERT(0); /* does this ever happen? */
- DEBUGF(infof(data, "conn terminate when inuse: %u", conn->attached_xfers));
- return;
- }
-
- /* This method may be called while we are under lock, e.g. from a
- * user callback in find. */
- do_lock = !CPOOL_IS_LOCKED(cpool);
- if(do_lock)
- CPOOL_LOCK(cpool, data);
-
- if(conn->bits.in_cpool) {
- cpool_remove_conn(cpool, conn);
- DEBUGASSERT(!conn->bits.in_cpool);
- }
-
- /* treat the connection as aborted in CONNECT_ONLY situations,
- * so no graceful shutdown is attempted. */
- if(conn->bits.connect_only)
- aborted = TRUE;
-
- if(data->multi) {
- /* Add it to the multi's cpool for shutdown handling */
- infof(data, "%s connection #%" FMT_OFF_T,
- aborted ? "closing" : "shutting down", conn->connection_id);
- cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
- }
- else {
- /* No multi available, terminate */
- infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
- Curl_cshutdn_terminate(cpool->idata, conn, !aborted);
- }
-
- if(do_lock)
- CPOOL_UNLOCK(cpool, data);
-}
-
struct cpool_reaper_ctx {
size_t reaped;
struct curltime now;
};
-static int cpool_reap_dead_cb(struct Curl_easy *data,
+static int cpool_reap_dead_cb(struct cpool *cpool,
+ struct Curl_easy *admin,
struct connectdata *conn, void *param)
{
struct cpool_reaper_ctx *reaper = param;
if(!CONN_INUSE(conn)) {
if(conn->bits.no_reuse || conn->bits.close ||
- !Curl_cpool_conn_seems_healthy(conn, data, &reaper->now)) {
+ !Curl_cpool_conn_seems_healthy(conn, admin, &reaper->now)) {
/* terminate conn and stop the iteration */
reaper->reaped++;
- Curl_conn_terminate(data, conn, FALSE);
+ cpool_conn_close(cpool, admin, conn, FALSE);
return 1;
}
}
@@ -730,46 +753,49 @@ static int cpool_reap_dead_cb(struct Curl_easy *data,
*
* When called, this transfer has no connection attached.
*/
-void Curl_cpool_prune_dead(struct Curl_easy *data)
+void Curl_cpool_prune_dead(struct cpool *cpool,
+ struct Curl_easy *data)
{
- struct cpool *cpool = cpool_get_instance(data);
+ struct Curl_easy *admin;
timediff_t elapsed;
if(!cpool)
return;
- CPOOL_LOCK(cpool, data);
- elapsed = curlx_ptimediff_ms(Curl_pgrs_now(data), &cpool->last_cleanup);
+ admin = Curl_get_admin(data);
+ CPOOL_LOCK(cpool, admin);
+ elapsed = curlx_ptimediff_ms(Curl_pgrs_now(admin), &cpool->last_cleanup);
if(elapsed >= 1000L) {
struct cpool_reaper_ctx reaper;
memset(&reaper, 0, sizeof(reaper));
- reaper.now = *Curl_pgrs_now(data);
- while(cpool_foreach(data, cpool, &reaper, cpool_reap_dead_cb))
+ reaper.now = *Curl_pgrs_now(admin);
+ while(cpool_foreach(admin, cpool, &reaper, cpool_reap_dead_cb))
;
- cpool->last_cleanup = *Curl_pgrs_now(data);
+ cpool->last_cleanup = *Curl_pgrs_now(admin);
}
- CPOOL_UNLOCK(cpool, data);
+ CPOOL_UNLOCK(cpool, admin);
}
-static int conn_upkeep(struct Curl_easy *data,
+static int conn_upkeep(struct cpool *cpool,
+ struct Curl_easy *admin,
struct connectdata *conn,
void *param)
{
(void)param;
- if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) >=
- data->set.upkeep_interval_ms) {
+ if(curlx_ptimediff_ms(Curl_pgrs_now(admin), &conn->keepalive) >=
+ admin->set.upkeep_interval_ms) {
CURLcode result;
/* briefly attach for action */
- Curl_attach_connection(data, conn);
- result = Curl_conn_keep_alive(data, conn);
- conn->keepalive = *Curl_pgrs_now(data);
- Curl_detach_connection(data);
+ Curl_attach_connection(admin, conn, FALSE);
+ result = Curl_conn_keep_alive(admin, conn);
+ conn->keepalive = *Curl_pgrs_now(admin);
+ Curl_detach_connection(admin);
if(result && !CONN_INUSE(conn)) {
- Curl_conn_terminate(data, conn, FALSE);
+ cpool_conn_close(cpool, admin, conn, FALSE);
return 1;
}
}
@@ -779,14 +805,15 @@ static int conn_upkeep(struct Curl_easy *data,
CURLcode Curl_cpool_upkeep(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
+ struct Curl_easy *admin = Curl_get_admin(data);
if(!cpool)
return CURLE_OK;
- CPOOL_LOCK(cpool, data);
- while(cpool_foreach(data, cpool, NULL, conn_upkeep))
+ CPOOL_LOCK(cpool, admin);
+ while(cpool_foreach(admin, cpool, NULL, conn_upkeep))
;
- CPOOL_UNLOCK(cpool, data);
+ CPOOL_UNLOCK(cpool, admin);
return CURLE_OK;
}
@@ -795,10 +822,12 @@ struct cpool_find_ctx {
struct connectdata *conn;
};
-static int cpool_find_conn(struct Curl_easy *data,
+static int cpool_find_conn(struct cpool *cpool,
+ struct Curl_easy *data,
struct connectdata *conn, void *param)
{
struct cpool_find_ctx *fctx = param;
+ (void)cpool;
(void)data;
if(conn->connection_id == fctx->id) {
fctx->conn = conn;
@@ -837,36 +866,37 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
cb(conn, data, cbdata);
}
-static int cpool_mark_stale(struct Curl_easy *data,
+static int cpool_mark_stale(struct cpool *cpool,
+ struct Curl_easy *admin,
struct connectdata *conn, void *param)
{
- (void)data;
+ (void)cpool;
+ (void)admin;
(void)param;
conn->bits.no_reuse = TRUE;
return 0;
}
-static int cpool_reap_no_reuse(struct Curl_easy *data,
+static int cpool_reap_no_reuse(struct cpool *cpool,
+ struct Curl_easy *admin,
struct connectdata *conn, void *param)
{
(void)param;
if(!CONN_INUSE(conn) && conn->bits.no_reuse) {
- Curl_conn_terminate(data, conn, FALSE);
+ cpool_conn_close(cpool, admin, conn, FALSE);
return 1;
}
return 0; /* continue iteration */
}
-void Curl_cpool_nw_changed(struct Curl_easy *data)
+void Curl_cpool_nw_changed(struct cpool *cpool, struct Curl_easy *admin)
{
- struct cpool *cpool = cpool_get_instance(data);
-
- if(cpool) {
- CPOOL_LOCK(cpool, data);
- cpool_foreach(data, cpool, NULL, cpool_mark_stale);
- while(cpool_foreach(data, cpool, NULL, cpool_reap_no_reuse))
+ if(cpool && admin) {
+ CPOOL_LOCK(cpool, admin);
+ cpool_foreach(admin, cpool, NULL, cpool_mark_stale);
+ while(cpool_foreach(admin, cpool, NULL, cpool_reap_no_reuse))
;
- CPOOL_UNLOCK(cpool, data);
+ CPOOL_UNLOCK(cpool, admin);
}
}
@@ -907,24 +937,27 @@ bool Curl_cpool_conn_seems_healthy(struct connectdata *conn,
struct Curl_easy *data,
const struct curltime *pnow)
{
+ struct Curl_easy *admin;
bool healthy = TRUE;
DEBUGASSERT(!data->conn);
if(!CONN_INUSE(conn) && cpool_conn_maxage(data, conn, pnow)) /* too old? */
return FALSE;
- else if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000)
+ if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000)
return TRUE;
- else if(conn->scheme->run->connection_is_dead) {
- Curl_attach_connection(data, conn);
- healthy = !conn->scheme->run->connection_is_dead(data, conn);
- Curl_detach_connection(data);
+
+ admin = Curl_get_admin(data);
+ if(conn->scheme->run->connection_is_dead) {
+ Curl_attach_connection(admin, conn, FALSE);
+ healthy = !conn->scheme->run->connection_is_dead(admin, conn);
+ Curl_detach_connection(admin);
}
else {
bool input_pending = FALSE;
- Curl_attach_connection(data, conn);
- healthy = Curl_conn_is_alive(data, conn, &input_pending);
- Curl_detach_connection(data);
+ Curl_attach_connection(admin, conn, FALSE);
+ healthy = Curl_conn_is_alive(admin, conn, &input_pending);
+ Curl_detach_connection(admin);
if(healthy && input_pending &&
!CONN_INUSE(conn) && !Curl_conn_is_multiplex(conn, FIRSTSOCKET)) {
/* Non-multiplexed connections without attached transfers should
lib/conncache.h+13 -12
@@ -34,7 +34,7 @@ struct Curl_multi;
struct Curl_share;
/**
- * Terminate the connection, e.g. close and destroy.
+ * Close and destroy the connection.
* If the connection is in a cpool, remove it.
* If a `cshutdn` is available (e.g. data has a multi handle),
* pass the connection to that for controlled shutdown.
@@ -42,9 +42,9 @@ struct Curl_share;
* Takes ownership of `conn`.
* `data` should not be attached to a connection.
*/
-void Curl_conn_terminate(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted);
+void Curl_conn_close(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool aborted);
struct cpool {
/* the pooled connections, bundled per destination */
@@ -53,22 +53,24 @@ struct cpool {
curl_off_t next_connection_id;
curl_off_t next_easy_id;
struct curltime last_cleanup;
- struct Curl_easy *idata; /* internal handle for maintenance */
struct Curl_share *share; /* != NULL if pool belongs to share */
BIT(locked);
BIT(initialized);
};
+/* Get connection pool instance for data or NULL if none exists */
+struct cpool *Curl_cpool_get_instance(struct Curl_easy *data);
+
/* Init the pool, pass multi only if pool is owned by it.
* Cannot fail.
*/
void Curl_cpool_init(struct cpool *cpool,
- struct Curl_easy *idata,
struct Curl_share *share,
size_t size);
/* Destroy all connections and free all members */
-void Curl_cpool_destroy(struct cpool *cpool);
+void Curl_cpool_destroy(struct cpool *cpool,
+ struct Curl_easy *admin);
/* Init the transfer to be used within its connection pool.
* Assigns `data->id`. */
@@ -126,13 +128,12 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
struct connectdata *conn);
/**
- * This function scans the data's connection pool for half-open/dead
+ * Scans the connection pool for half-open/dead
* connections, closes and removes them.
* The cleanup is done at most once per second.
- *
- * When called, this transfer has no connection attached.
*/
-void Curl_cpool_prune_dead(struct Curl_easy *data);
+void Curl_cpool_prune_dead(struct cpool *cpool,
+ struct Curl_easy *data);
/**
* Perform upkeep actions on connections in the transfer's pool.
@@ -154,7 +155,7 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
Curl_cpool_conn_do_cb *cb, void *cbdata);
/* Close all unused connections, prevent reuse of existing ones. */
-void Curl_cpool_nw_changed(struct Curl_easy *data);
+void Curl_cpool_nw_changed(struct cpool *cpool, struct Curl_easy *admin);
/* Return TRUE iff the given connection is considered healthy, e.g.
* usable for more transfers. */
lib/cshutdn.c+84 -90
@@ -38,6 +38,13 @@
#include "curlx/strparse.h"
+struct cshutdn *Curl_cshutdn_get(struct Curl_easy *data)
+{
+ if(data && data->multi)
+ return &data->multi->cshutdn;
+ return NULL;
+}
+
static void cshutdn_run_conn_handler(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -107,22 +114,22 @@ static void cshutdn_run_once(struct Curl_easy *data,
conn->bits.shutdown_filters = TRUE;
}
-void Curl_cshutdn_run_once(struct Curl_easy *data,
+void Curl_conn_shutdown_once(struct Curl_easy *admin,
struct connectdata *conn,
bool *done)
{
- DEBUGASSERT(!data->conn);
- Curl_attach_connection(data, conn);
- cshutdn_run_once(data, conn, done);
- CURL_TRC_M(data, "[SHUTDOWN] shutdown, done=%d", *done);
- Curl_detach_connection(data);
+ DEBUGASSERT(!admin->conn);
+ DEBUGASSERT(!admin->mid);
+ Curl_attach_connection(admin, conn, FALSE);
+ cshutdn_run_once(admin, conn, done);
+ CURL_TRC_M(admin, "[SHUTDOWN] shutdown, done=%d", *done);
+ Curl_detach_connection(admin);
}
-void Curl_cshutdn_terminate(struct Curl_easy *data,
- struct connectdata *conn,
- bool do_shutdown)
+void Curl_conn_terminate(struct Curl_easy *admin,
+ struct connectdata *conn,
+ bool do_shutdown)
{
- struct Curl_easy *admin = data;
bool done;
/* there must be a connection to close */
@@ -130,16 +137,10 @@ void Curl_cshutdn_terminate(struct Curl_easy *data,
/* it must be removed from the connection pool */
DEBUGASSERT(!conn->bits.in_cpool);
/* the transfer must be detached from the connection */
- DEBUGASSERT(data && !data->conn);
+ DEBUGASSERT(admin && !admin->conn);
+ DEBUGASSERT(!admin->mid);
- /* If we can obtain an internal admin handle, use that to attach
- * and terminate the connection. Some protocol will try to mess with
- * `data` during shutdown and we do not want that with a `data` from
- * the application. */
- if(data->multi && data->multi->admin)
- admin = data->multi->admin;
-
- Curl_attach_connection(admin, conn);
+ Curl_attach_connection(admin, conn, FALSE);
cshutdn_run_conn_handler(admin, conn);
if(do_shutdown) {
@@ -154,18 +155,17 @@ void Curl_cshutdn_terminate(struct Curl_easy *data,
Curl_conn_cf_discard_all(admin, conn, FIRSTSOCKET);
Curl_detach_connection(admin);
- if(data->multi)
- Curl_multi_ev_conn_done(data->multi, data, conn);
+ if(admin->multi)
+ Curl_multi_ev_conn_done(admin->multi, admin, conn);
Curl_conn_free(admin, conn);
- if(data->multi) {
- CURL_TRC_M(data, "[SHUTDOWN] trigger multi connchanged");
- Curl_multi_connchanged(data->multi);
+ if(admin->multi) {
+ CURL_TRC_M(admin, "[SHUTDOWN] trigger multi connchanged");
+ Curl_multi_connchanged(admin->multi);
}
}
static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn,
- struct Curl_easy *data,
const char *destination)
{
struct Curl_llist_node *e;
@@ -184,20 +184,19 @@ static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn,
conn = Curl_node_elem(e);
Curl_node_remove(e);
sigpipe_init(&sigpipe_ctx);
- sigpipe_apply(data, &sigpipe_ctx);
- Curl_cshutdn_terminate(data, conn, FALSE);
+ sigpipe_apply(cshutdn->multi->admin, &sigpipe_ctx);
+ Curl_conn_terminate(cshutdn->multi->admin, conn, FALSE);
sigpipe_restore(&sigpipe_ctx);
return TRUE;
}
return FALSE;
}
-bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
+bool Curl_cshutdn_close_oldest(struct cshutdn *cshutdn,
const char *destination)
{
- if(data && data->multi) {
- struct cshutdn *csd = &data->multi->cshutdn;
- return cshutdn_destroy_oldest(csd, data, destination);
+ if(cshutdn) {
+ return cshutdn_destroy_oldest(cshutdn, destination);
}
return FALSE;
}
@@ -205,7 +204,6 @@ bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
#define NUM_POLLS_ON_STACK 10
static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
- struct Curl_easy *data,
int timeout_ms)
{
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
@@ -214,7 +212,7 @@ static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
- result = Curl_cshutdn_add_pollfds(cshutdn, data, &cpfds);
+ result = Curl_cshutdn_add_pollfds(cshutdn, &cpfds);
if(result)
goto out;
@@ -226,11 +224,11 @@ out:
}
static void cshutdn_perform(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx)
{
struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
struct Curl_llist_node *enext;
+ struct Curl_easy *admin = cshutdn->multi->admin;
struct connectdata *conn;
timediff_t next_expire_ms = 0, ms;
bool done;
@@ -238,21 +236,21 @@ static void cshutdn_perform(struct cshutdn *cshutdn,
if(!e)
return;
- CURL_TRC_M(data, "[SHUTDOWN] perform on %zu connections",
+ CURL_TRC_M(admin, "[SHUTDOWN] perform on %zu connections",
Curl_llist_count(&cshutdn->list));
- sigpipe_apply(data, sigpipe_ctx);
+ sigpipe_apply(admin, sigpipe_ctx);
while(e) {
enext = Curl_node_next(e);
conn = Curl_node_elem(e);
- Curl_cshutdn_run_once(data, conn, &done);
+ Curl_conn_shutdown_once(admin, conn, &done);
if(done) {
Curl_node_remove(e);
- Curl_cshutdn_terminate(data, conn, FALSE);
+ Curl_conn_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(data, conn);
+ ms = Curl_conn_shutdown_timeleft(admin, conn);
if(ms && (!next_expire_ms || (ms < next_expire_ms)))
next_expire_ms = ms;
}
@@ -260,45 +258,42 @@ static void cshutdn_perform(struct cshutdn *cshutdn,
}
if(next_expire_ms)
- Curl_expire_ex(data, next_expire_ms, EXPIRE_SHUTDOWN);
+ Curl_expire_ex(admin, next_expire_ms, EXPIRE_SHUTDOWN);
}
static void cshutdn_terminate_all(struct cshutdn *cshutdn,
- struct Curl_easy *data,
int timeout_ms)
{
- struct curltime started = *Curl_pgrs_now(data);
+ struct Curl_easy *admin = cshutdn->multi->admin;
+ struct curltime started = *Curl_pgrs_now(admin);
struct Curl_llist_node *e;
struct Curl_sigpipe_ctx sigpipe_ctx;
- DEBUGASSERT(cshutdn);
- DEBUGASSERT(data);
-
- CURL_TRC_M(data, "[SHUTDOWN] shutdown all");
+ CURL_TRC_M(admin, "[SHUTDOWN] shutdown all");
sigpipe_init(&sigpipe_ctx);
while(Curl_llist_head(&cshutdn->list)) {
timediff_t spent_ms;
int remain_ms;
- cshutdn_perform(cshutdn, data, &sigpipe_ctx);
+ cshutdn_perform(cshutdn, &sigpipe_ctx);
if(!Curl_llist_head(&cshutdn->list)) {
- CURL_TRC_M(data, "[SHUTDOWN] shutdown finished cleanly");
+ CURL_TRC_M(admin, "[SHUTDOWN] shutdown finished cleanly");
break;
}
/* wait for activity, timeout or "nothing" */
- spent_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &started);
+ spent_ms = curlx_ptimediff_ms(Curl_pgrs_now(admin), &started);
if(spent_ms >= (timediff_t)timeout_ms) {
- CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, %s",
+ CURL_TRC_M(admin, "[SHUTDOWN] shutdown finished, %s",
(timeout_ms > 0) ? "timeout" : "best effort done");
break;
}
remain_ms = timeout_ms - (int)spent_ms;
- if(cshutdn_wait(cshutdn, data, remain_ms)) {
- CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, aborted");
+ if(cshutdn_wait(cshutdn, remain_ms)) {
+ CURL_TRC_M(admin, "[SHUTDOWN] shutdown finished, aborted");
break;
}
}
@@ -308,7 +303,7 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn,
while(e) {
struct connectdata *conn = Curl_node_elem(e);
Curl_node_remove(e);
- Curl_cshutdn_terminate(data, conn, FALSE);
+ Curl_conn_terminate(admin, conn, FALSE);
e = Curl_llist_head(&cshutdn->list);
}
DEBUGASSERT(!Curl_llist_count(&cshutdn->list));
@@ -327,12 +322,13 @@ int Curl_cshutdn_init(struct cshutdn *cshutdn,
}
void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
- struct Curl_easy *data)
+ struct Curl_easy *admin)
{
- if(cshutdn->initialized && data) {
+ if(cshutdn->initialized && admin) {
int timeout_ms = 0;
/* for testing, run graceful shutdown */
#ifdef DEBUGBUILD
+ DEBUGASSERT(!admin->mid);
{
const char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
if(p) {
@@ -343,29 +339,28 @@ void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
}
#endif
- CURL_TRC_M(data, "[SHUTDOWN] destroy, %zu connections, timeout=%dms",
+ CURL_TRC_M(admin, "[SHUTDOWN] destroy, %zu connections, timeout=%dms",
Curl_llist_count(&cshutdn->list), timeout_ms);
- cshutdn_terminate_all(cshutdn, data, timeout_ms);
+ cshutdn_terminate_all(cshutdn, timeout_ms);
}
cshutdn->multi = NULL;
+ cshutdn->initialized = FALSE;
}
-size_t Curl_cshutdn_count(struct Curl_easy *data)
+size_t Curl_cshutdn_count(struct cshutdn *cshutdn)
{
- if(data && data->multi) {
- struct cshutdn *csd = &data->multi->cshutdn;
- return Curl_llist_count(&csd->list);
+ if(cshutdn) {
+ return Curl_llist_count(&cshutdn->list);
}
return 0;
}
-size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
+size_t Curl_cshutdn_dest_count(struct cshutdn *cshutdn,
const char *destination)
{
- if(data && data->multi) {
- struct cshutdn *csd = &data->multi->cshutdn;
+ if(cshutdn) {
size_t n = 0;
- struct Curl_llist_node *e = Curl_llist_head(&csd->list);
+ struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
while(e) {
struct connectdata *conn = Curl_node_elem(e);
if(!strcmp(destination, conn->destination))
@@ -378,17 +373,17 @@ size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
}
static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct connectdata *conn)
{
+ struct Curl_easy *admin = cshutdn->multi->admin;
CURLMcode mresult;
DEBUGASSERT(cshutdn);
DEBUGASSERT(cshutdn->multi->socket_cb);
- Curl_attach_connection(data, conn);
- mresult = Curl_multi_ev_assess_conn(cshutdn->multi, data, conn);
- Curl_detach_connection(data);
+ Curl_attach_connection(admin, conn, FALSE);
+ mresult = Curl_multi_ev_assess_conn(cshutdn->multi, admin, conn);
+ Curl_detach_connection(admin);
return mresult;
}
@@ -396,47 +391,46 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn,
struct connectdata *conn,
size_t conns_in_pool)
{
- struct Curl_easy *data = cshutdn->multi->admin;
+ struct Curl_easy *admin = cshutdn->multi->admin;
size_t max_total = cshutdn->multi->max_total_connections;
/* Add the connection to our shutdown list for non-blocking shutdown
* during multi processing. */
if(max_total > 0 &&
(max_total <= (conns_in_pool + Curl_llist_count(&cshutdn->list)))) {
- CURL_TRC_M(data, "[SHUTDOWN] discarding oldest shutdown connection "
+ CURL_TRC_M(admin, "[SHUTDOWN] discarding oldest shutdown connection "
"due to connection limit of %zu", max_total);
- cshutdn_destroy_oldest(cshutdn, data, NULL);
+ cshutdn_destroy_oldest(cshutdn, NULL);
}
if(cshutdn->multi->socket_cb) {
- if(cshutdn_update_ev(cshutdn, data, conn)) {
- CURL_TRC_M(data, "[SHUTDOWN] update events failed, discarding #%"
+ if(cshutdn_update_ev(cshutdn, conn)) {
+ CURL_TRC_M(admin, "[SHUTDOWN] update events failed, discarding #%"
FMT_OFF_T, conn->connection_id);
- Curl_cshutdn_terminate(data, conn, FALSE);
+ Curl_conn_terminate(admin, conn, FALSE);
return;
}
}
Curl_llist_append(&cshutdn->list, conn, &conn->cshutdn_node);
- CURL_TRC_M(data, "[SHUTDOWN] added #%" FMT_OFF_T
+ CURL_TRC_M(admin, "[SHUTDOWN] added #%" FMT_OFF_T
" to shutdowns, now %zu conns in shutdown",
conn->connection_id, Curl_llist_count(&cshutdn->list));
}
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx)
{
- cshutdn_perform(cshutdn, data, sigpipe_ctx);
+ cshutdn_perform(cshutdn, sigpipe_ctx);
}
/* return fd_set info about the shutdown connections */
void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
- struct Curl_easy *data,
fd_set *read_fd_set, fd_set *write_fd_set,
int *maxfd)
{
if(Curl_llist_head(&cshutdn->list)) {
+ struct Curl_easy *admin = cshutdn->multi->admin;
struct Curl_llist_node *e;
struct easy_pollset ps;
@@ -447,9 +441,9 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
CURLcode result;
Curl_pollset_reset(&ps);
- Curl_attach_connection(data, conn);
- result = Curl_conn_adjust_pollset(data, conn, &ps);
- Curl_detach_connection(data);
+ Curl_attach_connection(admin, conn, FALSE);
+ result = Curl_conn_adjust_pollset(admin, conn, &ps);
+ Curl_detach_connection(admin);
if(result)
continue;
@@ -473,13 +467,13 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
/* return information about the shutdown connections */
unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct Curl_waitfds *cwfds)
{
unsigned int need = 0;
if(Curl_llist_head(&cshutdn->list)) {
struct Curl_llist_node *e;
+ struct Curl_easy *admin = cshutdn->multi->admin;
struct easy_pollset ps;
struct connectdata *conn;
CURLcode result;
@@ -488,9 +482,9 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
Curl_pollset_reset(&ps);
- Curl_attach_connection(data, conn);
- result = Curl_conn_adjust_pollset(data, conn, &ps);
- Curl_detach_connection(data);
+ Curl_attach_connection(admin, conn, FALSE);
+ result = Curl_conn_adjust_pollset(admin, conn, &ps);
+ Curl_detach_connection(admin);
if(!result)
need += Curl_waitfds_add_ps(cwfds, &ps);
@@ -501,7 +495,6 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
}
CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct curl_pollfds *cpfds)
{
CURLcode result = CURLE_OK;
@@ -509,15 +502,16 @@ CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
if(Curl_llist_head(&cshutdn->list)) {
struct Curl_llist_node *e;
struct easy_pollset ps;
+ struct Curl_easy *admin = cshutdn->multi->admin;
struct connectdata *conn;
Curl_pollset_init(&ps);
for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
Curl_pollset_reset(&ps);
- Curl_attach_connection(data, conn);
- result = Curl_conn_adjust_pollset(data, conn, &ps);
- Curl_detach_connection(data);
+ Curl_attach_connection(admin, conn, FALSE);
+ result = Curl_conn_adjust_pollset(admin, conn, &ps);
+ Curl_detach_connection(admin);
if(!result)
result = Curl_pollfds_add_ps(cpfds, &ps);
lib/cshutdn.h+14 -15
@@ -33,20 +33,20 @@ struct Curl_share;
struct Curl_sigpipe_ctx;
/* Run the shutdown of the connection once.
- * Shortly attach/detach `data` to `conn` while doing so.
+ * 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_cshutdn_run_once(struct Curl_easy *data,
- struct connectdata *conn,
- bool *done);
+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_cshutdn_terminate(struct Curl_easy *data,
- struct connectdata *conn,
- bool do_shutdown);
+void Curl_conn_terminate(struct Curl_easy *admin,
+ struct connectdata *conn,
+ bool do_shutdown);
/* A `cshutdown` is always owned by a multi handle to maintain
* the connections to be shut down. It registers timers and
@@ -57,25 +57,28 @@ struct cshutdn {
BIT(initialized);
};
+/* Get the cshutdn instance relevant for `data` or NULL if there is none */
+struct cshutdn *Curl_cshutdn_get(struct Curl_easy *data);
+
/* Init as part of the given multi handle. */
int Curl_cshutdn_init(struct cshutdn *cshutdn,
struct Curl_multi *multi);
/* Terminate all remaining connections and free resources. */
void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
- struct Curl_easy *data);
+ struct Curl_easy *admin);
/* Number of connections being shut down. */
-size_t Curl_cshutdn_count(struct Curl_easy *data);
+size_t Curl_cshutdn_count(struct cshutdn *cshutdn);
/* Number of connections to the destination being shut down. */
-size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
+size_t Curl_cshutdn_dest_count(struct cshutdn *cshutdn,
const char *destination);
/* Close the oldest connection in shutdown to destination or,
* when destination is NULL for any destination.
* Return TRUE if a connection has been closed. */
-bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
+bool Curl_cshutdn_close_oldest(struct cshutdn *cshutdn,
const char *destination);
/* Add a connection to have it shut down. Terminate the oldest
@@ -86,21 +89,17 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn,
/* Add sockets and POLLIN/OUT flags for connections being shut down. */
CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct curl_pollfds *cpfds);
unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct Curl_waitfds *cwfds);
void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
- struct Curl_easy *data,
fd_set *read_fd_set, fd_set *write_fd_set,
int *maxfd);
/* Run maintenance on all connections. */
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
- struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx);
#endif /* HEADER_CURL_CSHUTDN_H */
lib/curl_share.c+19 -8
@@ -38,7 +38,7 @@ static void share_destroy(struct Curl_share *share)
return;
if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
- Curl_cpool_destroy(&share->cpool);
+ Curl_cpool_destroy(&share->cpool, share->admin);
}
Curl_dnscache_destroy(&share->dnscache);
@@ -264,7 +264,7 @@ CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
case CURL_LOCK_DATA_CONNECT:
/* It is safe to set this option several times on a share. */
if(!share->cpool.initialized) {
- Curl_cpool_init(&share->cpool, share->admin, share, 103);
+ Curl_cpool_init(&share->cpool, share, 103);
}
break;
@@ -371,11 +371,11 @@ CURLSHcode curl_share_cleanup(CURLSH *sh)
return CURLSHE_OK;
}
-CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
- curl_lock_access accesstype)
+CURLSHcode Curl_share_lock_share(struct Curl_share *share,
+ struct Curl_easy *data,
+ curl_lock_data type,
+ curl_lock_access accesstype)
{
- struct Curl_share *share = data->share;
-
if(!share)
return CURLSHE_INVALID;
@@ -388,10 +388,16 @@ CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
return CURLSHE_OK;
}
-CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
+CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
+ curl_lock_access accesstype)
{
- struct Curl_share *share = data->share;
+ return Curl_share_lock_share(data->share, data, type, accesstype);
+}
+CURLSHcode Curl_share_unlock_share(struct Curl_share *share,
+ struct Curl_easy *data,
+ curl_lock_data type)
+{
if(!share)
return CURLSHE_INVALID;
@@ -403,6 +409,11 @@ CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
return CURLSHE_OK;
}
+CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
+{
+ return Curl_share_unlock_share(data->share, data, type);
+}
+
CURLcode Curl_share_easy_unlink(struct Curl_easy *data)
{
struct Curl_share *share = data->share;
lib/curl_share.h+8 -0
@@ -80,6 +80,14 @@ CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
curl_lock_access accesstype);
CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type);
+CURLSHcode Curl_share_lock_share(struct Curl_share *share,
+ struct Curl_easy *data,
+ curl_lock_data type,
+ curl_lock_access accesstype);
+CURLSHcode Curl_share_unlock_share(struct Curl_share *share,
+ struct Curl_easy *data,
+ curl_lock_data type);
+
/* convenience macro to check if this handle is using a shared SSL spool */
#define CURL_SHARE_ssl_scache(data) \
((data)->share && \
lib/curl_trc.c+1 -1
@@ -92,7 +92,7 @@ static struct curl_trc_feat Curl_trc_feat_ids = {
static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
{
- curl_off_t cid = data->state.recent_conn_id;
+ curl_off_t cid = data->state.lastconnect_id;
if(data->id >= 0) {
if(cid >= 0)
return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
lib/easy.c+5 -6
@@ -760,7 +760,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
if(data->conn) {
struct connectdata *conn = data->conn;
Curl_detach_connection(data);
- Curl_conn_terminate(data, conn, TRUE);
+ Curl_conn_close(data, conn, TRUE);
DEBUGASSERT(!data->conn);
}
@@ -996,7 +996,6 @@ CURL *curl_easy_duphandle(CURL *curl)
/* the connection pool is setup on demand */
outcurl->state.lastconnect_id = -1;
- outcurl->state.recent_conn_id = -1;
outcurl->id = -1;
outcurl->mid = UINT32_MAX;
outcurl->master_mid = UINT32_MAX;
@@ -1130,7 +1129,7 @@ void curl_easy_reset(CURL *curl)
data->progress.hide = TRUE;
data->state.current_speed = -1; /* init to negative == impossible */
- data->state.recent_conn_id = -1; /* clear remembered connection id */
+ data->state.lastconnect_id = -1; /* clear remembered connection id */
/* zero out authentication data: */
memset(&data->state.authhost, 0, sizeof(struct auth));
@@ -1259,7 +1258,7 @@ CURLcode Curl_easy_recv(struct Curl_easy *data,
if(!data->conn)
/* on first invoke, the transfer has been detached from the connection and
needs to be reattached */
- Curl_attach_connection(data, c);
+ Curl_attach_connection(data, c, TRUE);
*n = 0;
return Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, n);
@@ -1290,7 +1289,7 @@ CURLcode Curl_connect_only_attach(struct Curl_easy *data)
if(!data->conn)
/* on first invoke, the transfer has been detached from the connection and
needs to be reattached */
- Curl_attach_connection(data, c);
+ Curl_attach_connection(data, c, TRUE);
return CURLE_OK;
}
@@ -1316,7 +1315,7 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
if(!data->conn)
/* on first invoke, the transfer has been detached from the connection and
needs to be reattached */
- Curl_attach_connection(data, c);
+ Curl_attach_connection(data, c, TRUE);
sigpipe_ignore(data, &sigpipe_ctx);
result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
lib/getinfo.c+1 -2
@@ -463,8 +463,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
*param_offt = data->id;
break;
case CURLINFO_CONN_ID:
- *param_offt = data->conn ?
- data->conn->connection_id : data->state.recent_conn_id;
+ *param_offt = data->state.lastconnect_id;
break;
case CURLINFO_EARLYDATA_SENT_T:
*param_offt = data->progress.earlydata_sent;
lib/multi.c+34 -24
@@ -285,7 +285,7 @@ struct Curl_multi *Curl_multi_handle(uint32_t xfer_table_size,
if(Curl_cshutdn_init(&multi->cshutdn, multi))
goto error;
- Curl_cpool_init(&multi->cpool, multi->admin, NULL, chashsize);
+ Curl_cpool_init(&multi->cpool, NULL, chashsize);
#ifdef USE_SSL
if(Curl_ssl_scache_create(sesssize, 2, &multi->ssl_scache))
@@ -334,7 +334,7 @@ error:
Curl_multi_ev_cleanup(multi);
Curl_hash_destroy(&multi->proto_hash);
Curl_dnscache_destroy(&multi->dnscache);
- Curl_cpool_destroy(&multi->cpool);
+ Curl_cpool_destroy(&multi->cpool, multi->admin);
Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
#ifdef USE_SSL
Curl_ssl_scache_destroy(multi->ssl_scache);
@@ -654,20 +654,19 @@ static void multi_done_locked(struct connectdata *conn,
data->set.reuse_forbid, conn->bits.close, mdctx->premature,
Curl_conn_is_multiplex(conn, FIRSTSOCKET));
connclose(conn);
- Curl_conn_terminate(data, conn, (bool)mdctx->premature);
+ Curl_conn_close(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);
- Curl_conn_terminate(data, conn, (bool)mdctx->premature);
+ Curl_conn_close(data, conn, (bool)mdctx->premature);
}
else {
/* the connection is no longer in use by any transfer */
if(Curl_cpool_conn_now_idle(data, conn)) {
/* connection kept in the cpool */
- data->state.lastconnect_id = conn->connection_id;
infof(data, "Connection #%" FMT_OFF_T " to host %s left intact",
conn->connection_id, conn->destination);
}
@@ -845,7 +844,7 @@ CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
struct connectdata *conn;
(void)Curl_getconnectinfo(data, &conn);
if(conn)
- Curl_conn_terminate(data, conn, TRUE);
+ Curl_conn_close(data, conn, TRUE);
}
}
@@ -943,17 +942,23 @@ void Curl_detach_connection(struct Curl_easy *data)
/*
* Curl_attach_connection() attaches this transfer to this connection.
*
- * This is the only function that should assign data->conn
+ * This is the only function that should assign data->conn.
+ * `matched == TRUE` means the transfer's properties match this
+ * connection and it is not a temporary attach for maintenance.
*/
void Curl_attach_connection(struct Curl_easy *data,
- struct connectdata *conn)
+ struct connectdata *conn,
+ bool matched)
{
DEBUGASSERT(data);
DEBUGASSERT(!data->conn);
DEBUGASSERT(conn);
DEBUGASSERT(conn->attached_xfers < UINT32_MAX);
data->conn = conn;
- data->state.recent_conn_id = conn->connection_id;
+ if(matched)
+ data->state.lastconnect_id = conn->connection_id;
+ else
+ DEBUGASSERT(!data->mid); /* admin handle */
conn->attached_xfers++;
/* all attached transfers must be from the same multi */
if(!conn->attached_multi)
@@ -1288,8 +1293,8 @@ CURLMcode curl_multi_fdset(CURLM *m,
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
}
- Curl_cshutdn_setfds(&multi->cshutdn, multi->admin,
- read_fd_set, write_fd_set, &this_max_fd);
+ Curl_cshutdn_setfds(&multi->cshutdn, read_fd_set, write_fd_set,
+ &this_max_fd);
*max_fd = this_max_fd;
Curl_pollset_cleanup(&ps);
@@ -1337,7 +1342,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
}
- need += Curl_cshutdn_add_waitfds(&multi->cshutdn, multi->admin, &cwfds);
+ need += Curl_cshutdn_add_waitfds(&multi->cshutdn, &cwfds);
if(need != cwfds.n && ufds)
mresult = CURLM_OUT_OF_MEMORY;
@@ -1575,7 +1580,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
}
- if(Curl_cshutdn_add_pollfds(&multi->cshutdn, multi->admin, &cpfds)) {
+ if(Curl_cshutdn_add_pollfds(&multi->cshutdn, &cpfds)) {
mresult = CURLM_OUT_OF_MEMORY;
goto out;
}
@@ -1774,7 +1779,7 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* take this handle to the perform state right away */
multistate(data, MSTATE_PERFORMING);
- Curl_attach_connection(data, conn);
+ Curl_attach_connection(data, conn, TRUE);
CURL_REQ_SET_RECV(data);
}
return mresult;
@@ -2391,7 +2396,7 @@ static CURLcode is_finished(struct Curl_multi *multi,
We do not have to do this in every case block above where a
failure is detected */
Curl_detach_connection(data);
- Curl_conn_terminate(data, conn, dead_connection);
+ Curl_conn_close(data, conn, dead_connection);
}
}
else if(data->mstate == MSTATE_CONNECT) {
@@ -2711,7 +2716,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct Curl_easy *data,
struct Curl_sigpipe_ctx *sigpipe_ctx)
{
- CURLMcode mresult;
+ CURLMcode mresult = CURLM_OK;
CURLcode result = CURLE_OK;
if(multi->dead) {
@@ -2738,8 +2743,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifdef USE_RESOLV_THREADED
Curl_async_thrdd_multi_process(multi);
#endif
- Curl_cshutdn_perform(&multi->cshutdn, multi->admin, sigpipe_ctx);
- return CURLM_OK;
+ Curl_cshutdn_perform(&multi->cshutdn, sigpipe_ctx);
+ goto out;
}
sigpipe_apply(data, sigpipe_ctx);
@@ -2758,8 +2763,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->mstate < MSTATE_COMPLETED) {
/* Make sure we set the connection's current owner */
DEBUGASSERT(data->conn);
- if(!data->conn)
- return CURLM_INTERNAL_ERROR;
+ if(!data->conn) {
+ mresult = CURLM_INTERNAL_ERROR;
+ goto out;
+ }
}
/* Wait for the connect state as only then is the start time stored, but
@@ -2841,7 +2848,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
default:
- return CURLM_INTERNAL_ERROR;
+ mresult = CURLM_INTERNAL_ERROR;
+ goto out;
}
if(data->mstate >= MSTATE_CONNECT &&
@@ -2865,11 +2873,13 @@ statemachine_end:
if(MSTATE_COMPLETED == data->mstate) {
handle_completed(multi, data, result);
- return CURLM_OK;
+ mresult = CURLM_OK;
+ goto out;
}
} while((mresult == CURLM_CALL_MULTI_PERFORM) ||
multi_ischanged(multi, FALSE));
+out:
data->result = result;
return mresult;
}
@@ -3014,7 +3024,7 @@ CURLMcode curl_multi_cleanup(CURLM *m)
#ifdef USE_RESOLV_THREADED
Curl_async_thrdd_multi_destroy(multi, !multi->quick_exit);
#endif
- Curl_cpool_destroy(&multi->cpool);
+ Curl_cpool_destroy(&multi->cpool, multi->admin);
Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
if(multi->admin) {
CURL_TRC_M(multi->admin, "multi_cleanup, closing admin handle, done");
@@ -3393,7 +3403,7 @@ CURLMcode curl_multi_setopt(CURLM *m, CURLMoption option, ...)
Curl_dnscache_clear(multi->admin);
}
if(val & CURLMNWC_CLEAR_CONNS) {
- Curl_cpool_nw_changed(multi->admin);
+ Curl_cpool_nw_changed(&multi->cpool, multi->admin);
}
break;
}
lib/multiif.h+2 -1
@@ -34,7 +34,8 @@ void Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
void Curl_attach_connection(struct Curl_easy *data,
- struct connectdata *conn);
+ struct connectdata *conn,
+ bool matched);
void Curl_detach_connection(struct Curl_easy *data);
bool Curl_multiplex_wanted(const struct Curl_multi *multi);
CURLcode Curl_preconnect(struct Curl_easy *data);
lib/url.c+35 -9
@@ -471,7 +471,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
/* most recent connection is not yet defined */
data->state.lastconnect_id = -1;
- data->state.recent_conn_id = -1;
/* and not assigned an id yet */
data->id = -1;
data->mid = UINT32_MAX;
@@ -914,7 +913,7 @@ static bool url_allow_sspi_empty_creds(struct Curl_creds *conn_creds,
* To avoid TOCTOU attacks, do not reuse on empty credentials
* UNLESS this connection is the one used by this transfer before. */
if(!Curl_creds_has_user(conn_creds) &&
- (data->state.recent_conn_id != conn->connection_id))
+ (data->state.lastconnect_id != conn->connection_id))
return FALSE;
#else
(void)conn_creds;
@@ -1113,7 +1112,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
!Curl_cpool_conn_seems_healthy(conn, m->data, &m->now)) {
infof(m->data, "Connection %" FMT_OFF_T " seems to be dead, terminating",
conn->connection_id);
- Curl_conn_terminate(m->data, conn, FALSE);
+ Curl_conn_close(m->data, conn, FALSE);
return FALSE;
}
@@ -1128,7 +1127,7 @@ static bool url_match_result(void *userdata)
if(match->found) {
/* Attach it now while still under lock, so the connection does
* no longer appear idle and can be reaped. */
- Curl_attach_connection(match->data, match->found);
+ Curl_attach_connection(match->data, match->found, TRUE);
return TRUE;
}
else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
@@ -1159,11 +1158,11 @@ static bool url_attach_existing(struct Curl_easy *data,
struct connectdata *needle,
bool *waitpipe)
{
+ struct cpool *cpool = Curl_cpool_get_instance(data);
struct url_conn_match match;
bool success;
DEBUGASSERT(!data->conn);
- Curl_cpool_prune_dead(data);
memset(&match, 0, sizeof(match));
match.data = data;
@@ -1171,6 +1170,8 @@ static bool url_attach_existing(struct Curl_easy *data,
match.now = *Curl_pgrs_now(data);
match.may_multiplex = xfer_may_multiplex(data, needle);
+ Curl_cpool_prune_dead(cpool, data);
+
#ifdef USE_NTLM
match.want_ntlm_http =
(data->state.authhost.want & CURLAUTH_NTLM) &&
@@ -2303,9 +2304,9 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data)
goto out;
/* Setup a "faked" transfer that will do nothing */
- Curl_attach_connection(data, needle);
+ result = Curl_cpool_add(data, needle);
+ Curl_attach_connection(data, needle, TRUE);
needle = NULL;
- result = Curl_cpool_add(data, data->conn);
if(!result) {
/* Setup whatever necessary for a resumed transfer */
result = setup_range(data);
@@ -2411,7 +2412,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);
- Curl_attach_connection(data, needle);
+ Curl_attach_connection(data, needle, TRUE);
needle = NULL;
if(result)
goto out;
@@ -2523,7 +2524,7 @@ out:
/* We are not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
Curl_detach_connection(data);
- Curl_conn_terminate(data, conn, TRUE);
+ Curl_conn_close(data, conn, TRUE);
}
return result;
@@ -2595,6 +2596,31 @@ void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
}
+struct Curl_easy *Curl_get_admin(struct Curl_easy *data)
+{
+ struct Curl_easy *admin;
+
+ if(!data->mid) /* already an admin handle */
+ admin = data;
+ else if(data->multi)
+ admin = data->multi->admin;
+ else if(data->multi_easy)
+ admin = data->multi_easy->admin;
+ else {
+ DEBUGASSERT(0); /* we do not want this. does it happen? */
+ admin = data;
+ }
+ if(admin != data) {
+ admin->set.conn_max_idle_ms = data->set.conn_max_idle_ms;
+ admin->set.conn_max_age_ms = data->set.conn_max_age_ms;
+ admin->set.upkeep_interval_ms = data->set.upkeep_interval_ms;
+ admin->set.timeout = data->set.timeout;
+ admin->set.server_response_timeout = data->set.server_response_timeout;
+ admin->set.no_signal = data->set.no_signal;
+ }
+ return admin;
+}
+
CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
{
if(r1 && (r1 != CURLE_AGAIN))
lib/url.h+6 -0
@@ -67,6 +67,12 @@ CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
void Curl_conn_meta_remove(struct connectdata *conn, const char *key);
void *Curl_conn_meta_get(struct connectdata *conn, const char *key);
+/* Get an admin handle for internal operations from the given
+ * easy handle, if possible. The admin handle inherits certain
+ * properties from `data`. If no admin handle is available (not multi
+ * or share attached), the easy handle itself is returned. */
+struct Curl_easy *Curl_get_admin(struct Curl_easy *data);
+
#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
specified */
lib/urldata.h+1 -3
@@ -540,9 +540,7 @@ struct UrlState {
/* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */
- curl_off_t lastconnect_id; /* The last connection, -1 if undefined */
- curl_off_t recent_conn_id; /* The most recent connection used, might no
- * longer exist */
+ curl_off_t lastconnect_id; /* The last assigned connection or -1 */
struct dynbuf headerb; /* buffer to store headers in */
#ifndef CURL_DISABLE_HSTS
struct curl_slist *hstslist; /* list of HSTS files set by
tests/data/test1554+2 -0
@@ -63,6 +63,8 @@ run 1: foobar and so on fun!
[- Mutex unlock SHARE
-] Mutex lock SHARE
[- Mutex unlock SHARE
+-] Mutex lock CONNECT
+[- Mutex unlock CONNECT
</datacheck>
</reply>