1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Linus Nielsen Feltzing, <linus@haxx.se>
9 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
10 *
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at https://curl.se/docs/copyright.html.
14 *
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 * SPDX-License-Identifier: curl
23 *
24 ***************************************************************************/
25
26 #include "curl_setup.h"
27
28 #include <curl/curl.h>
29
30 #include "urldata.h"
31 #include "url.h"
32 #include "cfilters.h"
33 #include "progress.h"
34 #include "multiif.h"
35 #include "sendf.h"
36 #include "conncache.h"
37 #include "http_negotiate.h"
38 #include "http_ntlm.h"
39 #include "share.h"
40 #include "sigpipe.h"
41 #include "connect.h"
42 #include "select.h"
43 #include "strcase.h"
44
45 /* The last 3 #include files should be in this order */
46 #include "curl_printf.h"
47 #include "curl_memory.h"
48 #include "memdebug.h"
49
50 #define HASHKEY_SIZE 128
51
52 static void connc_discard_conn(struct conncache *connc,
53 struct Curl_easy *last_data,
54 struct connectdata *conn,
55 bool aborted);
56 static void connc_disconnect(struct Curl_easy *data,
57 struct connectdata *conn,
58 struct conncache *connc,
59 bool do_shutdown);
60 static void connc_run_conn_shutdown(struct Curl_easy *data,
61 struct connectdata *conn,
62 bool *done);
63 static void connc_run_conn_shutdown_handler(struct Curl_easy *data,
64 struct connectdata *conn);
65 static CURLcode connc_update_shutdown_ev(struct Curl_multi *multi,
66 struct Curl_easy *data,
67 struct connectdata *conn);
68 static void connc_shutdown_all(struct conncache *connc, int timeout_ms);
69
bundle_create(struct connectbundle ** bundlep)70 static CURLcode bundle_create(struct connectbundle **bundlep)
71 {
72 DEBUGASSERT(*bundlep == NULL);
73 *bundlep = malloc(sizeof(struct connectbundle));
74 if(!*bundlep)
75 return CURLE_OUT_OF_MEMORY;
76
77 (*bundlep)->num_connections = 0;
78 (*bundlep)->multiuse = BUNDLE_UNKNOWN;
79
80 Curl_llist_init(&(*bundlep)->conn_list, NULL);
81 return CURLE_OK;
82 }
83
bundle_destroy(struct connectbundle * bundle)84 static void bundle_destroy(struct connectbundle *bundle)
85 {
86 free(bundle);
87 }
88
89 /* Add a connection to a bundle */
bundle_add_conn(struct connectbundle * bundle,struct connectdata * conn)90 static void bundle_add_conn(struct connectbundle *bundle,
91 struct connectdata *conn)
92 {
93 Curl_llist_append(&bundle->conn_list, conn, &conn->bundle_node);
94 conn->bundle = bundle;
95 bundle->num_connections++;
96 }
97
98 /* Remove a connection from a bundle */
bundle_remove_conn(struct connectbundle * bundle,struct connectdata * conn)99 static int bundle_remove_conn(struct connectbundle *bundle,
100 struct connectdata *conn)
101 {
102 struct Curl_llist_element *curr;
103
104 curr = bundle->conn_list.head;
105 while(curr) {
106 if(curr->ptr == conn) {
107 Curl_llist_remove(&bundle->conn_list, curr, NULL);
108 bundle->num_connections--;
109 conn->bundle = NULL;
110 return 1; /* we removed a handle */
111 }
112 curr = curr->next;
113 }
114 DEBUGASSERT(0);
115 return 0;
116 }
117
free_bundle_hash_entry(void * freethis)118 static void free_bundle_hash_entry(void *freethis)
119 {
120 struct connectbundle *b = (struct connectbundle *) freethis;
121
122 bundle_destroy(b);
123 }
124
Curl_conncache_init(struct conncache * connc,struct Curl_multi * multi,size_t size)125 int Curl_conncache_init(struct conncache *connc,
126 struct Curl_multi *multi, size_t size)
127 {
128 /* allocate a new easy handle to use when closing cached connections */
129 connc->closure_handle = curl_easy_init();
130 if(!connc->closure_handle)
131 return 1; /* bad */
132 connc->closure_handle->state.internal = true;
133 #ifdef DEBUGBUILD
134 if(getenv("CURL_DEBUG"))
135 connc->closure_handle->set.verbose = true;
136 #endif
137
138 Curl_hash_init(&connc->hash, size, Curl_hash_str,
139 Curl_str_key_compare, free_bundle_hash_entry);
140 connc->closure_handle->state.conn_cache = connc;
141 connc->multi = multi;
142 Curl_llist_init(&connc->shutdowns.conn_list, NULL);
143
144 return 0; /* good */
145 }
146
Curl_conncache_destroy(struct conncache * connc)147 void Curl_conncache_destroy(struct conncache *connc)
148 {
149 if(connc) {
150 Curl_hash_destroy(&connc->hash);
151 connc->multi = NULL;
152 DEBUGASSERT(!Curl_llist_count(&connc->shutdowns.conn_list));
153 }
154 }
155
156 /* creates a key to find a bundle for this connection */
hashkey(struct connectdata * conn,char * buf,size_t len)157 static void hashkey(struct connectdata *conn, char *buf, size_t len)
158 {
159 const char *hostname;
160 long port = conn->remote_port;
161 DEBUGASSERT(len >= HASHKEY_SIZE);
162 #ifndef CURL_DISABLE_PROXY
163 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
164 hostname = conn->http_proxy.host.name;
165 port = conn->primary.remote_port;
166 }
167 else
168 #endif
169 if(conn->bits.conn_to_host)
170 hostname = conn->conn_to_host.name;
171 else
172 hostname = conn->host.name;
173
174 /* put the numbers first so that the hostname gets cut off if too long */
175 #ifdef USE_IPV6
176 msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname);
177 #else
178 msnprintf(buf, len, "%ld/%s", port, hostname);
179 #endif
180 Curl_strntolower(buf, buf, len);
181 }
182
183 /* Returns number of connections currently held in the connection cache.
184 Locks/unlocks the cache itself!
185 */
Curl_conncache_size(struct Curl_easy * data)186 size_t Curl_conncache_size(struct Curl_easy *data)
187 {
188 size_t num;
189 CONNCACHE_LOCK(data);
190 num = data->state.conn_cache->num_conn;
191 CONNCACHE_UNLOCK(data);
192 return num;
193 }
194
195 /* Look up the bundle with all the connections to the same host this
196 connectdata struct is setup to use.
197
198 **NOTE**: When it returns, it holds the connection cache lock! */
199 struct connectbundle *
Curl_conncache_find_bundle(struct Curl_easy * data,struct connectdata * conn,struct conncache * connc)200 Curl_conncache_find_bundle(struct Curl_easy *data,
201 struct connectdata *conn,
202 struct conncache *connc)
203 {
204 struct connectbundle *bundle = NULL;
205 CONNCACHE_LOCK(data);
206 if(connc) {
207 char key[HASHKEY_SIZE];
208 hashkey(conn, key, sizeof(key));
209 bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
210 }
211
212 return bundle;
213 }
214
connc_add_bundle(struct conncache * connc,char * key,struct connectbundle * bundle)215 static void *connc_add_bundle(struct conncache *connc,
216 char *key, struct connectbundle *bundle)
217 {
218 return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
219 }
220
connc_remove_bundle(struct conncache * connc,struct connectbundle * bundle)221 static void connc_remove_bundle(struct conncache *connc,
222 struct connectbundle *bundle)
223 {
224 struct Curl_hash_iterator iter;
225 struct Curl_hash_element *he;
226
227 if(!connc)
228 return;
229
230 Curl_hash_start_iterate(&connc->hash, &iter);
231
232 he = Curl_hash_next_element(&iter);
233 while(he) {
234 if(he->ptr == bundle) {
235 /* The bundle is destroyed by the hash destructor function,
236 free_bundle_hash_entry() */
237 Curl_hash_delete(&connc->hash, he->key, he->key_len);
238 return;
239 }
240
241 he = Curl_hash_next_element(&iter);
242 }
243 }
244
Curl_conncache_add_conn(struct Curl_easy * data)245 CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
246 {
247 CURLcode result = CURLE_OK;
248 struct connectbundle *bundle = NULL;
249 struct connectdata *conn = data->conn;
250 struct conncache *connc = data->state.conn_cache;
251 DEBUGASSERT(conn);
252
253 /* *find_bundle() locks the connection cache */
254 bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
255 if(!bundle) {
256 char key[HASHKEY_SIZE];
257
258 result = bundle_create(&bundle);
259 if(result) {
260 goto unlock;
261 }
262
263 hashkey(conn, key, sizeof(key));
264
265 if(!connc_add_bundle(data->state.conn_cache, key, bundle)) {
266 bundle_destroy(bundle);
267 result = CURLE_OUT_OF_MEMORY;
268 goto unlock;
269 }
270 }
271
272 bundle_add_conn(bundle, conn);
273 conn->connection_id = connc->next_connection_id++;
274 connc->num_conn++;
275
276 DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". "
277 "The cache now contains %zu members",
278 conn->connection_id, connc->num_conn));
279
280 unlock:
281 CONNCACHE_UNLOCK(data);
282
283 return result;
284 }
285
connc_remove_conn(struct conncache * connc,struct connectdata * conn)286 static void connc_remove_conn(struct conncache *connc,
287 struct connectdata *conn)
288 {
289 struct connectbundle *bundle = conn->bundle;
290
291 /* The bundle pointer can be NULL, since this function can be called
292 due to a failed connection attempt, before being added to a bundle */
293 if(bundle) {
294 bundle_remove_conn(bundle, conn);
295 if(connc && bundle->num_connections == 0)
296 connc_remove_bundle(connc, bundle);
297 conn->bundle = NULL; /* removed from it */
298 if(connc)
299 connc->num_conn--;
300 }
301 }
302
303 /*
304 * Removes the connectdata object from the connection cache, but the transfer
305 * still owns this connection.
306 *
307 * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
308 * already holds the lock or not.
309 */
Curl_conncache_remove_conn(struct Curl_easy * data,struct connectdata * conn,bool lock)310 void Curl_conncache_remove_conn(struct Curl_easy *data,
311 struct connectdata *conn, bool lock)
312 {
313 struct conncache *connc = data->state.conn_cache;
314
315 if(lock)
316 CONNCACHE_LOCK(data);
317 connc_remove_conn(connc, conn);
318 if(lock)
319 CONNCACHE_UNLOCK(data);
320 if(connc)
321 DEBUGF(infof(data, "The cache now contains %zu members",
322 connc->num_conn));
323 }
324
325 /* This function iterates the entire connection cache and calls the function
326 func() with the connection pointer as the first argument and the supplied
327 'param' argument as the other.
328
329 The conncache lock is still held when the callback is called. It needs it,
330 so that it can safely continue traversing the lists once the callback
331 returns.
332
333 Returns 1 if the loop was aborted due to the callback's return code.
334
335 Return 0 from func() to continue the loop, return 1 to abort it.
336 */
Curl_conncache_foreach(struct Curl_easy * data,struct conncache * connc,void * param,int (* func)(struct Curl_easy * data,struct connectdata * conn,void * param))337 bool Curl_conncache_foreach(struct Curl_easy *data,
338 struct conncache *connc,
339 void *param,
340 int (*func)(struct Curl_easy *data,
341 struct connectdata *conn, void *param))
342 {
343 struct Curl_hash_iterator iter;
344 struct Curl_llist_element *curr;
345 struct Curl_hash_element *he;
346
347 if(!connc)
348 return FALSE;
349
350 CONNCACHE_LOCK(data);
351 Curl_hash_start_iterate(&connc->hash, &iter);
352
353 he = Curl_hash_next_element(&iter);
354 while(he) {
355 struct connectbundle *bundle;
356
357 bundle = he->ptr;
358 he = Curl_hash_next_element(&iter);
359
360 curr = bundle->conn_list.head;
361 while(curr) {
362 /* Yes, we need to update curr before calling func(), because func()
363 might decide to remove the connection */
364 struct connectdata *conn = curr->ptr;
365 curr = curr->next;
366
367 if(1 == func(data, conn, param)) {
368 CONNCACHE_UNLOCK(data);
369 return TRUE;
370 }
371 }
372 }
373 CONNCACHE_UNLOCK(data);
374 return FALSE;
375 }
376
377 /* Return the first connection found in the cache. Used when closing all
378 connections.
379
380 NOTE: no locking is done here as this is presumably only done when cleaning
381 up a cache!
382 */
383 static struct connectdata *
connc_find_first_connection(struct conncache * connc)384 connc_find_first_connection(struct conncache *connc)
385 {
386 struct Curl_hash_iterator iter;
387 struct Curl_hash_element *he;
388 struct connectbundle *bundle;
389
390 Curl_hash_start_iterate(&connc->hash, &iter);
391
392 he = Curl_hash_next_element(&iter);
393 while(he) {
394 struct Curl_llist_element *curr;
395 bundle = he->ptr;
396
397 curr = bundle->conn_list.head;
398 if(curr) {
399 return curr->ptr;
400 }
401
402 he = Curl_hash_next_element(&iter);
403 }
404
405 return NULL;
406 }
407
408 /*
409 * Give ownership of a connection back to the connection cache. Might
410 * disconnect the oldest existing in there to make space.
411 *
412 * Return TRUE if stored, FALSE if closed.
413 */
Curl_conncache_return_conn(struct Curl_easy * data,struct connectdata * conn)414 bool Curl_conncache_return_conn(struct Curl_easy *data,
415 struct connectdata *conn)
416 {
417 unsigned int maxconnects = !data->multi->maxconnects ?
418 data->multi->num_easy * 4: data->multi->maxconnects;
419 struct connectdata *conn_candidate = NULL;
420
421 conn->lastused = Curl_now(); /* it was used up until now */
422 if(maxconnects && Curl_conncache_size(data) > maxconnects) {
423 infof(data, "Connection cache is full, closing the oldest one");
424
425 conn_candidate = Curl_conncache_extract_oldest(data);
426 if(conn_candidate) {
427 /* Use the closure handle for this disconnect so that anything that
428 happens during the disconnect is not stored and associated with the
429 'data' handle which already just finished a transfer and it is
430 important that details from this (unrelated) disconnect does not
431 taint meta-data in the data handle. */
432 struct conncache *connc = data->state.conn_cache;
433 connc_disconnect(NULL, conn_candidate, connc, TRUE);
434 }
435 }
436
437 return (conn_candidate == conn) ? FALSE : TRUE;
438
439 }
440
441 /*
442 * This function finds the connection in the connection bundle that has been
443 * unused for the longest time.
444 *
445 * Does not lock the connection cache!
446 *
447 * Returns the pointer to the oldest idle connection, or NULL if none was
448 * found.
449 */
450 struct connectdata *
Curl_conncache_extract_bundle(struct Curl_easy * data,struct connectbundle * bundle)451 Curl_conncache_extract_bundle(struct Curl_easy *data,
452 struct connectbundle *bundle)
453 {
454 struct Curl_llist_element *curr;
455 timediff_t highscore = -1;
456 timediff_t score;
457 struct curltime now;
458 struct connectdata *conn_candidate = NULL;
459 struct connectdata *conn;
460
461 (void)data;
462
463 now = Curl_now();
464
465 curr = bundle->conn_list.head;
466 while(curr) {
467 conn = curr->ptr;
468
469 if(!CONN_INUSE(conn)) {
470 /* Set higher score for the age passed since the connection was used */
471 score = Curl_timediff(now, conn->lastused);
472
473 if(score > highscore) {
474 highscore = score;
475 conn_candidate = conn;
476 }
477 }
478 curr = curr->next;
479 }
480 if(conn_candidate) {
481 /* remove it to prevent another thread from nicking it */
482 bundle_remove_conn(bundle, conn_candidate);
483 data->state.conn_cache->num_conn--;
484 DEBUGF(infof(data, "The cache now contains %zu members",
485 data->state.conn_cache->num_conn));
486 }
487
488 return conn_candidate;
489 }
490
491 /*
492 * This function finds the connection in the connection cache that has been
493 * unused for the longest time and extracts that from the bundle.
494 *
495 * Returns the pointer to the connection, or NULL if none was found.
496 */
497 struct connectdata *
Curl_conncache_extract_oldest(struct Curl_easy * data)498 Curl_conncache_extract_oldest(struct Curl_easy *data)
499 {
500 struct conncache *connc = data->state.conn_cache;
501 struct Curl_hash_iterator iter;
502 struct Curl_llist_element *curr;
503 struct Curl_hash_element *he;
504 timediff_t highscore =- 1;
505 timediff_t score;
506 struct curltime now;
507 struct connectdata *conn_candidate = NULL;
508 struct connectbundle *bundle;
509 struct connectbundle *bundle_candidate = NULL;
510
511 now = Curl_now();
512
513 CONNCACHE_LOCK(data);
514 Curl_hash_start_iterate(&connc->hash, &iter);
515
516 he = Curl_hash_next_element(&iter);
517 while(he) {
518 struct connectdata *conn;
519
520 bundle = he->ptr;
521
522 curr = bundle->conn_list.head;
523 while(curr) {
524 conn = curr->ptr;
525
526 if(!CONN_INUSE(conn) && !conn->bits.close &&
527 !conn->connect_only) {
528 /* Set higher score for the age passed since the connection was used */
529 score = Curl_timediff(now, conn->lastused);
530
531 if(score > highscore) {
532 highscore = score;
533 conn_candidate = conn;
534 bundle_candidate = bundle;
535 }
536 }
537 curr = curr->next;
538 }
539
540 he = Curl_hash_next_element(&iter);
541 }
542 if(conn_candidate) {
543 /* remove it to prevent another thread from nicking it */
544 bundle_remove_conn(bundle_candidate, conn_candidate);
545 connc->num_conn--;
546 DEBUGF(infof(data, "The cache now contains %zu members",
547 connc->num_conn));
548 }
549 CONNCACHE_UNLOCK(data);
550
551 return conn_candidate;
552 }
553
connc_shutdown_discard_all(struct conncache * connc)554 static void connc_shutdown_discard_all(struct conncache *connc)
555 {
556 struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
557 struct connectdata *conn;
558
559 if(!e)
560 return;
561
562 DEBUGF(infof(connc->closure_handle, "conncache_shutdown_discard_all"));
563 DEBUGASSERT(!connc->shutdowns.iter_locked);
564 connc->shutdowns.iter_locked = TRUE;
565 while(e) {
566 conn = e->ptr;
567 Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
568 DEBUGF(infof(connc->closure_handle, "discard connection #%"
569 CURL_FORMAT_CURL_OFF_T, conn->connection_id));
570 connc_disconnect(NULL, conn, connc, FALSE);
571 e = connc->shutdowns.conn_list.head;
572 }
573 connc->shutdowns.iter_locked = FALSE;
574 }
575
connc_close_all(struct conncache * connc)576 static void connc_close_all(struct conncache *connc)
577 {
578 struct Curl_easy *data = connc->closure_handle;
579 struct connectdata *conn;
580 int timeout_ms = 0;
581 SIGPIPE_VARIABLE(pipe_st);
582
583 if(!data)
584 return;
585
586 /* Move all connections to the shutdown list */
587 conn = connc_find_first_connection(connc);
588 while(conn) {
589 connc_remove_conn(connc, conn);
590 sigpipe_ignore(data, &pipe_st);
591 /* This will remove the connection from the cache */
592 connclose(conn, "kill all");
593 Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
594 connc_discard_conn(connc, connc->closure_handle, conn, FALSE);
595 sigpipe_restore(&pipe_st);
596
597 conn = connc_find_first_connection(connc);
598 }
599
600 /* Just for testing, run graceful shutdown */
601 #ifdef DEBUGBUILD
602 {
603 char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
604 if(p) {
605 long l = strtol(p, NULL, 10);
606 if(l > 0 && l < INT_MAX)
607 timeout_ms = (int)l;
608 }
609 }
610 #endif
611 connc_shutdown_all(connc, timeout_ms);
612
613 /* discard all connections in the shutdown list */
614 connc_shutdown_discard_all(connc);
615
616 sigpipe_ignore(data, &pipe_st);
617 Curl_hostcache_clean(data, data->dns.hostcache);
618 Curl_close(&data);
619 sigpipe_restore(&pipe_st);
620 }
621
Curl_conncache_close_all_connections(struct conncache * connc)622 void Curl_conncache_close_all_connections(struct conncache *connc)
623 {
624 connc_close_all(connc);
625 }
626
connc_shutdown_discard_oldest(struct conncache * connc)627 static void connc_shutdown_discard_oldest(struct conncache *connc)
628 {
629 struct Curl_llist_element *e;
630 struct connectdata *conn;
631 SIGPIPE_VARIABLE(pipe_st);
632
633 DEBUGASSERT(!connc->shutdowns.iter_locked);
634 if(connc->shutdowns.iter_locked)
635 return;
636
637 e = connc->shutdowns.conn_list.head;
638 if(e) {
639 conn = e->ptr;
640 Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
641 sigpipe_ignore(connc->closure_handle, &pipe_st);
642 connc_disconnect(NULL, conn, connc, FALSE);
643 sigpipe_restore(&pipe_st);
644 }
645 }
646
connc_discard_conn(struct conncache * connc,struct Curl_easy * last_data,struct connectdata * conn,bool aborted)647 static void connc_discard_conn(struct conncache *connc,
648 struct Curl_easy *last_data,
649 struct connectdata *conn,
650 bool aborted)
651 {
652 /* `last_data`, if present, is the transfer that last worked with
653 * the connection. It is present when the connection is being shut down
654 * via `Curl_conncache_discard_conn()`, e.g. when the transfer failed
655 * or does not allow connection reuse.
656 * Using the original handle is necessary for shutting down the protocol
657 * handler belonging to the connection. Protocols like 'file:' rely on
658 * being invoked to clean up their allocations in the easy handle.
659 * When a connection comes from the cache, the transfer is no longer
660 * there and we use the cache's own closure handle.
661 */
662 struct Curl_easy *data = last_data? last_data : connc->closure_handle;
663 bool done = FALSE;
664
665 DEBUGASSERT(data);
666 DEBUGASSERT(connc);
667 DEBUGASSERT(!conn->bundle);
668
669 /*
670 * If this connection isn't marked to force-close, leave it open if there
671 * are other users of it
672 */
673 if(CONN_INUSE(conn) && !aborted) {
674 DEBUGF(infof(data, "[CCACHE] not discarding #%" CURL_FORMAT_CURL_OFF_T
675 " still in use by %zu transfers", conn->connection_id,
676 CONN_INUSE(conn)));
677 return;
678 }
679
680 /* treat the connection as aborted in CONNECT_ONLY situations, we do
681 * not know what the APP did with it. */
682 if(conn->connect_only)
683 aborted = TRUE;
684 conn->bits.aborted = aborted;
685
686 /* We do not shutdown dead connections. The term 'dead' can be misleading
687 * here, as we also mark errored connections/transfers as 'dead'.
688 * If we do a shutdown for an aborted transfer, the server might think
689 * it was successful otherwise (for example an ftps: upload). This is
690 * not what we want. */
691 if(aborted)
692 done = TRUE;
693 if(!done) {
694 /* Attempt to shutdown the connection right away. */
695 Curl_attach_connection(data, conn);
696 connc_run_conn_shutdown(data, conn, &done);
697 DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
698 ", done=%d",conn->connection_id, done));
699 Curl_detach_connection(data);
700 }
701
702 if(done) {
703 connc_disconnect(data, conn, connc, FALSE);
704 return;
705 }
706
707 DEBUGASSERT(!connc->shutdowns.iter_locked);
708 if(connc->shutdowns.iter_locked) {
709 DEBUGF(infof(data, "[CCACHE] discarding #%" CURL_FORMAT_CURL_OFF_T
710 ", list locked", conn->connection_id));
711 connc_disconnect(data, conn, connc, FALSE);
712 return;
713 }
714
715 /* Add the connection to our shutdown list for non-blocking shutdown
716 * during multi processing. */
717 if(data->multi && data->multi->max_shutdown_connections > 0 &&
718 (data->multi->max_shutdown_connections >=
719 (long)Curl_llist_count(&connc->shutdowns.conn_list))) {
720 DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
721 "due to limit of %ld",
722 data->multi->max_shutdown_connections));
723 connc_shutdown_discard_oldest(connc);
724 }
725
726 if(data->multi && data->multi->socket_cb) {
727 DEBUGASSERT(connc == &data->multi->conn_cache);
728 if(connc_update_shutdown_ev(data->multi, data, conn)) {
729 DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
730 "discarding #%" CURL_FORMAT_CURL_OFF_T,
731 conn->connection_id));
732 connc_disconnect(data, conn, connc, FALSE);
733 return;
734 }
735 }
736
737 Curl_llist_append(&connc->shutdowns.conn_list, conn, &conn->bundle_node);
738 DEBUGF(infof(data, "[CCACHE] added #%" CURL_FORMAT_CURL_OFF_T
739 " to shutdown list of length %zu", conn->connection_id,
740 Curl_llist_count(&connc->shutdowns.conn_list)));
741
742 /* Forget what this transfer last polled, the connection is ours now.
743 * If we do not clear this, the event handling for `data` will tell
744 * the callback to remove the connection socket after we return here. */
745 memset(&data->last_poll, 0, sizeof(data->last_poll));
746 }
747
Curl_conncache_disconnect(struct Curl_easy * data,struct connectdata * conn,bool aborted)748 void Curl_conncache_disconnect(struct Curl_easy *data,
749 struct connectdata *conn,
750 bool aborted)
751 {
752 DEBUGASSERT(data);
753 /* Connection must no longer be in and connection cache */
754 DEBUGASSERT(!conn->bundle);
755
756 if(data->multi) {
757 /* Add it to the multi's conncache for shutdown handling */
758 infof(data, "%s connection #%" CURL_FORMAT_CURL_OFF_T,
759 aborted? "closing" : "shutting down", conn->connection_id);
760 connc_discard_conn(&data->multi->conn_cache, data, conn, aborted);
761 }
762 else {
763 /* No multi available. Make a best-effort shutdown + close */
764 infof(data, "closing connection #%" CURL_FORMAT_CURL_OFF_T,
765 conn->connection_id);
766 DEBUGASSERT(!conn->bundle);
767 connc_run_conn_shutdown_handler(data, conn);
768 connc_disconnect(data, conn, NULL, !aborted);
769 }
770 }
771
connc_run_conn_shutdown_handler(struct Curl_easy * data,struct connectdata * conn)772 static void connc_run_conn_shutdown_handler(struct Curl_easy *data,
773 struct connectdata *conn)
774 {
775 if(!conn->bits.shutdown_handler) {
776 if(conn->dns_entry) {
777 Curl_resolv_unlock(data, conn->dns_entry);
778 conn->dns_entry = NULL;
779 }
780
781 /* Cleanup NTLM connection-related data */
782 Curl_http_auth_cleanup_ntlm(conn);
783
784 /* Cleanup NEGOTIATE connection-related data */
785 Curl_http_auth_cleanup_negotiate(conn);
786
787 if(conn->handler && conn->handler->disconnect) {
788 /* This is set if protocol-specific cleanups should be made */
789 DEBUGF(infof(data, "connection #%" CURL_FORMAT_CURL_OFF_T
790 ", shutdown protocol handler (aborted=%d)",
791 conn->connection_id, conn->bits.aborted));
792 conn->handler->disconnect(data, conn, conn->bits.aborted);
793 }
794
795 /* possible left-overs from the async name resolvers */
796 Curl_resolver_cancel(data);
797
798 conn->bits.shutdown_handler = TRUE;
799 }
800 }
801
connc_run_conn_shutdown(struct Curl_easy * data,struct connectdata * conn,bool * done)802 static void connc_run_conn_shutdown(struct Curl_easy *data,
803 struct connectdata *conn,
804 bool *done)
805 {
806 CURLcode r1, r2;
807 bool done1, done2;
808
809 /* We expect to be attached when called */
810 DEBUGASSERT(data->conn == conn);
811
812 connc_run_conn_shutdown_handler(data, conn);
813
814 if(conn->bits.shutdown_filters) {
815 *done = TRUE;
816 return;
817 }
818
819 if(!conn->connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET))
820 r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1);
821 else {
822 r1 = CURLE_OK;
823 done1 = TRUE;
824 }
825
826 if(!conn->connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET))
827 r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2);
828 else {
829 r2 = CURLE_OK;
830 done2 = TRUE;
831 }
832
833 /* we are done when any failed or both report success */
834 *done = (r1 || r2 || (done1 && done2));
835 if(*done)
836 conn->bits.shutdown_filters = TRUE;
837 }
838
Curl_conncache_add_pollfds(struct conncache * connc,struct curl_pollfds * cpfds)839 CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
840 struct curl_pollfds *cpfds)
841 {
842 CURLcode result = CURLE_OK;
843
844 DEBUGASSERT(!connc->shutdowns.iter_locked);
845 connc->shutdowns.iter_locked = TRUE;
846 if(connc->shutdowns.conn_list.head) {
847 struct Curl_llist_element *e;
848 struct easy_pollset ps;
849 struct connectdata *conn;
850
851 for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
852 conn = e->ptr;
853 memset(&ps, 0, sizeof(ps));
854 Curl_attach_connection(connc->closure_handle, conn);
855 Curl_conn_adjust_pollset(connc->closure_handle, &ps);
856 Curl_detach_connection(connc->closure_handle);
857
858 result = Curl_pollfds_add_ps(cpfds, &ps);
859 if(result) {
860 Curl_pollfds_cleanup(cpfds);
861 goto out;
862 }
863 }
864 }
865 out:
866 connc->shutdowns.iter_locked = FALSE;
867 return result;
868 }
869
Curl_conncache_add_waitfds(struct conncache * connc,struct curl_waitfds * cwfds)870 CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
871 struct curl_waitfds *cwfds)
872 {
873 CURLcode result = CURLE_OK;
874
875 DEBUGASSERT(!connc->shutdowns.iter_locked);
876 connc->shutdowns.iter_locked = TRUE;
877 if(connc->shutdowns.conn_list.head) {
878 struct Curl_llist_element *e;
879 struct easy_pollset ps;
880 struct connectdata *conn;
881
882 for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
883 conn = e->ptr;
884 memset(&ps, 0, sizeof(ps));
885 Curl_attach_connection(connc->closure_handle, conn);
886 Curl_conn_adjust_pollset(connc->closure_handle, &ps);
887 Curl_detach_connection(connc->closure_handle);
888
889 result = Curl_waitfds_add_ps(cwfds, &ps);
890 if(result)
891 goto out;
892 }
893 }
894 out:
895 connc->shutdowns.iter_locked = FALSE;
896 return result;
897 }
898
connc_perform(struct conncache * connc)899 static void connc_perform(struct conncache *connc)
900 {
901 struct Curl_easy *data = connc->closure_handle;
902 struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
903 struct Curl_llist_element *enext;
904 struct connectdata *conn;
905 bool done;
906
907 if(!e)
908 return;
909
910 DEBUGASSERT(data);
911 DEBUGASSERT(!connc->shutdowns.iter_locked);
912 DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
913 Curl_llist_count(&connc->shutdowns.conn_list)));
914 connc->shutdowns.iter_locked = TRUE;
915 while(e) {
916 enext = e->next;
917 conn = e->ptr;
918 Curl_attach_connection(data, conn);
919 connc_run_conn_shutdown(data, conn, &done);
920 DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
921 ", done=%d", conn->connection_id, done));
922 Curl_detach_connection(data);
923 if(done) {
924 Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
925 connc_disconnect(NULL, conn, connc, FALSE);
926 }
927 e = enext;
928 }
929 connc->shutdowns.iter_locked = FALSE;
930 }
931
Curl_conncache_multi_perform(struct Curl_multi * multi)932 void Curl_conncache_multi_perform(struct Curl_multi *multi)
933 {
934 connc_perform(&multi->conn_cache);
935 }
936
937
938 /*
939 * Disconnects the given connection. Note the connection may not be the
940 * primary connection, like when freeing room in the connection cache or
941 * killing of a dead old connection.
942 *
943 * A connection needs an easy handle when closing down. We support this passed
944 * in separately since the connection to get closed here is often already
945 * disassociated from an easy handle.
946 *
947 * This function MUST NOT reset state in the Curl_easy struct if that
948 * isn't strictly bound to the life-time of *this* particular connection.
949 *
950 */
connc_disconnect(struct Curl_easy * data,struct connectdata * conn,struct conncache * connc,bool do_shutdown)951 static void connc_disconnect(struct Curl_easy *data,
952 struct connectdata *conn,
953 struct conncache *connc,
954 bool do_shutdown)
955 {
956 bool done;
957
958 /* there must be a connection to close */
959 DEBUGASSERT(conn);
960 /* it must be removed from the connection cache */
961 DEBUGASSERT(!conn->bundle);
962 /* there must be an associated transfer */
963 DEBUGASSERT(data || connc);
964 if(!data)
965 data = connc->closure_handle;
966
967 /* the transfer must be detached from the connection */
968 DEBUGASSERT(data && !data->conn);
969
970 if(connc && connc->multi && connc->multi->socket_cb) {
971 unsigned int i;
972 for(i = 0; i < 2; ++i) {
973 if(CURL_SOCKET_BAD == conn->sock[i])
974 continue;
975 /* remove all connection's sockets from event handling */
976 connc->multi->in_callback = TRUE;
977 connc->multi->socket_cb(data, conn->sock[i], CURL_POLL_REMOVE,
978 connc->multi->socket_userp, NULL);
979 connc->multi->in_callback = FALSE;
980 }
981 }
982
983 Curl_attach_connection(data, conn);
984
985 connc_run_conn_shutdown_handler(data, conn);
986 if(do_shutdown) {
987 /* Make a last attempt to shutdown handlers and filters, if
988 * not done so already. */
989 connc_run_conn_shutdown(data, conn, &done);
990 }
991
992 if(connc)
993 DEBUGF(infof(data, "[CCACHE] closing #%" CURL_FORMAT_CURL_OFF_T,
994 conn->connection_id));
995 else
996 DEBUGF(infof(data, "closing connection #%" CURL_FORMAT_CURL_OFF_T,
997 conn->connection_id));
998 Curl_conn_close(data, SECONDARYSOCKET);
999 Curl_conn_close(data, FIRSTSOCKET);
1000 Curl_detach_connection(data);
1001
1002 Curl_conn_free(data, conn);
1003 }
1004
1005
connc_update_shutdown_ev(struct Curl_multi * multi,struct Curl_easy * data,struct connectdata * conn)1006 static CURLcode connc_update_shutdown_ev(struct Curl_multi *multi,
1007 struct Curl_easy *data,
1008 struct connectdata *conn)
1009 {
1010 struct easy_pollset ps;
1011 unsigned int i;
1012 int rc;
1013
1014 DEBUGASSERT(data);
1015 DEBUGASSERT(multi);
1016 DEBUGASSERT(multi->socket_cb);
1017
1018 memset(&ps, 0, sizeof(ps));
1019 Curl_attach_connection(data, conn);
1020 Curl_conn_adjust_pollset(data, &ps);
1021 Curl_detach_connection(data);
1022
1023 if(!ps.num)
1024 return CURLE_FAILED_INIT;
1025
1026 for(i = 0; i < ps.num; ++i) {
1027 DEBUGF(infof(data, "[CCACHE] set socket=%" CURL_FORMAT_SOCKET_T
1028 " events=%d on #%" CURL_FORMAT_CURL_OFF_T,
1029 ps.sockets[i], ps.actions[i], conn->connection_id));
1030 multi->in_callback = TRUE;
1031 rc = multi->socket_cb(data, ps.sockets[i], ps.actions[i],
1032 multi->socket_userp, NULL);
1033 multi->in_callback = FALSE;
1034 if(rc == -1)
1035 return CURLE_FAILED_INIT;
1036 }
1037
1038 return CURLE_OK;
1039 }
1040
Curl_conncache_multi_socket(struct Curl_multi * multi,curl_socket_t s,int ev_bitmask)1041 void Curl_conncache_multi_socket(struct Curl_multi *multi,
1042 curl_socket_t s, int ev_bitmask)
1043 {
1044 struct conncache *connc = &multi->conn_cache;
1045 struct Curl_easy *data = connc->closure_handle;
1046 struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
1047 struct connectdata *conn;
1048 bool done;
1049
1050 (void)ev_bitmask;
1051 DEBUGASSERT(multi->socket_cb);
1052 if(!e)
1053 return;
1054
1055 connc->shutdowns.iter_locked = TRUE;
1056 while(e) {
1057 conn = e->ptr;
1058 if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
1059 Curl_attach_connection(data, conn);
1060 connc_run_conn_shutdown(data, conn, &done);
1061 DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
1062 ", done=%d", conn->connection_id, done));
1063 Curl_detach_connection(data);
1064 if(done || connc_update_shutdown_ev(multi, data, conn)) {
1065 Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
1066 connc_disconnect(NULL, conn, connc, FALSE);
1067 }
1068 break;
1069 }
1070 e = e->next;
1071 }
1072 connc->shutdowns.iter_locked = FALSE;
1073 }
1074
Curl_conncache_multi_close_all(struct Curl_multi * multi)1075 void Curl_conncache_multi_close_all(struct Curl_multi *multi)
1076 {
1077 connc_close_all(&multi->conn_cache);
1078 }
1079
1080
1081 #define NUM_POLLS_ON_STACK 10
1082
connc_shutdown_wait(struct conncache * connc,int timeout_ms)1083 static CURLcode connc_shutdown_wait(struct conncache *connc, int timeout_ms)
1084 {
1085 struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
1086 struct curl_pollfds cpfds;
1087 CURLcode result;
1088
1089 Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
1090
1091 result = Curl_conncache_add_pollfds(connc, &cpfds);
1092 if(result)
1093 goto out;
1094
1095 Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
1096
1097 out:
1098 Curl_pollfds_cleanup(&cpfds);
1099 return result;
1100 }
1101
connc_shutdown_all(struct conncache * connc,int timeout_ms)1102 static void connc_shutdown_all(struct conncache *connc, int timeout_ms)
1103 {
1104 struct Curl_easy *data = connc->closure_handle;
1105 struct connectdata *conn;
1106 struct curltime started = Curl_now();
1107
1108 if(!data)
1109 return;
1110 (void)data;
1111
1112 DEBUGF(infof(data, "conncache shutdown all"));
1113
1114 /* Move all connections into the shutdown queue */
1115 conn = connc_find_first_connection(connc);
1116 while(conn) {
1117 /* This will remove the connection from the cache */
1118 DEBUGF(infof(data, "moving connection %" CURL_FORMAT_CURL_OFF_T
1119 " to shutdown queue", conn->connection_id));
1120 connc_remove_conn(connc, conn);
1121 connc_discard_conn(connc, NULL, conn, FALSE);
1122 conn = connc_find_first_connection(connc);
1123 }
1124
1125 DEBUGASSERT(!connc->shutdowns.iter_locked);
1126 while(connc->shutdowns.conn_list.head) {
1127 timediff_t timespent;
1128 int remain_ms;
1129
1130 connc_perform(connc);
1131
1132 if(!connc->shutdowns.conn_list.head) {
1133 DEBUGF(infof(data, "conncache shutdown ok"));
1134 break;
1135 }
1136
1137 /* wait for activity, timeout or "nothing" */
1138 timespent = Curl_timediff(Curl_now(), started);
1139 if(timespent >= (timediff_t)timeout_ms) {
1140 DEBUGF(infof(data, "conncache shutdown %s",
1141 (timeout_ms > 0)? "timeout" : "best effort done"));
1142 break;
1143 }
1144
1145 remain_ms = timeout_ms - (int)timespent;
1146 if(connc_shutdown_wait(connc, remain_ms)) {
1147 DEBUGF(infof(data, "conncache shutdown all, abort"));
1148 break;
1149 }
1150 }
1151
1152 /* Due to errors/timeout, we might come here without being full ydone. */
1153 connc_shutdown_discard_all(connc);
1154 }
1155
1156 #if 0
1157 /* Useful for debugging the connection cache */
1158 void Curl_conncache_print(struct conncache *connc)
1159 {
1160 struct Curl_hash_iterator iter;
1161 struct Curl_llist_element *curr;
1162 struct Curl_hash_element *he;
1163
1164 if(!connc)
1165 return;
1166
1167 fprintf(stderr, "=Bundle cache=\n");
1168
1169 Curl_hash_start_iterate(connc->hash, &iter);
1170
1171 he = Curl_hash_next_element(&iter);
1172 while(he) {
1173 struct connectbundle *bundle;
1174 struct connectdata *conn;
1175
1176 bundle = he->ptr;
1177
1178 fprintf(stderr, "%s -", he->key);
1179 curr = bundle->conn_list->head;
1180 while(curr) {
1181 conn = curr->ptr;
1182
1183 fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
1184 curr = curr->next;
1185 }
1186 fprintf(stderr, "\n");
1187
1188 he = Curl_hash_next_element(&iter);
1189 }
1190 }
1191 #endif
1192