1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Linus Nielsen Feltzing, <[email protected]>
9*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
10*6236dae4SAndroid Build Coastguard Worker *
11*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
12*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
13*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
14*6236dae4SAndroid Build Coastguard Worker *
15*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
17*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
18*6236dae4SAndroid Build Coastguard Worker *
19*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
21*6236dae4SAndroid Build Coastguard Worker *
22*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
23*6236dae4SAndroid Build Coastguard Worker *
24*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
27*6236dae4SAndroid Build Coastguard Worker
28*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
29*6236dae4SAndroid Build Coastguard Worker
30*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
31*6236dae4SAndroid Build Coastguard Worker #include "url.h"
32*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
33*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
34*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
35*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
36*6236dae4SAndroid Build Coastguard Worker #include "conncache.h"
37*6236dae4SAndroid Build Coastguard Worker #include "http_negotiate.h"
38*6236dae4SAndroid Build Coastguard Worker #include "http_ntlm.h"
39*6236dae4SAndroid Build Coastguard Worker #include "share.h"
40*6236dae4SAndroid Build Coastguard Worker #include "sigpipe.h"
41*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
42*6236dae4SAndroid Build Coastguard Worker #include "select.h"
43*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
44*6236dae4SAndroid Build Coastguard Worker
45*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
46*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
47*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
48*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
49*6236dae4SAndroid Build Coastguard Worker
50*6236dae4SAndroid Build Coastguard Worker
51*6236dae4SAndroid Build Coastguard Worker #define CPOOL_IS_LOCKED(c) ((c) && (c)->locked)
52*6236dae4SAndroid Build Coastguard Worker
53*6236dae4SAndroid Build Coastguard Worker #define CPOOL_LOCK(c) \
54*6236dae4SAndroid Build Coastguard Worker do { \
55*6236dae4SAndroid Build Coastguard Worker if((c)) { \
56*6236dae4SAndroid Build Coastguard Worker if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
57*6236dae4SAndroid Build Coastguard Worker Curl_share_lock(((c)->idata), CURL_LOCK_DATA_CONNECT, \
58*6236dae4SAndroid Build Coastguard Worker CURL_LOCK_ACCESS_SINGLE); \
59*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!(c)->locked); \
60*6236dae4SAndroid Build Coastguard Worker (c)->locked = TRUE; \
61*6236dae4SAndroid Build Coastguard Worker } \
62*6236dae4SAndroid Build Coastguard Worker } while(0)
63*6236dae4SAndroid Build Coastguard Worker
64*6236dae4SAndroid Build Coastguard Worker #define CPOOL_UNLOCK(c) \
65*6236dae4SAndroid Build Coastguard Worker do { \
66*6236dae4SAndroid Build Coastguard Worker if((c)) { \
67*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT((c)->locked); \
68*6236dae4SAndroid Build Coastguard Worker (c)->locked = FALSE; \
69*6236dae4SAndroid Build Coastguard Worker if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
70*6236dae4SAndroid Build Coastguard Worker Curl_share_unlock((c)->idata, CURL_LOCK_DATA_CONNECT); \
71*6236dae4SAndroid Build Coastguard Worker } \
72*6236dae4SAndroid Build Coastguard Worker } while(0)
73*6236dae4SAndroid Build Coastguard Worker
74*6236dae4SAndroid Build Coastguard Worker
75*6236dae4SAndroid Build Coastguard Worker /* A list of connections to the same destination. */
76*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle {
77*6236dae4SAndroid Build Coastguard Worker struct Curl_llist conns; /* connections in the bundle */
78*6236dae4SAndroid Build Coastguard Worker size_t dest_len; /* total length of destination, including NUL */
79*6236dae4SAndroid Build Coastguard Worker char *dest[1]; /* destination of bundle, allocated to keep dest_len bytes */
80*6236dae4SAndroid Build Coastguard Worker };
81*6236dae4SAndroid Build Coastguard Worker
82*6236dae4SAndroid Build Coastguard Worker
83*6236dae4SAndroid Build Coastguard Worker static void cpool_discard_conn(struct cpool *cpool,
84*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
85*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
86*6236dae4SAndroid Build Coastguard Worker bool aborted);
87*6236dae4SAndroid Build Coastguard Worker static void cpool_close_and_destroy(struct cpool *cpool,
88*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
89*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
90*6236dae4SAndroid Build Coastguard Worker bool do_shutdown);
91*6236dae4SAndroid Build Coastguard Worker static void cpool_run_conn_shutdown(struct Curl_easy *data,
92*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
93*6236dae4SAndroid Build Coastguard Worker bool *done);
94*6236dae4SAndroid Build Coastguard Worker static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
95*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn);
96*6236dae4SAndroid Build Coastguard Worker static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
97*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
98*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn);
99*6236dae4SAndroid Build Coastguard Worker static void cpool_shutdown_all(struct cpool *cpool,
100*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data, int timeout_ms);
101*6236dae4SAndroid Build Coastguard Worker static void cpool_close_and_destroy_all(struct cpool *cpool);
102*6236dae4SAndroid Build Coastguard Worker static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool);
103*6236dae4SAndroid Build Coastguard Worker
cpool_bundle_create(const char * dest,size_t dest_len)104*6236dae4SAndroid Build Coastguard Worker static struct cpool_bundle *cpool_bundle_create(const char *dest,
105*6236dae4SAndroid Build Coastguard Worker size_t dest_len)
106*6236dae4SAndroid Build Coastguard Worker {
107*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
108*6236dae4SAndroid Build Coastguard Worker bundle = calloc(1, sizeof(*bundle) + dest_len);
109*6236dae4SAndroid Build Coastguard Worker if(!bundle)
110*6236dae4SAndroid Build Coastguard Worker return NULL;
111*6236dae4SAndroid Build Coastguard Worker Curl_llist_init(&bundle->conns, NULL);
112*6236dae4SAndroid Build Coastguard Worker bundle->dest_len = dest_len;
113*6236dae4SAndroid Build Coastguard Worker memcpy(bundle->dest, dest, dest_len);
114*6236dae4SAndroid Build Coastguard Worker return bundle;
115*6236dae4SAndroid Build Coastguard Worker }
116*6236dae4SAndroid Build Coastguard Worker
cpool_bundle_destroy(struct cpool_bundle * bundle)117*6236dae4SAndroid Build Coastguard Worker static void cpool_bundle_destroy(struct cpool_bundle *bundle)
118*6236dae4SAndroid Build Coastguard Worker {
119*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!Curl_llist_count(&bundle->conns));
120*6236dae4SAndroid Build Coastguard Worker free(bundle);
121*6236dae4SAndroid Build Coastguard Worker }
122*6236dae4SAndroid Build Coastguard Worker
123*6236dae4SAndroid Build Coastguard Worker /* Add a connection to a bundle */
cpool_bundle_add(struct cpool_bundle * bundle,struct connectdata * conn)124*6236dae4SAndroid Build Coastguard Worker static void cpool_bundle_add(struct cpool_bundle *bundle,
125*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
126*6236dae4SAndroid Build Coastguard Worker {
127*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!Curl_node_llist(&conn->cpool_node));
128*6236dae4SAndroid Build Coastguard Worker Curl_llist_append(&bundle->conns, conn, &conn->cpool_node);
129*6236dae4SAndroid Build Coastguard Worker conn->bits.in_cpool = TRUE;
130*6236dae4SAndroid Build Coastguard Worker }
131*6236dae4SAndroid Build Coastguard Worker
132*6236dae4SAndroid Build Coastguard Worker /* Remove a connection from a bundle */
cpool_bundle_remove(struct cpool_bundle * bundle,struct connectdata * conn)133*6236dae4SAndroid Build Coastguard Worker static void cpool_bundle_remove(struct cpool_bundle *bundle,
134*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
135*6236dae4SAndroid Build Coastguard Worker {
136*6236dae4SAndroid Build Coastguard Worker (void)bundle;
137*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(Curl_node_llist(&conn->cpool_node) == &bundle->conns);
138*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(&conn->cpool_node);
139*6236dae4SAndroid Build Coastguard Worker conn->bits.in_cpool = FALSE;
140*6236dae4SAndroid Build Coastguard Worker }
141*6236dae4SAndroid Build Coastguard Worker
cpool_bundle_free_entry(void * freethis)142*6236dae4SAndroid Build Coastguard Worker static void cpool_bundle_free_entry(void *freethis)
143*6236dae4SAndroid Build Coastguard Worker {
144*6236dae4SAndroid Build Coastguard Worker cpool_bundle_destroy((struct cpool_bundle *)freethis);
145*6236dae4SAndroid Build Coastguard Worker }
146*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_init(struct cpool * cpool,Curl_cpool_disconnect_cb * disconnect_cb,struct Curl_multi * multi,struct Curl_share * share,size_t size)147*6236dae4SAndroid Build Coastguard Worker int Curl_cpool_init(struct cpool *cpool,
148*6236dae4SAndroid Build Coastguard Worker Curl_cpool_disconnect_cb *disconnect_cb,
149*6236dae4SAndroid Build Coastguard Worker struct Curl_multi *multi,
150*6236dae4SAndroid Build Coastguard Worker struct Curl_share *share,
151*6236dae4SAndroid Build Coastguard Worker size_t size)
152*6236dae4SAndroid Build Coastguard Worker {
153*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!!multi != !!share); /* either one */
154*6236dae4SAndroid Build Coastguard Worker Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
155*6236dae4SAndroid Build Coastguard Worker Curl_str_key_compare, cpool_bundle_free_entry);
156*6236dae4SAndroid Build Coastguard Worker Curl_llist_init(&cpool->shutdowns, NULL);
157*6236dae4SAndroid Build Coastguard Worker
158*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(disconnect_cb);
159*6236dae4SAndroid Build Coastguard Worker if(!disconnect_cb)
160*6236dae4SAndroid Build Coastguard Worker return 1;
161*6236dae4SAndroid Build Coastguard Worker
162*6236dae4SAndroid Build Coastguard Worker /* allocate a new easy handle to use when closing cached connections */
163*6236dae4SAndroid Build Coastguard Worker cpool->idata = curl_easy_init();
164*6236dae4SAndroid Build Coastguard Worker if(!cpool->idata)
165*6236dae4SAndroid Build Coastguard Worker return 1; /* bad */
166*6236dae4SAndroid Build Coastguard Worker cpool->idata->state.internal = TRUE;
167*6236dae4SAndroid Build Coastguard Worker /* TODO: this is quirky. We need an internal handle for certain
168*6236dae4SAndroid Build Coastguard Worker * operations, but we do not add it to the multi (if there is one).
169*6236dae4SAndroid Build Coastguard Worker * But we give it the multi so that socket event operations can work.
170*6236dae4SAndroid Build Coastguard Worker * Probably better to have an internal handle owned by the multi that
171*6236dae4SAndroid Build Coastguard Worker * can be used for cpool operations. */
172*6236dae4SAndroid Build Coastguard Worker cpool->idata->multi = multi;
173*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
174*6236dae4SAndroid Build Coastguard Worker if(getenv("CURL_DEBUG"))
175*6236dae4SAndroid Build Coastguard Worker cpool->idata->set.verbose = TRUE;
176*6236dae4SAndroid Build Coastguard Worker #endif
177*6236dae4SAndroid Build Coastguard Worker
178*6236dae4SAndroid Build Coastguard Worker cpool->disconnect_cb = disconnect_cb;
179*6236dae4SAndroid Build Coastguard Worker cpool->idata->multi = cpool->multi = multi;
180*6236dae4SAndroid Build Coastguard Worker cpool->idata->share = cpool->share = share;
181*6236dae4SAndroid Build Coastguard Worker
182*6236dae4SAndroid Build Coastguard Worker return 0; /* good */
183*6236dae4SAndroid Build Coastguard Worker }
184*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_destroy(struct cpool * cpool)185*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_destroy(struct cpool *cpool)
186*6236dae4SAndroid Build Coastguard Worker {
187*6236dae4SAndroid Build Coastguard Worker if(cpool) {
188*6236dae4SAndroid Build Coastguard Worker if(cpool->idata) {
189*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy_all(cpool);
190*6236dae4SAndroid Build Coastguard Worker /* The internal closure handle is special and we need to
191*6236dae4SAndroid Build Coastguard Worker * disconnect it from multi/share before closing it down. */
192*6236dae4SAndroid Build Coastguard Worker cpool->idata->multi = NULL;
193*6236dae4SAndroid Build Coastguard Worker cpool->idata->share = NULL;
194*6236dae4SAndroid Build Coastguard Worker Curl_close(&cpool->idata);
195*6236dae4SAndroid Build Coastguard Worker }
196*6236dae4SAndroid Build Coastguard Worker Curl_hash_destroy(&cpool->dest2bundle);
197*6236dae4SAndroid Build Coastguard Worker cpool->multi = NULL;
198*6236dae4SAndroid Build Coastguard Worker }
199*6236dae4SAndroid Build Coastguard Worker }
200*6236dae4SAndroid Build Coastguard Worker
cpool_get_instance(struct Curl_easy * data)201*6236dae4SAndroid Build Coastguard Worker static struct cpool *cpool_get_instance(struct Curl_easy *data)
202*6236dae4SAndroid Build Coastguard Worker {
203*6236dae4SAndroid Build Coastguard Worker if(data) {
204*6236dae4SAndroid Build Coastguard Worker if(CURL_SHARE_KEEP_CONNECT(data->share))
205*6236dae4SAndroid Build Coastguard Worker return &data->share->cpool;
206*6236dae4SAndroid Build Coastguard Worker else if(data->multi_easy)
207*6236dae4SAndroid Build Coastguard Worker return &data->multi_easy->cpool;
208*6236dae4SAndroid Build Coastguard Worker else if(data->multi)
209*6236dae4SAndroid Build Coastguard Worker return &data->multi->cpool;
210*6236dae4SAndroid Build Coastguard Worker }
211*6236dae4SAndroid Build Coastguard Worker return NULL;
212*6236dae4SAndroid Build Coastguard Worker }
213*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_xfer_init(struct Curl_easy * data)214*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_xfer_init(struct Curl_easy *data)
215*6236dae4SAndroid Build Coastguard Worker {
216*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
217*6236dae4SAndroid Build Coastguard Worker
218*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
219*6236dae4SAndroid Build Coastguard Worker if(cpool) {
220*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
221*6236dae4SAndroid Build Coastguard Worker /* the identifier inside the connection cache */
222*6236dae4SAndroid Build Coastguard Worker data->id = cpool->next_easy_id++;
223*6236dae4SAndroid Build Coastguard Worker if(cpool->next_easy_id <= 0)
224*6236dae4SAndroid Build Coastguard Worker cpool->next_easy_id = 0;
225*6236dae4SAndroid Build Coastguard Worker data->state.lastconnect_id = -1;
226*6236dae4SAndroid Build Coastguard Worker
227*6236dae4SAndroid Build Coastguard Worker /* The closure handle only ever has default timeouts set. To improve the
228*6236dae4SAndroid Build Coastguard Worker state somewhat we clone the timeouts from each added handle so that the
229*6236dae4SAndroid Build Coastguard Worker closure handle always has the same timeouts as the most recently added
230*6236dae4SAndroid Build Coastguard Worker easy handle. */
231*6236dae4SAndroid Build Coastguard Worker cpool->idata->set.timeout = data->set.timeout;
232*6236dae4SAndroid Build Coastguard Worker cpool->idata->set.server_response_timeout =
233*6236dae4SAndroid Build Coastguard Worker data->set.server_response_timeout;
234*6236dae4SAndroid Build Coastguard Worker cpool->idata->set.no_signal = data->set.no_signal;
235*6236dae4SAndroid Build Coastguard Worker
236*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
237*6236dae4SAndroid Build Coastguard Worker }
238*6236dae4SAndroid Build Coastguard Worker else {
239*6236dae4SAndroid Build Coastguard Worker /* We should not get here, but in a non-debug build, do something */
240*6236dae4SAndroid Build Coastguard Worker data->id = 0;
241*6236dae4SAndroid Build Coastguard Worker data->state.lastconnect_id = -1;
242*6236dae4SAndroid Build Coastguard Worker }
243*6236dae4SAndroid Build Coastguard Worker }
244*6236dae4SAndroid Build Coastguard Worker
cpool_find_bundle(struct cpool * cpool,struct connectdata * conn)245*6236dae4SAndroid Build Coastguard Worker static struct cpool_bundle *cpool_find_bundle(struct cpool *cpool,
246*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
247*6236dae4SAndroid Build Coastguard Worker {
248*6236dae4SAndroid Build Coastguard Worker return Curl_hash_pick(&cpool->dest2bundle,
249*6236dae4SAndroid Build Coastguard Worker conn->destination, conn->destination_len);
250*6236dae4SAndroid Build Coastguard Worker }
251*6236dae4SAndroid Build Coastguard Worker
252*6236dae4SAndroid Build Coastguard Worker static struct cpool_bundle *
cpool_add_bundle(struct cpool * cpool,struct connectdata * conn)253*6236dae4SAndroid Build Coastguard Worker cpool_add_bundle(struct cpool *cpool, struct connectdata *conn)
254*6236dae4SAndroid Build Coastguard Worker {
255*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
256*6236dae4SAndroid Build Coastguard Worker
257*6236dae4SAndroid Build Coastguard Worker bundle = cpool_bundle_create(conn->destination, conn->destination_len);
258*6236dae4SAndroid Build Coastguard Worker if(!bundle)
259*6236dae4SAndroid Build Coastguard Worker return NULL;
260*6236dae4SAndroid Build Coastguard Worker
261*6236dae4SAndroid Build Coastguard Worker if(!Curl_hash_add(&cpool->dest2bundle,
262*6236dae4SAndroid Build Coastguard Worker bundle->dest, bundle->dest_len, bundle)) {
263*6236dae4SAndroid Build Coastguard Worker cpool_bundle_destroy(bundle);
264*6236dae4SAndroid Build Coastguard Worker return NULL;
265*6236dae4SAndroid Build Coastguard Worker }
266*6236dae4SAndroid Build Coastguard Worker return bundle;
267*6236dae4SAndroid Build Coastguard Worker }
268*6236dae4SAndroid Build Coastguard Worker
cpool_remove_bundle(struct cpool * cpool,struct cpool_bundle * bundle)269*6236dae4SAndroid Build Coastguard Worker static void cpool_remove_bundle(struct cpool *cpool,
270*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle)
271*6236dae4SAndroid Build Coastguard Worker {
272*6236dae4SAndroid Build Coastguard Worker if(!cpool)
273*6236dae4SAndroid Build Coastguard Worker return;
274*6236dae4SAndroid Build Coastguard Worker
275*6236dae4SAndroid Build Coastguard Worker Curl_hash_delete(&cpool->dest2bundle, bundle->dest, bundle->dest_len);
276*6236dae4SAndroid Build Coastguard Worker }
277*6236dae4SAndroid Build Coastguard Worker
278*6236dae4SAndroid Build Coastguard Worker static struct connectdata *
279*6236dae4SAndroid Build Coastguard Worker cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle);
280*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_check_limits(struct Curl_easy * data,struct connectdata * conn)281*6236dae4SAndroid Build Coastguard Worker int Curl_cpool_check_limits(struct Curl_easy *data,
282*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
283*6236dae4SAndroid Build Coastguard Worker {
284*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
285*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
286*6236dae4SAndroid Build Coastguard Worker size_t dest_limit = 0;
287*6236dae4SAndroid Build Coastguard Worker size_t total_limit = 0;
288*6236dae4SAndroid Build Coastguard Worker int result = CPOOL_LIMIT_OK;
289*6236dae4SAndroid Build Coastguard Worker
290*6236dae4SAndroid Build Coastguard Worker if(!cpool)
291*6236dae4SAndroid Build Coastguard Worker return CPOOL_LIMIT_OK;
292*6236dae4SAndroid Build Coastguard Worker
293*6236dae4SAndroid Build Coastguard Worker if(data && data->multi) {
294*6236dae4SAndroid Build Coastguard Worker dest_limit = data->multi->max_host_connections;
295*6236dae4SAndroid Build Coastguard Worker total_limit = data->multi->max_total_connections;
296*6236dae4SAndroid Build Coastguard Worker }
297*6236dae4SAndroid Build Coastguard Worker
298*6236dae4SAndroid Build Coastguard Worker if(!dest_limit && !total_limit)
299*6236dae4SAndroid Build Coastguard Worker return CPOOL_LIMIT_OK;
300*6236dae4SAndroid Build Coastguard Worker
301*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
302*6236dae4SAndroid Build Coastguard Worker if(dest_limit) {
303*6236dae4SAndroid Build Coastguard Worker bundle = cpool_find_bundle(cpool, conn);
304*6236dae4SAndroid Build Coastguard Worker while(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
305*6236dae4SAndroid Build Coastguard Worker struct connectdata *oldest_idle = NULL;
306*6236dae4SAndroid Build Coastguard Worker /* The bundle is full. Extract the oldest connection that may
307*6236dae4SAndroid Build Coastguard Worker * be removed now, if there is one. */
308*6236dae4SAndroid Build Coastguard Worker oldest_idle = cpool_bundle_get_oldest_idle(bundle);
309*6236dae4SAndroid Build Coastguard Worker if(!oldest_idle)
310*6236dae4SAndroid Build Coastguard Worker break;
311*6236dae4SAndroid Build Coastguard Worker /* disconnect the old conn and continue */
312*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "Discarding connection #%"
313*6236dae4SAndroid Build Coastguard Worker FMT_OFF_T " from %zu to reach destination "
314*6236dae4SAndroid Build Coastguard Worker "limit of %zu", oldest_idle->connection_id,
315*6236dae4SAndroid Build Coastguard Worker Curl_llist_count(&bundle->conns), dest_limit));
316*6236dae4SAndroid Build Coastguard Worker Curl_cpool_disconnect(data, oldest_idle, FALSE);
317*6236dae4SAndroid Build Coastguard Worker
318*6236dae4SAndroid Build Coastguard Worker /* in case the bundle was destroyed in disconnect, look it up again */
319*6236dae4SAndroid Build Coastguard Worker bundle = cpool_find_bundle(cpool, conn);
320*6236dae4SAndroid Build Coastguard Worker }
321*6236dae4SAndroid Build Coastguard Worker if(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
322*6236dae4SAndroid Build Coastguard Worker result = CPOOL_LIMIT_DEST;
323*6236dae4SAndroid Build Coastguard Worker goto out;
324*6236dae4SAndroid Build Coastguard Worker }
325*6236dae4SAndroid Build Coastguard Worker }
326*6236dae4SAndroid Build Coastguard Worker
327*6236dae4SAndroid Build Coastguard Worker if(total_limit) {
328*6236dae4SAndroid Build Coastguard Worker while(cpool->num_conn >= total_limit) {
329*6236dae4SAndroid Build Coastguard Worker struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
330*6236dae4SAndroid Build Coastguard Worker if(!oldest_idle)
331*6236dae4SAndroid Build Coastguard Worker break;
332*6236dae4SAndroid Build Coastguard Worker /* disconnect the old conn and continue */
333*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "Discarding connection #%"
334*6236dae4SAndroid Build Coastguard Worker FMT_OFF_T " from %zu to reach total "
335*6236dae4SAndroid Build Coastguard Worker "limit of %zu",
336*6236dae4SAndroid Build Coastguard Worker oldest_idle->connection_id, cpool->num_conn, total_limit));
337*6236dae4SAndroid Build Coastguard Worker Curl_cpool_disconnect(data, oldest_idle, FALSE);
338*6236dae4SAndroid Build Coastguard Worker }
339*6236dae4SAndroid Build Coastguard Worker if(cpool->num_conn >= total_limit) {
340*6236dae4SAndroid Build Coastguard Worker result = CPOOL_LIMIT_TOTAL;
341*6236dae4SAndroid Build Coastguard Worker goto out;
342*6236dae4SAndroid Build Coastguard Worker }
343*6236dae4SAndroid Build Coastguard Worker }
344*6236dae4SAndroid Build Coastguard Worker
345*6236dae4SAndroid Build Coastguard Worker out:
346*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
347*6236dae4SAndroid Build Coastguard Worker return result;
348*6236dae4SAndroid Build Coastguard Worker }
349*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_add_conn(struct Curl_easy * data,struct connectdata * conn)350*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
351*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
352*6236dae4SAndroid Build Coastguard Worker {
353*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
354*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle = NULL;
355*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
356*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(conn);
357*6236dae4SAndroid Build Coastguard Worker
358*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
359*6236dae4SAndroid Build Coastguard Worker if(!cpool)
360*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
361*6236dae4SAndroid Build Coastguard Worker
362*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
363*6236dae4SAndroid Build Coastguard Worker bundle = cpool_find_bundle(cpool, conn);
364*6236dae4SAndroid Build Coastguard Worker if(!bundle) {
365*6236dae4SAndroid Build Coastguard Worker bundle = cpool_add_bundle(cpool, conn);
366*6236dae4SAndroid Build Coastguard Worker if(!bundle) {
367*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
368*6236dae4SAndroid Build Coastguard Worker goto out;
369*6236dae4SAndroid Build Coastguard Worker }
370*6236dae4SAndroid Build Coastguard Worker }
371*6236dae4SAndroid Build Coastguard Worker
372*6236dae4SAndroid Build Coastguard Worker cpool_bundle_add(bundle, conn);
373*6236dae4SAndroid Build Coastguard Worker conn->connection_id = cpool->next_connection_id++;
374*6236dae4SAndroid Build Coastguard Worker cpool->num_conn++;
375*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "Added connection %" FMT_OFF_T ". "
376*6236dae4SAndroid Build Coastguard Worker "The cache now contains %zu members",
377*6236dae4SAndroid Build Coastguard Worker conn->connection_id, cpool->num_conn));
378*6236dae4SAndroid Build Coastguard Worker out:
379*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
380*6236dae4SAndroid Build Coastguard Worker
381*6236dae4SAndroid Build Coastguard Worker return result;
382*6236dae4SAndroid Build Coastguard Worker }
383*6236dae4SAndroid Build Coastguard Worker
cpool_remove_conn(struct cpool * cpool,struct connectdata * conn)384*6236dae4SAndroid Build Coastguard Worker static void cpool_remove_conn(struct cpool *cpool,
385*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
386*6236dae4SAndroid Build Coastguard Worker {
387*6236dae4SAndroid Build Coastguard Worker struct Curl_llist *list = Curl_node_llist(&conn->cpool_node);
388*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
389*6236dae4SAndroid Build Coastguard Worker if(list) {
390*6236dae4SAndroid Build Coastguard Worker /* The connection is certainly in the pool, but where? */
391*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle = cpool_find_bundle(cpool, conn);
392*6236dae4SAndroid Build Coastguard Worker if(bundle && (list == &bundle->conns)) {
393*6236dae4SAndroid Build Coastguard Worker cpool_bundle_remove(bundle, conn);
394*6236dae4SAndroid Build Coastguard Worker if(!Curl_llist_count(&bundle->conns))
395*6236dae4SAndroid Build Coastguard Worker cpool_remove_bundle(cpool, bundle);
396*6236dae4SAndroid Build Coastguard Worker conn->bits.in_cpool = FALSE;
397*6236dae4SAndroid Build Coastguard Worker cpool->num_conn--;
398*6236dae4SAndroid Build Coastguard Worker }
399*6236dae4SAndroid Build Coastguard Worker else {
400*6236dae4SAndroid Build Coastguard Worker /* Not in a bundle, already in the shutdown list? */
401*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(list == &cpool->shutdowns);
402*6236dae4SAndroid Build Coastguard Worker }
403*6236dae4SAndroid Build Coastguard Worker }
404*6236dae4SAndroid Build Coastguard Worker }
405*6236dae4SAndroid Build Coastguard Worker
406*6236dae4SAndroid Build Coastguard Worker /* This function iterates the entire connection pool and calls the function
407*6236dae4SAndroid Build Coastguard Worker func() with the connection pointer as the first argument and the supplied
408*6236dae4SAndroid Build Coastguard Worker 'param' argument as the other.
409*6236dae4SAndroid Build Coastguard Worker
410*6236dae4SAndroid Build Coastguard Worker The cpool lock is still held when the callback is called. It needs it,
411*6236dae4SAndroid Build Coastguard Worker so that it can safely continue traversing the lists once the callback
412*6236dae4SAndroid Build Coastguard Worker returns.
413*6236dae4SAndroid Build Coastguard Worker
414*6236dae4SAndroid Build Coastguard Worker Returns TRUE if the loop was aborted due to the callback's return code.
415*6236dae4SAndroid Build Coastguard Worker
416*6236dae4SAndroid Build Coastguard Worker Return 0 from func() to continue the loop, return 1 to abort it.
417*6236dae4SAndroid Build Coastguard Worker */
cpool_foreach(struct Curl_easy * data,struct cpool * cpool,void * param,int (* func)(struct Curl_easy * data,struct connectdata * conn,void * param))418*6236dae4SAndroid Build Coastguard Worker static bool cpool_foreach(struct Curl_easy *data,
419*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool,
420*6236dae4SAndroid Build Coastguard Worker void *param,
421*6236dae4SAndroid Build Coastguard Worker int (*func)(struct Curl_easy *data,
422*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, void *param))
423*6236dae4SAndroid Build Coastguard Worker {
424*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_iterator iter;
425*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_element *he;
426*6236dae4SAndroid Build Coastguard Worker
427*6236dae4SAndroid Build Coastguard Worker if(!cpool)
428*6236dae4SAndroid Build Coastguard Worker return FALSE;
429*6236dae4SAndroid Build Coastguard Worker
430*6236dae4SAndroid Build Coastguard Worker Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
431*6236dae4SAndroid Build Coastguard Worker
432*6236dae4SAndroid Build Coastguard Worker he = Curl_hash_next_element(&iter);
433*6236dae4SAndroid Build Coastguard Worker while(he) {
434*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *curr;
435*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle = he->ptr;
436*6236dae4SAndroid Build Coastguard Worker he = Curl_hash_next_element(&iter);
437*6236dae4SAndroid Build Coastguard Worker
438*6236dae4SAndroid Build Coastguard Worker curr = Curl_llist_head(&bundle->conns);
439*6236dae4SAndroid Build Coastguard Worker while(curr) {
440*6236dae4SAndroid Build Coastguard Worker /* Yes, we need to update curr before calling func(), because func()
441*6236dae4SAndroid Build Coastguard Worker might decide to remove the connection */
442*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = Curl_node_elem(curr);
443*6236dae4SAndroid Build Coastguard Worker curr = Curl_node_next(curr);
444*6236dae4SAndroid Build Coastguard Worker
445*6236dae4SAndroid Build Coastguard Worker if(1 == func(data, conn, param)) {
446*6236dae4SAndroid Build Coastguard Worker return TRUE;
447*6236dae4SAndroid Build Coastguard Worker }
448*6236dae4SAndroid Build Coastguard Worker }
449*6236dae4SAndroid Build Coastguard Worker }
450*6236dae4SAndroid Build Coastguard Worker return FALSE;
451*6236dae4SAndroid Build Coastguard Worker }
452*6236dae4SAndroid Build Coastguard Worker
453*6236dae4SAndroid Build Coastguard Worker /* Return a live connection in the pool or NULL. */
cpool_get_live_conn(struct cpool * cpool)454*6236dae4SAndroid Build Coastguard Worker static struct connectdata *cpool_get_live_conn(struct cpool *cpool)
455*6236dae4SAndroid Build Coastguard Worker {
456*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_iterator iter;
457*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_element *he;
458*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
459*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *conn_node;
460*6236dae4SAndroid Build Coastguard Worker
461*6236dae4SAndroid Build Coastguard Worker Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
462*6236dae4SAndroid Build Coastguard Worker for(he = Curl_hash_next_element(&iter); he;
463*6236dae4SAndroid Build Coastguard Worker he = Curl_hash_next_element(&iter)) {
464*6236dae4SAndroid Build Coastguard Worker bundle = he->ptr;
465*6236dae4SAndroid Build Coastguard Worker conn_node = Curl_llist_head(&bundle->conns);
466*6236dae4SAndroid Build Coastguard Worker if(conn_node)
467*6236dae4SAndroid Build Coastguard Worker return Curl_node_elem(conn_node);
468*6236dae4SAndroid Build Coastguard Worker }
469*6236dae4SAndroid Build Coastguard Worker return NULL;
470*6236dae4SAndroid Build Coastguard Worker }
471*6236dae4SAndroid Build Coastguard Worker
472*6236dae4SAndroid Build Coastguard Worker /*
473*6236dae4SAndroid Build Coastguard Worker * A connection (already in the pool) has become idle. Do any
474*6236dae4SAndroid Build Coastguard Worker * cleanups in regard to the pool's limits.
475*6236dae4SAndroid Build Coastguard Worker *
476*6236dae4SAndroid Build Coastguard Worker * Return TRUE if idle connection kept in pool, FALSE if closed.
477*6236dae4SAndroid Build Coastguard Worker */
Curl_cpool_conn_now_idle(struct Curl_easy * data,struct connectdata * conn)478*6236dae4SAndroid Build Coastguard Worker bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
479*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
480*6236dae4SAndroid Build Coastguard Worker {
481*6236dae4SAndroid Build Coastguard Worker unsigned int maxconnects = !data->multi->maxconnects ?
482*6236dae4SAndroid Build Coastguard Worker data->multi->num_easy * 4 : data->multi->maxconnects;
483*6236dae4SAndroid Build Coastguard Worker struct connectdata *oldest_idle = NULL;
484*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
485*6236dae4SAndroid Build Coastguard Worker bool kept = TRUE;
486*6236dae4SAndroid Build Coastguard Worker
487*6236dae4SAndroid Build Coastguard Worker conn->lastused = Curl_now(); /* it was used up until now */
488*6236dae4SAndroid Build Coastguard Worker if(cpool && maxconnects) {
489*6236dae4SAndroid Build Coastguard Worker /* may be called form a callback already under lock */
490*6236dae4SAndroid Build Coastguard Worker bool do_lock = !CPOOL_IS_LOCKED(cpool);
491*6236dae4SAndroid Build Coastguard Worker if(do_lock)
492*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
493*6236dae4SAndroid Build Coastguard Worker if(cpool->num_conn > maxconnects) {
494*6236dae4SAndroid Build Coastguard Worker infof(data, "Connection pool is full, closing the oldest one");
495*6236dae4SAndroid Build Coastguard Worker
496*6236dae4SAndroid Build Coastguard Worker oldest_idle = cpool_get_oldest_idle(cpool);
497*6236dae4SAndroid Build Coastguard Worker kept = (oldest_idle != conn);
498*6236dae4SAndroid Build Coastguard Worker if(oldest_idle) {
499*6236dae4SAndroid Build Coastguard Worker Curl_cpool_disconnect(cpool->idata, oldest_idle, FALSE);
500*6236dae4SAndroid Build Coastguard Worker }
501*6236dae4SAndroid Build Coastguard Worker }
502*6236dae4SAndroid Build Coastguard Worker if(do_lock)
503*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
504*6236dae4SAndroid Build Coastguard Worker }
505*6236dae4SAndroid Build Coastguard Worker
506*6236dae4SAndroid Build Coastguard Worker return kept;
507*6236dae4SAndroid Build Coastguard Worker }
508*6236dae4SAndroid Build Coastguard Worker
509*6236dae4SAndroid Build Coastguard Worker /*
510*6236dae4SAndroid Build Coastguard Worker * This function finds the connection in the connection bundle that has been
511*6236dae4SAndroid Build Coastguard Worker * unused for the longest time.
512*6236dae4SAndroid Build Coastguard Worker */
513*6236dae4SAndroid Build Coastguard Worker static struct connectdata *
cpool_bundle_get_oldest_idle(struct cpool_bundle * bundle)514*6236dae4SAndroid Build Coastguard Worker cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
515*6236dae4SAndroid Build Coastguard Worker {
516*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *curr;
517*6236dae4SAndroid Build Coastguard Worker timediff_t highscore = -1;
518*6236dae4SAndroid Build Coastguard Worker timediff_t score;
519*6236dae4SAndroid Build Coastguard Worker struct curltime now;
520*6236dae4SAndroid Build Coastguard Worker struct connectdata *oldest_idle = NULL;
521*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
522*6236dae4SAndroid Build Coastguard Worker
523*6236dae4SAndroid Build Coastguard Worker now = Curl_now();
524*6236dae4SAndroid Build Coastguard Worker curr = Curl_llist_head(&bundle->conns);
525*6236dae4SAndroid Build Coastguard Worker while(curr) {
526*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(curr);
527*6236dae4SAndroid Build Coastguard Worker
528*6236dae4SAndroid Build Coastguard Worker if(!CONN_INUSE(conn)) {
529*6236dae4SAndroid Build Coastguard Worker /* Set higher score for the age passed since the connection was used */
530*6236dae4SAndroid Build Coastguard Worker score = Curl_timediff(now, conn->lastused);
531*6236dae4SAndroid Build Coastguard Worker
532*6236dae4SAndroid Build Coastguard Worker if(score > highscore) {
533*6236dae4SAndroid Build Coastguard Worker highscore = score;
534*6236dae4SAndroid Build Coastguard Worker oldest_idle = conn;
535*6236dae4SAndroid Build Coastguard Worker }
536*6236dae4SAndroid Build Coastguard Worker }
537*6236dae4SAndroid Build Coastguard Worker curr = Curl_node_next(curr);
538*6236dae4SAndroid Build Coastguard Worker }
539*6236dae4SAndroid Build Coastguard Worker return oldest_idle;
540*6236dae4SAndroid Build Coastguard Worker }
541*6236dae4SAndroid Build Coastguard Worker
cpool_get_oldest_idle(struct cpool * cpool)542*6236dae4SAndroid Build Coastguard Worker static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
543*6236dae4SAndroid Build Coastguard Worker {
544*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_iterator iter;
545*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *curr;
546*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_element *he;
547*6236dae4SAndroid Build Coastguard Worker struct connectdata *oldest_idle = NULL;
548*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
549*6236dae4SAndroid Build Coastguard Worker struct curltime now;
550*6236dae4SAndroid Build Coastguard Worker timediff_t highscore =- 1;
551*6236dae4SAndroid Build Coastguard Worker timediff_t score;
552*6236dae4SAndroid Build Coastguard Worker
553*6236dae4SAndroid Build Coastguard Worker now = Curl_now();
554*6236dae4SAndroid Build Coastguard Worker Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
555*6236dae4SAndroid Build Coastguard Worker
556*6236dae4SAndroid Build Coastguard Worker for(he = Curl_hash_next_element(&iter); he;
557*6236dae4SAndroid Build Coastguard Worker he = Curl_hash_next_element(&iter)) {
558*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
559*6236dae4SAndroid Build Coastguard Worker bundle = he->ptr;
560*6236dae4SAndroid Build Coastguard Worker
561*6236dae4SAndroid Build Coastguard Worker for(curr = Curl_llist_head(&bundle->conns); curr;
562*6236dae4SAndroid Build Coastguard Worker curr = Curl_node_next(curr)) {
563*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(curr);
564*6236dae4SAndroid Build Coastguard Worker if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
565*6236dae4SAndroid Build Coastguard Worker continue;
566*6236dae4SAndroid Build Coastguard Worker /* Set higher score for the age passed since the connection was used */
567*6236dae4SAndroid Build Coastguard Worker score = Curl_timediff(now, conn->lastused);
568*6236dae4SAndroid Build Coastguard Worker if(score > highscore) {
569*6236dae4SAndroid Build Coastguard Worker highscore = score;
570*6236dae4SAndroid Build Coastguard Worker oldest_idle = conn;
571*6236dae4SAndroid Build Coastguard Worker }
572*6236dae4SAndroid Build Coastguard Worker }
573*6236dae4SAndroid Build Coastguard Worker }
574*6236dae4SAndroid Build Coastguard Worker return oldest_idle;
575*6236dae4SAndroid Build Coastguard Worker }
576*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_find(struct Curl_easy * data,const char * destination,size_t dest_len,Curl_cpool_conn_match_cb * conn_cb,Curl_cpool_done_match_cb * done_cb,void * userdata)577*6236dae4SAndroid Build Coastguard Worker bool Curl_cpool_find(struct Curl_easy *data,
578*6236dae4SAndroid Build Coastguard Worker const char *destination, size_t dest_len,
579*6236dae4SAndroid Build Coastguard Worker Curl_cpool_conn_match_cb *conn_cb,
580*6236dae4SAndroid Build Coastguard Worker Curl_cpool_done_match_cb *done_cb,
581*6236dae4SAndroid Build Coastguard Worker void *userdata)
582*6236dae4SAndroid Build Coastguard Worker {
583*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
584*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
585*6236dae4SAndroid Build Coastguard Worker bool result = FALSE;
586*6236dae4SAndroid Build Coastguard Worker
587*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
588*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(conn_cb);
589*6236dae4SAndroid Build Coastguard Worker if(!cpool)
590*6236dae4SAndroid Build Coastguard Worker return FALSE;
591*6236dae4SAndroid Build Coastguard Worker
592*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
593*6236dae4SAndroid Build Coastguard Worker bundle = Curl_hash_pick(&cpool->dest2bundle, (void *)destination, dest_len);
594*6236dae4SAndroid Build Coastguard Worker if(bundle) {
595*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *curr = Curl_llist_head(&bundle->conns);
596*6236dae4SAndroid Build Coastguard Worker while(curr) {
597*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = Curl_node_elem(curr);
598*6236dae4SAndroid Build Coastguard Worker /* Get next node now. callback might discard current */
599*6236dae4SAndroid Build Coastguard Worker curr = Curl_node_next(curr);
600*6236dae4SAndroid Build Coastguard Worker
601*6236dae4SAndroid Build Coastguard Worker if(conn_cb(conn, userdata)) {
602*6236dae4SAndroid Build Coastguard Worker result = TRUE;
603*6236dae4SAndroid Build Coastguard Worker break;
604*6236dae4SAndroid Build Coastguard Worker }
605*6236dae4SAndroid Build Coastguard Worker }
606*6236dae4SAndroid Build Coastguard Worker }
607*6236dae4SAndroid Build Coastguard Worker
608*6236dae4SAndroid Build Coastguard Worker if(done_cb) {
609*6236dae4SAndroid Build Coastguard Worker result = done_cb(result, userdata);
610*6236dae4SAndroid Build Coastguard Worker }
611*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
612*6236dae4SAndroid Build Coastguard Worker return result;
613*6236dae4SAndroid Build Coastguard Worker }
614*6236dae4SAndroid Build Coastguard Worker
cpool_shutdown_discard_all(struct cpool * cpool)615*6236dae4SAndroid Build Coastguard Worker static void cpool_shutdown_discard_all(struct cpool *cpool)
616*6236dae4SAndroid Build Coastguard Worker {
617*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
618*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
619*6236dae4SAndroid Build Coastguard Worker
620*6236dae4SAndroid Build Coastguard Worker if(!e)
621*6236dae4SAndroid Build Coastguard Worker return;
622*6236dae4SAndroid Build Coastguard Worker
623*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(cpool->idata, "cpool_shutdown_discard_all"));
624*6236dae4SAndroid Build Coastguard Worker while(e) {
625*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(e);
626*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(e);
627*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(cpool->idata, "discard connection #%" FMT_OFF_T,
628*6236dae4SAndroid Build Coastguard Worker conn->connection_id));
629*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(cpool, conn, NULL, FALSE);
630*6236dae4SAndroid Build Coastguard Worker e = Curl_llist_head(&cpool->shutdowns);
631*6236dae4SAndroid Build Coastguard Worker }
632*6236dae4SAndroid Build Coastguard Worker }
633*6236dae4SAndroid Build Coastguard Worker
cpool_close_and_destroy_all(struct cpool * cpool)634*6236dae4SAndroid Build Coastguard Worker static void cpool_close_and_destroy_all(struct cpool *cpool)
635*6236dae4SAndroid Build Coastguard Worker {
636*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
637*6236dae4SAndroid Build Coastguard Worker int timeout_ms = 0;
638*6236dae4SAndroid Build Coastguard Worker SIGPIPE_VARIABLE(pipe_st);
639*6236dae4SAndroid Build Coastguard Worker
640*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
641*6236dae4SAndroid Build Coastguard Worker /* Move all connections to the shutdown list */
642*6236dae4SAndroid Build Coastguard Worker sigpipe_init(&pipe_st);
643*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
644*6236dae4SAndroid Build Coastguard Worker conn = cpool_get_live_conn(cpool);
645*6236dae4SAndroid Build Coastguard Worker while(conn) {
646*6236dae4SAndroid Build Coastguard Worker cpool_remove_conn(cpool, conn);
647*6236dae4SAndroid Build Coastguard Worker sigpipe_apply(cpool->idata, &pipe_st);
648*6236dae4SAndroid Build Coastguard Worker connclose(conn, "kill all");
649*6236dae4SAndroid Build Coastguard Worker cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
650*6236dae4SAndroid Build Coastguard Worker
651*6236dae4SAndroid Build Coastguard Worker conn = cpool_get_live_conn(cpool);
652*6236dae4SAndroid Build Coastguard Worker }
653*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
654*6236dae4SAndroid Build Coastguard Worker
655*6236dae4SAndroid Build Coastguard Worker /* Just for testing, run graceful shutdown */
656*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
657*6236dae4SAndroid Build Coastguard Worker {
658*6236dae4SAndroid Build Coastguard Worker char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
659*6236dae4SAndroid Build Coastguard Worker if(p) {
660*6236dae4SAndroid Build Coastguard Worker long l = strtol(p, NULL, 10);
661*6236dae4SAndroid Build Coastguard Worker if(l > 0 && l < INT_MAX)
662*6236dae4SAndroid Build Coastguard Worker timeout_ms = (int)l;
663*6236dae4SAndroid Build Coastguard Worker }
664*6236dae4SAndroid Build Coastguard Worker }
665*6236dae4SAndroid Build Coastguard Worker #endif
666*6236dae4SAndroid Build Coastguard Worker sigpipe_apply(cpool->idata, &pipe_st);
667*6236dae4SAndroid Build Coastguard Worker cpool_shutdown_all(cpool, cpool->idata, timeout_ms);
668*6236dae4SAndroid Build Coastguard Worker
669*6236dae4SAndroid Build Coastguard Worker /* discard all connections in the shutdown list */
670*6236dae4SAndroid Build Coastguard Worker cpool_shutdown_discard_all(cpool);
671*6236dae4SAndroid Build Coastguard Worker
672*6236dae4SAndroid Build Coastguard Worker Curl_hostcache_clean(cpool->idata, cpool->idata->dns.hostcache);
673*6236dae4SAndroid Build Coastguard Worker sigpipe_restore(&pipe_st);
674*6236dae4SAndroid Build Coastguard Worker }
675*6236dae4SAndroid Build Coastguard Worker
676*6236dae4SAndroid Build Coastguard Worker
cpool_shutdown_destroy_oldest(struct cpool * cpool)677*6236dae4SAndroid Build Coastguard Worker static void cpool_shutdown_destroy_oldest(struct cpool *cpool)
678*6236dae4SAndroid Build Coastguard Worker {
679*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
680*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
681*6236dae4SAndroid Build Coastguard Worker
682*6236dae4SAndroid Build Coastguard Worker e = Curl_llist_head(&cpool->shutdowns);
683*6236dae4SAndroid Build Coastguard Worker if(e) {
684*6236dae4SAndroid Build Coastguard Worker SIGPIPE_VARIABLE(pipe_st);
685*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(e);
686*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(e);
687*6236dae4SAndroid Build Coastguard Worker sigpipe_init(&pipe_st);
688*6236dae4SAndroid Build Coastguard Worker sigpipe_apply(cpool->idata, &pipe_st);
689*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(cpool, conn, NULL, FALSE);
690*6236dae4SAndroid Build Coastguard Worker sigpipe_restore(&pipe_st);
691*6236dae4SAndroid Build Coastguard Worker }
692*6236dae4SAndroid Build Coastguard Worker }
693*6236dae4SAndroid Build Coastguard Worker
cpool_discard_conn(struct cpool * cpool,struct Curl_easy * data,struct connectdata * conn,bool aborted)694*6236dae4SAndroid Build Coastguard Worker static void cpool_discard_conn(struct cpool *cpool,
695*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
696*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
697*6236dae4SAndroid Build Coastguard Worker bool aborted)
698*6236dae4SAndroid Build Coastguard Worker {
699*6236dae4SAndroid Build Coastguard Worker bool done = FALSE;
700*6236dae4SAndroid Build Coastguard Worker
701*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data);
702*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
703*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!conn->bits.in_cpool);
704*6236dae4SAndroid Build Coastguard Worker
705*6236dae4SAndroid Build Coastguard Worker /*
706*6236dae4SAndroid Build Coastguard Worker * If this connection is not marked to force-close, leave it open if there
707*6236dae4SAndroid Build Coastguard Worker * are other users of it
708*6236dae4SAndroid Build Coastguard Worker */
709*6236dae4SAndroid Build Coastguard Worker if(CONN_INUSE(conn) && !aborted) {
710*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] not discarding #%" FMT_OFF_T
711*6236dae4SAndroid Build Coastguard Worker " still in use by %zu transfers", conn->connection_id,
712*6236dae4SAndroid Build Coastguard Worker CONN_INUSE(conn)));
713*6236dae4SAndroid Build Coastguard Worker return;
714*6236dae4SAndroid Build Coastguard Worker }
715*6236dae4SAndroid Build Coastguard Worker
716*6236dae4SAndroid Build Coastguard Worker /* treat the connection as aborted in CONNECT_ONLY situations, we do
717*6236dae4SAndroid Build Coastguard Worker * not know what the APP did with it. */
718*6236dae4SAndroid Build Coastguard Worker if(conn->connect_only)
719*6236dae4SAndroid Build Coastguard Worker aborted = TRUE;
720*6236dae4SAndroid Build Coastguard Worker conn->bits.aborted = aborted;
721*6236dae4SAndroid Build Coastguard Worker
722*6236dae4SAndroid Build Coastguard Worker /* We do not shutdown dead connections. The term 'dead' can be misleading
723*6236dae4SAndroid Build Coastguard Worker * here, as we also mark errored connections/transfers as 'dead'.
724*6236dae4SAndroid Build Coastguard Worker * If we do a shutdown for an aborted transfer, the server might think
725*6236dae4SAndroid Build Coastguard Worker * it was successful otherwise (for example an ftps: upload). This is
726*6236dae4SAndroid Build Coastguard Worker * not what we want. */
727*6236dae4SAndroid Build Coastguard Worker if(aborted)
728*6236dae4SAndroid Build Coastguard Worker done = TRUE;
729*6236dae4SAndroid Build Coastguard Worker if(!done) {
730*6236dae4SAndroid Build Coastguard Worker /* Attempt to shutdown the connection right away. */
731*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(data, conn);
732*6236dae4SAndroid Build Coastguard Worker cpool_run_conn_shutdown(data, conn, &done);
733*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
734*6236dae4SAndroid Build Coastguard Worker conn->connection_id, done));
735*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(data);
736*6236dae4SAndroid Build Coastguard Worker }
737*6236dae4SAndroid Build Coastguard Worker
738*6236dae4SAndroid Build Coastguard Worker if(done) {
739*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(cpool, conn, data, FALSE);
740*6236dae4SAndroid Build Coastguard Worker return;
741*6236dae4SAndroid Build Coastguard Worker }
742*6236dae4SAndroid Build Coastguard Worker
743*6236dae4SAndroid Build Coastguard Worker /* Add the connection to our shutdown list for non-blocking shutdown
744*6236dae4SAndroid Build Coastguard Worker * during multi processing. */
745*6236dae4SAndroid Build Coastguard Worker if(data->multi && data->multi->max_shutdown_connections > 0 &&
746*6236dae4SAndroid Build Coastguard Worker (data->multi->max_shutdown_connections >=
747*6236dae4SAndroid Build Coastguard Worker (long)Curl_llist_count(&cpool->shutdowns))) {
748*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
749*6236dae4SAndroid Build Coastguard Worker "due to limit of %ld",
750*6236dae4SAndroid Build Coastguard Worker data->multi->max_shutdown_connections));
751*6236dae4SAndroid Build Coastguard Worker cpool_shutdown_destroy_oldest(cpool);
752*6236dae4SAndroid Build Coastguard Worker }
753*6236dae4SAndroid Build Coastguard Worker
754*6236dae4SAndroid Build Coastguard Worker if(data->multi && data->multi->socket_cb) {
755*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool == &data->multi->cpool);
756*6236dae4SAndroid Build Coastguard Worker /* Start with an empty shutdown pollset, so out internal closure handle
757*6236dae4SAndroid Build Coastguard Worker * is added to the sockets. */
758*6236dae4SAndroid Build Coastguard Worker memset(&conn->shutdown_poll, 0, sizeof(conn->shutdown_poll));
759*6236dae4SAndroid Build Coastguard Worker if(cpool_update_shutdown_ev(data->multi, cpool->idata, conn)) {
760*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
761*6236dae4SAndroid Build Coastguard Worker "discarding #%" FMT_OFF_T,
762*6236dae4SAndroid Build Coastguard Worker conn->connection_id));
763*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(cpool, conn, data, FALSE);
764*6236dae4SAndroid Build Coastguard Worker return;
765*6236dae4SAndroid Build Coastguard Worker }
766*6236dae4SAndroid Build Coastguard Worker }
767*6236dae4SAndroid Build Coastguard Worker
768*6236dae4SAndroid Build Coastguard Worker Curl_llist_append(&cpool->shutdowns, conn, &conn->cpool_node);
769*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] added #%" FMT_OFF_T
770*6236dae4SAndroid Build Coastguard Worker " to shutdown list of length %zu", conn->connection_id,
771*6236dae4SAndroid Build Coastguard Worker Curl_llist_count(&cpool->shutdowns)));
772*6236dae4SAndroid Build Coastguard Worker }
773*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_disconnect(struct Curl_easy * data,struct connectdata * conn,bool aborted)774*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_disconnect(struct Curl_easy *data,
775*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
776*6236dae4SAndroid Build Coastguard Worker bool aborted)
777*6236dae4SAndroid Build Coastguard Worker {
778*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
779*6236dae4SAndroid Build Coastguard Worker bool do_lock;
780*6236dae4SAndroid Build Coastguard Worker
781*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(cpool);
782*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data && !data->conn);
783*6236dae4SAndroid Build Coastguard Worker if(!cpool)
784*6236dae4SAndroid Build Coastguard Worker return;
785*6236dae4SAndroid Build Coastguard Worker
786*6236dae4SAndroid Build Coastguard Worker /* If this connection is not marked to force-close, leave it open if there
787*6236dae4SAndroid Build Coastguard Worker * are other users of it */
788*6236dae4SAndroid Build Coastguard Worker if(CONN_INUSE(conn) && !aborted) {
789*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(0); /* does this ever happen? */
790*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
791*6236dae4SAndroid Build Coastguard Worker return;
792*6236dae4SAndroid Build Coastguard Worker }
793*6236dae4SAndroid Build Coastguard Worker
794*6236dae4SAndroid Build Coastguard Worker /* This method may be called while we are under lock, e.g. from a
795*6236dae4SAndroid Build Coastguard Worker * user callback in find. */
796*6236dae4SAndroid Build Coastguard Worker do_lock = !CPOOL_IS_LOCKED(cpool);
797*6236dae4SAndroid Build Coastguard Worker if(do_lock)
798*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
799*6236dae4SAndroid Build Coastguard Worker
800*6236dae4SAndroid Build Coastguard Worker if(conn->bits.in_cpool) {
801*6236dae4SAndroid Build Coastguard Worker cpool_remove_conn(cpool, conn);
802*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!conn->bits.in_cpool);
803*6236dae4SAndroid Build Coastguard Worker }
804*6236dae4SAndroid Build Coastguard Worker
805*6236dae4SAndroid Build Coastguard Worker /* Run the callback to let it clean up anything it wants to. */
806*6236dae4SAndroid Build Coastguard Worker aborted = cpool->disconnect_cb(data, conn, aborted);
807*6236dae4SAndroid Build Coastguard Worker
808*6236dae4SAndroid Build Coastguard Worker if(data->multi) {
809*6236dae4SAndroid Build Coastguard Worker /* Add it to the multi's cpool for shutdown handling */
810*6236dae4SAndroid Build Coastguard Worker infof(data, "%s connection #%" FMT_OFF_T,
811*6236dae4SAndroid Build Coastguard Worker aborted ? "closing" : "shutting down", conn->connection_id);
812*6236dae4SAndroid Build Coastguard Worker cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
813*6236dae4SAndroid Build Coastguard Worker }
814*6236dae4SAndroid Build Coastguard Worker else {
815*6236dae4SAndroid Build Coastguard Worker /* No multi available. Make a best-effort shutdown + close */
816*6236dae4SAndroid Build Coastguard Worker infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
817*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(NULL, conn, data, !aborted);
818*6236dae4SAndroid Build Coastguard Worker }
819*6236dae4SAndroid Build Coastguard Worker
820*6236dae4SAndroid Build Coastguard Worker if(do_lock)
821*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
822*6236dae4SAndroid Build Coastguard Worker }
823*6236dae4SAndroid Build Coastguard Worker
cpool_run_conn_shutdown_handler(struct Curl_easy * data,struct connectdata * conn)824*6236dae4SAndroid Build Coastguard Worker static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
825*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
826*6236dae4SAndroid Build Coastguard Worker {
827*6236dae4SAndroid Build Coastguard Worker if(!conn->bits.shutdown_handler) {
828*6236dae4SAndroid Build Coastguard Worker if(conn->dns_entry)
829*6236dae4SAndroid Build Coastguard Worker Curl_resolv_unlink(data, &conn->dns_entry);
830*6236dae4SAndroid Build Coastguard Worker
831*6236dae4SAndroid Build Coastguard Worker /* Cleanup NTLM connection-related data */
832*6236dae4SAndroid Build Coastguard Worker Curl_http_auth_cleanup_ntlm(conn);
833*6236dae4SAndroid Build Coastguard Worker
834*6236dae4SAndroid Build Coastguard Worker /* Cleanup NEGOTIATE connection-related data */
835*6236dae4SAndroid Build Coastguard Worker Curl_http_auth_cleanup_negotiate(conn);
836*6236dae4SAndroid Build Coastguard Worker
837*6236dae4SAndroid Build Coastguard Worker if(conn->handler && conn->handler->disconnect) {
838*6236dae4SAndroid Build Coastguard Worker /* This is set if protocol-specific cleanups should be made */
839*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "connection #%" FMT_OFF_T
840*6236dae4SAndroid Build Coastguard Worker ", shutdown protocol handler (aborted=%d)",
841*6236dae4SAndroid Build Coastguard Worker conn->connection_id, conn->bits.aborted));
842*6236dae4SAndroid Build Coastguard Worker
843*6236dae4SAndroid Build Coastguard Worker conn->handler->disconnect(data, conn, conn->bits.aborted);
844*6236dae4SAndroid Build Coastguard Worker }
845*6236dae4SAndroid Build Coastguard Worker
846*6236dae4SAndroid Build Coastguard Worker /* possible left-overs from the async name resolvers */
847*6236dae4SAndroid Build Coastguard Worker Curl_resolver_cancel(data);
848*6236dae4SAndroid Build Coastguard Worker
849*6236dae4SAndroid Build Coastguard Worker conn->bits.shutdown_handler = TRUE;
850*6236dae4SAndroid Build Coastguard Worker }
851*6236dae4SAndroid Build Coastguard Worker }
852*6236dae4SAndroid Build Coastguard Worker
cpool_run_conn_shutdown(struct Curl_easy * data,struct connectdata * conn,bool * done)853*6236dae4SAndroid Build Coastguard Worker static void cpool_run_conn_shutdown(struct Curl_easy *data,
854*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
855*6236dae4SAndroid Build Coastguard Worker bool *done)
856*6236dae4SAndroid Build Coastguard Worker {
857*6236dae4SAndroid Build Coastguard Worker CURLcode r1, r2;
858*6236dae4SAndroid Build Coastguard Worker bool done1, done2;
859*6236dae4SAndroid Build Coastguard Worker
860*6236dae4SAndroid Build Coastguard Worker /* We expect to be attached when called */
861*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data->conn == conn);
862*6236dae4SAndroid Build Coastguard Worker
863*6236dae4SAndroid Build Coastguard Worker cpool_run_conn_shutdown_handler(data, conn);
864*6236dae4SAndroid Build Coastguard Worker
865*6236dae4SAndroid Build Coastguard Worker if(conn->bits.shutdown_filters) {
866*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
867*6236dae4SAndroid Build Coastguard Worker return;
868*6236dae4SAndroid Build Coastguard Worker }
869*6236dae4SAndroid Build Coastguard Worker
870*6236dae4SAndroid Build Coastguard Worker if(!conn->connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET))
871*6236dae4SAndroid Build Coastguard Worker r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1);
872*6236dae4SAndroid Build Coastguard Worker else {
873*6236dae4SAndroid Build Coastguard Worker r1 = CURLE_OK;
874*6236dae4SAndroid Build Coastguard Worker done1 = TRUE;
875*6236dae4SAndroid Build Coastguard Worker }
876*6236dae4SAndroid Build Coastguard Worker
877*6236dae4SAndroid Build Coastguard Worker if(!conn->connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET))
878*6236dae4SAndroid Build Coastguard Worker r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2);
879*6236dae4SAndroid Build Coastguard Worker else {
880*6236dae4SAndroid Build Coastguard Worker r2 = CURLE_OK;
881*6236dae4SAndroid Build Coastguard Worker done2 = TRUE;
882*6236dae4SAndroid Build Coastguard Worker }
883*6236dae4SAndroid Build Coastguard Worker
884*6236dae4SAndroid Build Coastguard Worker /* we are done when any failed or both report success */
885*6236dae4SAndroid Build Coastguard Worker *done = (r1 || r2 || (done1 && done2));
886*6236dae4SAndroid Build Coastguard Worker if(*done)
887*6236dae4SAndroid Build Coastguard Worker conn->bits.shutdown_filters = TRUE;
888*6236dae4SAndroid Build Coastguard Worker }
889*6236dae4SAndroid Build Coastguard Worker
cpool_add_pollfds(struct cpool * cpool,struct curl_pollfds * cpfds)890*6236dae4SAndroid Build Coastguard Worker static CURLcode cpool_add_pollfds(struct cpool *cpool,
891*6236dae4SAndroid Build Coastguard Worker struct curl_pollfds *cpfds)
892*6236dae4SAndroid Build Coastguard Worker {
893*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
894*6236dae4SAndroid Build Coastguard Worker
895*6236dae4SAndroid Build Coastguard Worker if(Curl_llist_head(&cpool->shutdowns)) {
896*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
897*6236dae4SAndroid Build Coastguard Worker struct easy_pollset ps;
898*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
899*6236dae4SAndroid Build Coastguard Worker
900*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&cpool->shutdowns); e;
901*6236dae4SAndroid Build Coastguard Worker e = Curl_node_next(e)) {
902*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(e);
903*6236dae4SAndroid Build Coastguard Worker memset(&ps, 0, sizeof(ps));
904*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(cpool->idata, conn);
905*6236dae4SAndroid Build Coastguard Worker Curl_conn_adjust_pollset(cpool->idata, &ps);
906*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(cpool->idata);
907*6236dae4SAndroid Build Coastguard Worker
908*6236dae4SAndroid Build Coastguard Worker result = Curl_pollfds_add_ps(cpfds, &ps);
909*6236dae4SAndroid Build Coastguard Worker if(result) {
910*6236dae4SAndroid Build Coastguard Worker Curl_pollfds_cleanup(cpfds);
911*6236dae4SAndroid Build Coastguard Worker goto out;
912*6236dae4SAndroid Build Coastguard Worker }
913*6236dae4SAndroid Build Coastguard Worker }
914*6236dae4SAndroid Build Coastguard Worker }
915*6236dae4SAndroid Build Coastguard Worker out:
916*6236dae4SAndroid Build Coastguard Worker return result;
917*6236dae4SAndroid Build Coastguard Worker }
918*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_add_pollfds(struct cpool * cpool,struct curl_pollfds * cpfds)919*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cpool_add_pollfds(struct cpool *cpool,
920*6236dae4SAndroid Build Coastguard Worker struct curl_pollfds *cpfds)
921*6236dae4SAndroid Build Coastguard Worker {
922*6236dae4SAndroid Build Coastguard Worker CURLcode result;
923*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
924*6236dae4SAndroid Build Coastguard Worker result = cpool_add_pollfds(cpool, cpfds);
925*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
926*6236dae4SAndroid Build Coastguard Worker return result;
927*6236dae4SAndroid Build Coastguard Worker }
928*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_add_waitfds(struct cpool * cpool,struct curl_waitfds * cwfds)929*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cpool_add_waitfds(struct cpool *cpool,
930*6236dae4SAndroid Build Coastguard Worker struct curl_waitfds *cwfds)
931*6236dae4SAndroid Build Coastguard Worker {
932*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
933*6236dae4SAndroid Build Coastguard Worker
934*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
935*6236dae4SAndroid Build Coastguard Worker if(Curl_llist_head(&cpool->shutdowns)) {
936*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
937*6236dae4SAndroid Build Coastguard Worker struct easy_pollset ps;
938*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
939*6236dae4SAndroid Build Coastguard Worker
940*6236dae4SAndroid Build Coastguard Worker for(e = Curl_llist_head(&cpool->shutdowns); e;
941*6236dae4SAndroid Build Coastguard Worker e = Curl_node_next(e)) {
942*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(e);
943*6236dae4SAndroid Build Coastguard Worker memset(&ps, 0, sizeof(ps));
944*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(cpool->idata, conn);
945*6236dae4SAndroid Build Coastguard Worker Curl_conn_adjust_pollset(cpool->idata, &ps);
946*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(cpool->idata);
947*6236dae4SAndroid Build Coastguard Worker
948*6236dae4SAndroid Build Coastguard Worker result = Curl_waitfds_add_ps(cwfds, &ps);
949*6236dae4SAndroid Build Coastguard Worker if(result)
950*6236dae4SAndroid Build Coastguard Worker goto out;
951*6236dae4SAndroid Build Coastguard Worker }
952*6236dae4SAndroid Build Coastguard Worker }
953*6236dae4SAndroid Build Coastguard Worker out:
954*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
955*6236dae4SAndroid Build Coastguard Worker return result;
956*6236dae4SAndroid Build Coastguard Worker }
957*6236dae4SAndroid Build Coastguard Worker
cpool_perform(struct cpool * cpool)958*6236dae4SAndroid Build Coastguard Worker static void cpool_perform(struct cpool *cpool)
959*6236dae4SAndroid Build Coastguard Worker {
960*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = cpool->idata;
961*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
962*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *enext;
963*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
964*6236dae4SAndroid Build Coastguard Worker struct curltime *nowp = NULL;
965*6236dae4SAndroid Build Coastguard Worker struct curltime now;
966*6236dae4SAndroid Build Coastguard Worker timediff_t next_from_now_ms = 0, ms;
967*6236dae4SAndroid Build Coastguard Worker bool done;
968*6236dae4SAndroid Build Coastguard Worker
969*6236dae4SAndroid Build Coastguard Worker if(!e)
970*6236dae4SAndroid Build Coastguard Worker return;
971*6236dae4SAndroid Build Coastguard Worker
972*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data);
973*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
974*6236dae4SAndroid Build Coastguard Worker Curl_llist_count(&cpool->shutdowns)));
975*6236dae4SAndroid Build Coastguard Worker while(e) {
976*6236dae4SAndroid Build Coastguard Worker enext = Curl_node_next(e);
977*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(e);
978*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(data, conn);
979*6236dae4SAndroid Build Coastguard Worker cpool_run_conn_shutdown(data, conn, &done);
980*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
981*6236dae4SAndroid Build Coastguard Worker conn->connection_id, done));
982*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(data);
983*6236dae4SAndroid Build Coastguard Worker if(done) {
984*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(e);
985*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(cpool, conn, NULL, FALSE);
986*6236dae4SAndroid Build Coastguard Worker }
987*6236dae4SAndroid Build Coastguard Worker else {
988*6236dae4SAndroid Build Coastguard Worker /* Not done, when does this connection time out? */
989*6236dae4SAndroid Build Coastguard Worker if(!nowp) {
990*6236dae4SAndroid Build Coastguard Worker now = Curl_now();
991*6236dae4SAndroid Build Coastguard Worker nowp = &now;
992*6236dae4SAndroid Build Coastguard Worker }
993*6236dae4SAndroid Build Coastguard Worker ms = Curl_conn_shutdown_timeleft(conn, nowp);
994*6236dae4SAndroid Build Coastguard Worker if(ms && ms < next_from_now_ms)
995*6236dae4SAndroid Build Coastguard Worker next_from_now_ms = ms;
996*6236dae4SAndroid Build Coastguard Worker }
997*6236dae4SAndroid Build Coastguard Worker e = enext;
998*6236dae4SAndroid Build Coastguard Worker }
999*6236dae4SAndroid Build Coastguard Worker
1000*6236dae4SAndroid Build Coastguard Worker if(next_from_now_ms)
1001*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, next_from_now_ms, EXPIRE_RUN_NOW);
1002*6236dae4SAndroid Build Coastguard Worker }
1003*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_multi_perform(struct Curl_multi * multi)1004*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_multi_perform(struct Curl_multi *multi)
1005*6236dae4SAndroid Build Coastguard Worker {
1006*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(&multi->cpool);
1007*6236dae4SAndroid Build Coastguard Worker cpool_perform(&multi->cpool);
1008*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(&multi->cpool);
1009*6236dae4SAndroid Build Coastguard Worker }
1010*6236dae4SAndroid Build Coastguard Worker
1011*6236dae4SAndroid Build Coastguard Worker
1012*6236dae4SAndroid Build Coastguard Worker /*
1013*6236dae4SAndroid Build Coastguard Worker * Close and destroy the connection. Run the shutdown sequence once,
1014*6236dae4SAndroid Build Coastguard Worker * of so requested.
1015*6236dae4SAndroid Build Coastguard Worker */
cpool_close_and_destroy(struct cpool * cpool,struct connectdata * conn,struct Curl_easy * data,bool do_shutdown)1016*6236dae4SAndroid Build Coastguard Worker static void cpool_close_and_destroy(struct cpool *cpool,
1017*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
1018*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1019*6236dae4SAndroid Build Coastguard Worker bool do_shutdown)
1020*6236dae4SAndroid Build Coastguard Worker {
1021*6236dae4SAndroid Build Coastguard Worker bool done;
1022*6236dae4SAndroid Build Coastguard Worker
1023*6236dae4SAndroid Build Coastguard Worker /* there must be a connection to close */
1024*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(conn);
1025*6236dae4SAndroid Build Coastguard Worker /* it must be removed from the connection pool */
1026*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!conn->bits.in_cpool);
1027*6236dae4SAndroid Build Coastguard Worker /* there must be an associated transfer */
1028*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data || cpool);
1029*6236dae4SAndroid Build Coastguard Worker if(!data)
1030*6236dae4SAndroid Build Coastguard Worker data = cpool->idata;
1031*6236dae4SAndroid Build Coastguard Worker
1032*6236dae4SAndroid Build Coastguard Worker /* the transfer must be detached from the connection */
1033*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data && !data->conn);
1034*6236dae4SAndroid Build Coastguard Worker
1035*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(data, conn);
1036*6236dae4SAndroid Build Coastguard Worker
1037*6236dae4SAndroid Build Coastguard Worker cpool_run_conn_shutdown_handler(data, conn);
1038*6236dae4SAndroid Build Coastguard Worker if(do_shutdown) {
1039*6236dae4SAndroid Build Coastguard Worker /* Make a last attempt to shutdown handlers and filters, if
1040*6236dae4SAndroid Build Coastguard Worker * not done so already. */
1041*6236dae4SAndroid Build Coastguard Worker cpool_run_conn_shutdown(data, conn, &done);
1042*6236dae4SAndroid Build Coastguard Worker }
1043*6236dae4SAndroid Build Coastguard Worker
1044*6236dae4SAndroid Build Coastguard Worker if(cpool)
1045*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] closing #%" FMT_OFF_T,
1046*6236dae4SAndroid Build Coastguard Worker conn->connection_id));
1047*6236dae4SAndroid Build Coastguard Worker else
1048*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "closing connection #%" FMT_OFF_T,
1049*6236dae4SAndroid Build Coastguard Worker conn->connection_id));
1050*6236dae4SAndroid Build Coastguard Worker Curl_conn_close(data, SECONDARYSOCKET);
1051*6236dae4SAndroid Build Coastguard Worker Curl_conn_close(data, FIRSTSOCKET);
1052*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(data);
1053*6236dae4SAndroid Build Coastguard Worker
1054*6236dae4SAndroid Build Coastguard Worker Curl_conn_free(data, conn);
1055*6236dae4SAndroid Build Coastguard Worker }
1056*6236dae4SAndroid Build Coastguard Worker
1057*6236dae4SAndroid Build Coastguard Worker
cpool_update_shutdown_ev(struct Curl_multi * multi,struct Curl_easy * data,struct connectdata * conn)1058*6236dae4SAndroid Build Coastguard Worker static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
1059*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
1060*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
1061*6236dae4SAndroid Build Coastguard Worker {
1062*6236dae4SAndroid Build Coastguard Worker struct easy_pollset ps;
1063*6236dae4SAndroid Build Coastguard Worker CURLMcode mresult;
1064*6236dae4SAndroid Build Coastguard Worker
1065*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(data);
1066*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(multi);
1067*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(multi->socket_cb);
1068*6236dae4SAndroid Build Coastguard Worker
1069*6236dae4SAndroid Build Coastguard Worker memset(&ps, 0, sizeof(ps));
1070*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(data, conn);
1071*6236dae4SAndroid Build Coastguard Worker Curl_conn_adjust_pollset(data, &ps);
1072*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(data);
1073*6236dae4SAndroid Build Coastguard Worker
1074*6236dae4SAndroid Build Coastguard Worker mresult = Curl_multi_pollset_ev(multi, data, &ps, &conn->shutdown_poll);
1075*6236dae4SAndroid Build Coastguard Worker
1076*6236dae4SAndroid Build Coastguard Worker if(!mresult) /* Remember for next time */
1077*6236dae4SAndroid Build Coastguard Worker memcpy(&conn->shutdown_poll, &ps, sizeof(ps));
1078*6236dae4SAndroid Build Coastguard Worker return mresult;
1079*6236dae4SAndroid Build Coastguard Worker }
1080*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_multi_socket(struct Curl_multi * multi,curl_socket_t s,int ev_bitmask)1081*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_multi_socket(struct Curl_multi *multi,
1082*6236dae4SAndroid Build Coastguard Worker curl_socket_t s, int ev_bitmask)
1083*6236dae4SAndroid Build Coastguard Worker {
1084*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = &multi->cpool;
1085*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data = cpool->idata;
1086*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *e;
1087*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
1088*6236dae4SAndroid Build Coastguard Worker bool done;
1089*6236dae4SAndroid Build Coastguard Worker
1090*6236dae4SAndroid Build Coastguard Worker (void)ev_bitmask;
1091*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(multi->socket_cb);
1092*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
1093*6236dae4SAndroid Build Coastguard Worker e = Curl_llist_head(&cpool->shutdowns);
1094*6236dae4SAndroid Build Coastguard Worker while(e) {
1095*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(e);
1096*6236dae4SAndroid Build Coastguard Worker if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
1097*6236dae4SAndroid Build Coastguard Worker Curl_attach_connection(data, conn);
1098*6236dae4SAndroid Build Coastguard Worker cpool_run_conn_shutdown(data, conn, &done);
1099*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
1100*6236dae4SAndroid Build Coastguard Worker conn->connection_id, done));
1101*6236dae4SAndroid Build Coastguard Worker Curl_detach_connection(data);
1102*6236dae4SAndroid Build Coastguard Worker if(done || cpool_update_shutdown_ev(multi, data, conn)) {
1103*6236dae4SAndroid Build Coastguard Worker Curl_node_remove(e);
1104*6236dae4SAndroid Build Coastguard Worker cpool_close_and_destroy(cpool, conn, NULL, FALSE);
1105*6236dae4SAndroid Build Coastguard Worker }
1106*6236dae4SAndroid Build Coastguard Worker break;
1107*6236dae4SAndroid Build Coastguard Worker }
1108*6236dae4SAndroid Build Coastguard Worker e = Curl_node_next(e);
1109*6236dae4SAndroid Build Coastguard Worker }
1110*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
1111*6236dae4SAndroid Build Coastguard Worker }
1112*6236dae4SAndroid Build Coastguard Worker
1113*6236dae4SAndroid Build Coastguard Worker #define NUM_POLLS_ON_STACK 10
1114*6236dae4SAndroid Build Coastguard Worker
cpool_shutdown_wait(struct cpool * cpool,int timeout_ms)1115*6236dae4SAndroid Build Coastguard Worker static CURLcode cpool_shutdown_wait(struct cpool *cpool, int timeout_ms)
1116*6236dae4SAndroid Build Coastguard Worker {
1117*6236dae4SAndroid Build Coastguard Worker struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
1118*6236dae4SAndroid Build Coastguard Worker struct curl_pollfds cpfds;
1119*6236dae4SAndroid Build Coastguard Worker CURLcode result;
1120*6236dae4SAndroid Build Coastguard Worker
1121*6236dae4SAndroid Build Coastguard Worker Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
1122*6236dae4SAndroid Build Coastguard Worker
1123*6236dae4SAndroid Build Coastguard Worker result = cpool_add_pollfds(cpool, &cpfds);
1124*6236dae4SAndroid Build Coastguard Worker if(result)
1125*6236dae4SAndroid Build Coastguard Worker goto out;
1126*6236dae4SAndroid Build Coastguard Worker
1127*6236dae4SAndroid Build Coastguard Worker Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
1128*6236dae4SAndroid Build Coastguard Worker
1129*6236dae4SAndroid Build Coastguard Worker out:
1130*6236dae4SAndroid Build Coastguard Worker Curl_pollfds_cleanup(&cpfds);
1131*6236dae4SAndroid Build Coastguard Worker return result;
1132*6236dae4SAndroid Build Coastguard Worker }
1133*6236dae4SAndroid Build Coastguard Worker
cpool_shutdown_all(struct cpool * cpool,struct Curl_easy * data,int timeout_ms)1134*6236dae4SAndroid Build Coastguard Worker static void cpool_shutdown_all(struct cpool *cpool,
1135*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data, int timeout_ms)
1136*6236dae4SAndroid Build Coastguard Worker {
1137*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
1138*6236dae4SAndroid Build Coastguard Worker struct curltime started = Curl_now();
1139*6236dae4SAndroid Build Coastguard Worker
1140*6236dae4SAndroid Build Coastguard Worker if(!data)
1141*6236dae4SAndroid Build Coastguard Worker return;
1142*6236dae4SAndroid Build Coastguard Worker (void)data;
1143*6236dae4SAndroid Build Coastguard Worker
1144*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "cpool shutdown all"));
1145*6236dae4SAndroid Build Coastguard Worker
1146*6236dae4SAndroid Build Coastguard Worker /* Move all connections into the shutdown queue */
1147*6236dae4SAndroid Build Coastguard Worker for(conn = cpool_get_live_conn(cpool); conn;
1148*6236dae4SAndroid Build Coastguard Worker conn = cpool_get_live_conn(cpool)) {
1149*6236dae4SAndroid Build Coastguard Worker /* Move conn from live set to shutdown or destroy right away */
1150*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "moving connection #%" FMT_OFF_T
1151*6236dae4SAndroid Build Coastguard Worker " to shutdown queue", conn->connection_id));
1152*6236dae4SAndroid Build Coastguard Worker cpool_remove_conn(cpool, conn);
1153*6236dae4SAndroid Build Coastguard Worker cpool_discard_conn(cpool, data, conn, FALSE);
1154*6236dae4SAndroid Build Coastguard Worker }
1155*6236dae4SAndroid Build Coastguard Worker
1156*6236dae4SAndroid Build Coastguard Worker while(Curl_llist_head(&cpool->shutdowns)) {
1157*6236dae4SAndroid Build Coastguard Worker timediff_t timespent;
1158*6236dae4SAndroid Build Coastguard Worker int remain_ms;
1159*6236dae4SAndroid Build Coastguard Worker
1160*6236dae4SAndroid Build Coastguard Worker cpool_perform(cpool);
1161*6236dae4SAndroid Build Coastguard Worker
1162*6236dae4SAndroid Build Coastguard Worker if(!Curl_llist_head(&cpool->shutdowns)) {
1163*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "cpool shutdown ok"));
1164*6236dae4SAndroid Build Coastguard Worker break;
1165*6236dae4SAndroid Build Coastguard Worker }
1166*6236dae4SAndroid Build Coastguard Worker
1167*6236dae4SAndroid Build Coastguard Worker /* wait for activity, timeout or "nothing" */
1168*6236dae4SAndroid Build Coastguard Worker timespent = Curl_timediff(Curl_now(), started);
1169*6236dae4SAndroid Build Coastguard Worker if(timespent >= (timediff_t)timeout_ms) {
1170*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "cpool shutdown %s",
1171*6236dae4SAndroid Build Coastguard Worker (timeout_ms > 0) ? "timeout" : "best effort done"));
1172*6236dae4SAndroid Build Coastguard Worker break;
1173*6236dae4SAndroid Build Coastguard Worker }
1174*6236dae4SAndroid Build Coastguard Worker
1175*6236dae4SAndroid Build Coastguard Worker remain_ms = timeout_ms - (int)timespent;
1176*6236dae4SAndroid Build Coastguard Worker if(cpool_shutdown_wait(cpool, remain_ms)) {
1177*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "cpool shutdown all, abort"));
1178*6236dae4SAndroid Build Coastguard Worker break;
1179*6236dae4SAndroid Build Coastguard Worker }
1180*6236dae4SAndroid Build Coastguard Worker }
1181*6236dae4SAndroid Build Coastguard Worker
1182*6236dae4SAndroid Build Coastguard Worker /* Due to errors/timeout, we might come here without being done. */
1183*6236dae4SAndroid Build Coastguard Worker cpool_shutdown_discard_all(cpool);
1184*6236dae4SAndroid Build Coastguard Worker }
1185*6236dae4SAndroid Build Coastguard Worker
1186*6236dae4SAndroid Build Coastguard Worker struct cpool_reaper_ctx {
1187*6236dae4SAndroid Build Coastguard Worker struct curltime now;
1188*6236dae4SAndroid Build Coastguard Worker };
1189*6236dae4SAndroid Build Coastguard Worker
cpool_reap_dead_cb(struct Curl_easy * data,struct connectdata * conn,void * param)1190*6236dae4SAndroid Build Coastguard Worker static int cpool_reap_dead_cb(struct Curl_easy *data,
1191*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, void *param)
1192*6236dae4SAndroid Build Coastguard Worker {
1193*6236dae4SAndroid Build Coastguard Worker struct cpool_reaper_ctx *rctx = param;
1194*6236dae4SAndroid Build Coastguard Worker if(Curl_conn_seems_dead(conn, data, &rctx->now)) {
1195*6236dae4SAndroid Build Coastguard Worker /* stop the iteration here, pass back the connection that was pruned */
1196*6236dae4SAndroid Build Coastguard Worker Curl_cpool_disconnect(data, conn, FALSE);
1197*6236dae4SAndroid Build Coastguard Worker return 1;
1198*6236dae4SAndroid Build Coastguard Worker }
1199*6236dae4SAndroid Build Coastguard Worker return 0; /* continue iteration */
1200*6236dae4SAndroid Build Coastguard Worker }
1201*6236dae4SAndroid Build Coastguard Worker
1202*6236dae4SAndroid Build Coastguard Worker /*
1203*6236dae4SAndroid Build Coastguard Worker * This function scans the data's connection pool for half-open/dead
1204*6236dae4SAndroid Build Coastguard Worker * connections, closes and removes them.
1205*6236dae4SAndroid Build Coastguard Worker * The cleanup is done at most once per second.
1206*6236dae4SAndroid Build Coastguard Worker *
1207*6236dae4SAndroid Build Coastguard Worker * When called, this transfer has no connection attached.
1208*6236dae4SAndroid Build Coastguard Worker */
Curl_cpool_prune_dead(struct Curl_easy * data)1209*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_prune_dead(struct Curl_easy *data)
1210*6236dae4SAndroid Build Coastguard Worker {
1211*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
1212*6236dae4SAndroid Build Coastguard Worker struct cpool_reaper_ctx rctx;
1213*6236dae4SAndroid Build Coastguard Worker timediff_t elapsed;
1214*6236dae4SAndroid Build Coastguard Worker
1215*6236dae4SAndroid Build Coastguard Worker if(!cpool)
1216*6236dae4SAndroid Build Coastguard Worker return;
1217*6236dae4SAndroid Build Coastguard Worker
1218*6236dae4SAndroid Build Coastguard Worker rctx.now = Curl_now();
1219*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
1220*6236dae4SAndroid Build Coastguard Worker elapsed = Curl_timediff(rctx.now, cpool->last_cleanup);
1221*6236dae4SAndroid Build Coastguard Worker
1222*6236dae4SAndroid Build Coastguard Worker if(elapsed >= 1000L) {
1223*6236dae4SAndroid Build Coastguard Worker while(cpool_foreach(data, cpool, &rctx, cpool_reap_dead_cb))
1224*6236dae4SAndroid Build Coastguard Worker ;
1225*6236dae4SAndroid Build Coastguard Worker cpool->last_cleanup = rctx.now;
1226*6236dae4SAndroid Build Coastguard Worker }
1227*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
1228*6236dae4SAndroid Build Coastguard Worker }
1229*6236dae4SAndroid Build Coastguard Worker
conn_upkeep(struct Curl_easy * data,struct connectdata * conn,void * param)1230*6236dae4SAndroid Build Coastguard Worker static int conn_upkeep(struct Curl_easy *data,
1231*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
1232*6236dae4SAndroid Build Coastguard Worker void *param)
1233*6236dae4SAndroid Build Coastguard Worker {
1234*6236dae4SAndroid Build Coastguard Worker struct curltime *now = param;
1235*6236dae4SAndroid Build Coastguard Worker /* TODO, shall we reap connections that return an error here? */
1236*6236dae4SAndroid Build Coastguard Worker Curl_conn_upkeep(data, conn, now);
1237*6236dae4SAndroid Build Coastguard Worker return 0; /* continue iteration */
1238*6236dae4SAndroid Build Coastguard Worker }
1239*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_upkeep(void * data)1240*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cpool_upkeep(void *data)
1241*6236dae4SAndroid Build Coastguard Worker {
1242*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
1243*6236dae4SAndroid Build Coastguard Worker struct curltime now = Curl_now();
1244*6236dae4SAndroid Build Coastguard Worker
1245*6236dae4SAndroid Build Coastguard Worker if(!cpool)
1246*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1247*6236dae4SAndroid Build Coastguard Worker
1248*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
1249*6236dae4SAndroid Build Coastguard Worker cpool_foreach(data, cpool, &now, conn_upkeep);
1250*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
1251*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1252*6236dae4SAndroid Build Coastguard Worker }
1253*6236dae4SAndroid Build Coastguard Worker
1254*6236dae4SAndroid Build Coastguard Worker struct cpool_find_ctx {
1255*6236dae4SAndroid Build Coastguard Worker curl_off_t id;
1256*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
1257*6236dae4SAndroid Build Coastguard Worker };
1258*6236dae4SAndroid Build Coastguard Worker
cpool_find_conn(struct Curl_easy * data,struct connectdata * conn,void * param)1259*6236dae4SAndroid Build Coastguard Worker static int cpool_find_conn(struct Curl_easy *data,
1260*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, void *param)
1261*6236dae4SAndroid Build Coastguard Worker {
1262*6236dae4SAndroid Build Coastguard Worker struct cpool_find_ctx *fctx = param;
1263*6236dae4SAndroid Build Coastguard Worker (void)data;
1264*6236dae4SAndroid Build Coastguard Worker if(conn->connection_id == fctx->id) {
1265*6236dae4SAndroid Build Coastguard Worker fctx->conn = conn;
1266*6236dae4SAndroid Build Coastguard Worker return 1;
1267*6236dae4SAndroid Build Coastguard Worker }
1268*6236dae4SAndroid Build Coastguard Worker return 0;
1269*6236dae4SAndroid Build Coastguard Worker }
1270*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_get_conn(struct Curl_easy * data,curl_off_t conn_id)1271*6236dae4SAndroid Build Coastguard Worker struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
1272*6236dae4SAndroid Build Coastguard Worker curl_off_t conn_id)
1273*6236dae4SAndroid Build Coastguard Worker {
1274*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
1275*6236dae4SAndroid Build Coastguard Worker struct cpool_find_ctx fctx;
1276*6236dae4SAndroid Build Coastguard Worker
1277*6236dae4SAndroid Build Coastguard Worker if(!cpool)
1278*6236dae4SAndroid Build Coastguard Worker return NULL;
1279*6236dae4SAndroid Build Coastguard Worker fctx.id = conn_id;
1280*6236dae4SAndroid Build Coastguard Worker fctx.conn = NULL;
1281*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
1282*6236dae4SAndroid Build Coastguard Worker cpool_foreach(cpool->idata, cpool, &fctx, cpool_find_conn);
1283*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
1284*6236dae4SAndroid Build Coastguard Worker return fctx.conn;
1285*6236dae4SAndroid Build Coastguard Worker }
1286*6236dae4SAndroid Build Coastguard Worker
1287*6236dae4SAndroid Build Coastguard Worker struct cpool_do_conn_ctx {
1288*6236dae4SAndroid Build Coastguard Worker curl_off_t id;
1289*6236dae4SAndroid Build Coastguard Worker Curl_cpool_conn_do_cb *cb;
1290*6236dae4SAndroid Build Coastguard Worker void *cbdata;
1291*6236dae4SAndroid Build Coastguard Worker };
1292*6236dae4SAndroid Build Coastguard Worker
cpool_do_conn(struct Curl_easy * data,struct connectdata * conn,void * param)1293*6236dae4SAndroid Build Coastguard Worker static int cpool_do_conn(struct Curl_easy *data,
1294*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, void *param)
1295*6236dae4SAndroid Build Coastguard Worker {
1296*6236dae4SAndroid Build Coastguard Worker struct cpool_do_conn_ctx *dctx = param;
1297*6236dae4SAndroid Build Coastguard Worker (void)data;
1298*6236dae4SAndroid Build Coastguard Worker if(conn->connection_id == dctx->id) {
1299*6236dae4SAndroid Build Coastguard Worker dctx->cb(conn, data, dctx->cbdata);
1300*6236dae4SAndroid Build Coastguard Worker return 1;
1301*6236dae4SAndroid Build Coastguard Worker }
1302*6236dae4SAndroid Build Coastguard Worker return 0;
1303*6236dae4SAndroid Build Coastguard Worker }
1304*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_do_by_id(struct Curl_easy * data,curl_off_t conn_id,Curl_cpool_conn_do_cb * cb,void * cbdata)1305*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_do_by_id(struct Curl_easy *data, curl_off_t conn_id,
1306*6236dae4SAndroid Build Coastguard Worker Curl_cpool_conn_do_cb *cb, void *cbdata)
1307*6236dae4SAndroid Build Coastguard Worker {
1308*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
1309*6236dae4SAndroid Build Coastguard Worker struct cpool_do_conn_ctx dctx;
1310*6236dae4SAndroid Build Coastguard Worker
1311*6236dae4SAndroid Build Coastguard Worker if(!cpool)
1312*6236dae4SAndroid Build Coastguard Worker return;
1313*6236dae4SAndroid Build Coastguard Worker dctx.id = conn_id;
1314*6236dae4SAndroid Build Coastguard Worker dctx.cb = cb;
1315*6236dae4SAndroid Build Coastguard Worker dctx.cbdata = cbdata;
1316*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
1317*6236dae4SAndroid Build Coastguard Worker cpool_foreach(data, cpool, &dctx, cpool_do_conn);
1318*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
1319*6236dae4SAndroid Build Coastguard Worker }
1320*6236dae4SAndroid Build Coastguard Worker
Curl_cpool_do_locked(struct Curl_easy * data,struct connectdata * conn,Curl_cpool_conn_do_cb * cb,void * cbdata)1321*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_do_locked(struct Curl_easy *data,
1322*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
1323*6236dae4SAndroid Build Coastguard Worker Curl_cpool_conn_do_cb *cb, void *cbdata)
1324*6236dae4SAndroid Build Coastguard Worker {
1325*6236dae4SAndroid Build Coastguard Worker struct cpool *cpool = cpool_get_instance(data);
1326*6236dae4SAndroid Build Coastguard Worker if(cpool) {
1327*6236dae4SAndroid Build Coastguard Worker CPOOL_LOCK(cpool);
1328*6236dae4SAndroid Build Coastguard Worker cb(conn, data, cbdata);
1329*6236dae4SAndroid Build Coastguard Worker CPOOL_UNLOCK(cpool);
1330*6236dae4SAndroid Build Coastguard Worker }
1331*6236dae4SAndroid Build Coastguard Worker else
1332*6236dae4SAndroid Build Coastguard Worker cb(conn, data, cbdata);
1333*6236dae4SAndroid Build Coastguard Worker }
1334*6236dae4SAndroid Build Coastguard Worker
1335*6236dae4SAndroid Build Coastguard Worker #if 0
1336*6236dae4SAndroid Build Coastguard Worker /* Useful for debugging the connection pool */
1337*6236dae4SAndroid Build Coastguard Worker void Curl_cpool_print(struct cpool *cpool)
1338*6236dae4SAndroid Build Coastguard Worker {
1339*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_iterator iter;
1340*6236dae4SAndroid Build Coastguard Worker struct Curl_llist_node *curr;
1341*6236dae4SAndroid Build Coastguard Worker struct Curl_hash_element *he;
1342*6236dae4SAndroid Build Coastguard Worker
1343*6236dae4SAndroid Build Coastguard Worker if(!cpool)
1344*6236dae4SAndroid Build Coastguard Worker return;
1345*6236dae4SAndroid Build Coastguard Worker
1346*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "=Bundle cache=\n");
1347*6236dae4SAndroid Build Coastguard Worker
1348*6236dae4SAndroid Build Coastguard Worker Curl_hash_start_iterate(cpool->dest2bundle, &iter);
1349*6236dae4SAndroid Build Coastguard Worker
1350*6236dae4SAndroid Build Coastguard Worker he = Curl_hash_next_element(&iter);
1351*6236dae4SAndroid Build Coastguard Worker while(he) {
1352*6236dae4SAndroid Build Coastguard Worker struct cpool_bundle *bundle;
1353*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn;
1354*6236dae4SAndroid Build Coastguard Worker
1355*6236dae4SAndroid Build Coastguard Worker bundle = he->ptr;
1356*6236dae4SAndroid Build Coastguard Worker
1357*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%s -", he->key);
1358*6236dae4SAndroid Build Coastguard Worker curr = Curl_llist_head(bundle->conns);
1359*6236dae4SAndroid Build Coastguard Worker while(curr) {
1360*6236dae4SAndroid Build Coastguard Worker conn = Curl_node_elem(curr);
1361*6236dae4SAndroid Build Coastguard Worker
1362*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount);
1363*6236dae4SAndroid Build Coastguard Worker curr = Curl_node_next(curr);
1364*6236dae4SAndroid Build Coastguard Worker }
1365*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "\n");
1366*6236dae4SAndroid Build Coastguard Worker
1367*6236dae4SAndroid Build Coastguard Worker he = Curl_hash_next_element(&iter);
1368*6236dae4SAndroid Build Coastguard Worker }
1369*6236dae4SAndroid Build Coastguard Worker }
1370*6236dae4SAndroid Build Coastguard Worker #endif
1371