Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/conncache.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*************************************************************************** | |
| 2 * _ _ ____ _ | |
| 3 * Project ___| | | | _ \| | | |
| 4 * / __| | | | |_) | | | |
| 5 * | (__| |_| | _ <| |___ | |
| 6 * \___|\___/|_| \_\_____| | |
| 7 * | |
| 8 * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se> | |
| 9 * Copyright (C) 2012 - 2019, 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.haxx.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 ***************************************************************************/ | |
| 23 | |
| 24 #include "curl_setup.h" | |
| 25 | |
| 26 #include <curl/curl.h> | |
| 27 | |
| 28 #include "urldata.h" | |
| 29 #include "url.h" | |
| 30 #include "progress.h" | |
| 31 #include "multiif.h" | |
| 32 #include "sendf.h" | |
| 33 #include "conncache.h" | |
| 34 #include "share.h" | |
| 35 #include "sigpipe.h" | |
| 36 #include "connect.h" | |
| 37 | |
| 38 /* The last 3 #include files should be in this order */ | |
| 39 #include "curl_printf.h" | |
| 40 #include "curl_memory.h" | |
| 41 #include "memdebug.h" | |
| 42 | |
| 43 #ifdef CURLDEBUG | |
| 44 /* the debug versions of these macros make extra certain that the lock is | |
| 45 never doubly locked or unlocked */ | |
| 46 #define CONN_LOCK(x) if((x)->share) { \ | |
| 47 Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \ | |
| 48 DEBUGASSERT(!(x)->state.conncache_lock); \ | |
| 49 (x)->state.conncache_lock = TRUE; \ | |
| 50 } | |
| 51 | |
| 52 #define CONN_UNLOCK(x) if((x)->share) { \ | |
| 53 DEBUGASSERT((x)->state.conncache_lock); \ | |
| 54 (x)->state.conncache_lock = FALSE; \ | |
| 55 Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \ | |
| 56 } | |
| 57 #else | |
| 58 #define CONN_LOCK(x) if((x)->share) \ | |
| 59 Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE) | |
| 60 #define CONN_UNLOCK(x) if((x)->share) \ | |
| 61 Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT) | |
| 62 #endif | |
| 63 | |
| 64 #define HASHKEY_SIZE 128 | |
| 65 | |
| 66 static void conn_llist_dtor(void *user, void *element) | |
| 67 { | |
| 68 struct connectdata *conn = element; | |
| 69 (void)user; | |
| 70 conn->bundle = NULL; | |
| 71 } | |
| 72 | |
| 73 static CURLcode bundle_create(struct Curl_easy *data, | |
| 74 struct connectbundle **cb_ptr) | |
| 75 { | |
| 76 (void)data; | |
| 77 DEBUGASSERT(*cb_ptr == NULL); | |
| 78 *cb_ptr = malloc(sizeof(struct connectbundle)); | |
| 79 if(!*cb_ptr) | |
| 80 return CURLE_OUT_OF_MEMORY; | |
| 81 | |
| 82 (*cb_ptr)->num_connections = 0; | |
| 83 (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; | |
| 84 | |
| 85 Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor); | |
| 86 return CURLE_OK; | |
| 87 } | |
| 88 | |
| 89 static void bundle_destroy(struct connectbundle *cb_ptr) | |
| 90 { | |
| 91 if(!cb_ptr) | |
| 92 return; | |
| 93 | |
| 94 Curl_llist_destroy(&cb_ptr->conn_list, NULL); | |
| 95 | |
| 96 free(cb_ptr); | |
| 97 } | |
| 98 | |
| 99 /* Add a connection to a bundle */ | |
| 100 static void bundle_add_conn(struct connectbundle *cb_ptr, | |
| 101 struct connectdata *conn) | |
| 102 { | |
| 103 Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn, | |
| 104 &conn->bundle_node); | |
| 105 conn->bundle = cb_ptr; | |
| 106 cb_ptr->num_connections++; | |
| 107 } | |
| 108 | |
| 109 /* Remove a connection from a bundle */ | |
| 110 static int bundle_remove_conn(struct connectbundle *cb_ptr, | |
| 111 struct connectdata *conn) | |
| 112 { | |
| 113 struct curl_llist_element *curr; | |
| 114 | |
| 115 curr = cb_ptr->conn_list.head; | |
| 116 while(curr) { | |
| 117 if(curr->ptr == conn) { | |
| 118 Curl_llist_remove(&cb_ptr->conn_list, curr, NULL); | |
| 119 cb_ptr->num_connections--; | |
| 120 conn->bundle = NULL; | |
| 121 return 1; /* we removed a handle */ | |
| 122 } | |
| 123 curr = curr->next; | |
| 124 } | |
| 125 return 0; | |
| 126 } | |
| 127 | |
| 128 static void free_bundle_hash_entry(void *freethis) | |
| 129 { | |
| 130 struct connectbundle *b = (struct connectbundle *) freethis; | |
| 131 | |
| 132 bundle_destroy(b); | |
| 133 } | |
| 134 | |
| 135 int Curl_conncache_init(struct conncache *connc, int size) | |
| 136 { | |
| 137 int rc; | |
| 138 | |
| 139 /* allocate a new easy handle to use when closing cached connections */ | |
| 140 connc->closure_handle = curl_easy_init(); | |
| 141 if(!connc->closure_handle) | |
| 142 return 1; /* bad */ | |
| 143 | |
| 144 rc = Curl_hash_init(&connc->hash, size, Curl_hash_str, | |
| 145 Curl_str_key_compare, free_bundle_hash_entry); | |
| 146 if(rc) { | |
| 147 Curl_close(connc->closure_handle); | |
| 148 connc->closure_handle = NULL; | |
| 149 } | |
| 150 else | |
| 151 connc->closure_handle->state.conn_cache = connc; | |
| 152 | |
| 153 return rc; | |
| 154 } | |
| 155 | |
| 156 void Curl_conncache_destroy(struct conncache *connc) | |
| 157 { | |
| 158 if(connc) | |
| 159 Curl_hash_destroy(&connc->hash); | |
| 160 } | |
| 161 | |
| 162 /* creates a key to find a bundle for this connection */ | |
| 163 static void hashkey(struct connectdata *conn, char *buf, | |
| 164 size_t len, /* something like 128 is fine */ | |
| 165 const char **hostp) | |
| 166 { | |
| 167 const char *hostname; | |
| 168 long port = conn->remote_port; | |
| 169 | |
| 170 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { | |
| 171 hostname = conn->http_proxy.host.name; | |
| 172 port = conn->port; | |
| 173 } | |
| 174 else if(conn->bits.conn_to_host) | |
| 175 hostname = conn->conn_to_host.name; | |
| 176 else | |
| 177 hostname = conn->host.name; | |
| 178 | |
| 179 if(hostp) | |
| 180 /* report back which name we used */ | |
| 181 *hostp = hostname; | |
| 182 | |
| 183 /* put the number first so that the hostname gets cut off if too long */ | |
| 184 msnprintf(buf, len, "%ld%s", port, hostname); | |
| 185 } | |
| 186 | |
| 187 void Curl_conncache_unlock(struct Curl_easy *data) | |
| 188 { | |
| 189 CONN_UNLOCK(data); | |
| 190 } | |
| 191 | |
| 192 /* Returns number of connections currently held in the connection cache. | |
| 193 Locks/unlocks the cache itself! | |
| 194 */ | |
| 195 size_t Curl_conncache_size(struct Curl_easy *data) | |
| 196 { | |
| 197 size_t num; | |
| 198 CONN_LOCK(data); | |
| 199 num = data->state.conn_cache->num_conn; | |
| 200 CONN_UNLOCK(data); | |
| 201 return num; | |
| 202 } | |
| 203 | |
| 204 /* Returns number of connections currently held in the connections's bundle | |
| 205 Locks/unlocks the cache itself! | |
| 206 */ | |
| 207 size_t Curl_conncache_bundle_size(struct connectdata *conn) | |
| 208 { | |
| 209 size_t num; | |
| 210 CONN_LOCK(conn->data); | |
| 211 num = conn->bundle->num_connections; | |
| 212 CONN_UNLOCK(conn->data); | |
| 213 return num; | |
| 214 } | |
| 215 | |
| 216 /* Look up the bundle with all the connections to the same host this | |
| 217 connectdata struct is setup to use. | |
| 218 | |
| 219 **NOTE**: When it returns, it holds the connection cache lock! */ | |
| 220 struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, | |
| 221 struct conncache *connc, | |
| 222 const char **hostp) | |
| 223 { | |
| 224 struct connectbundle *bundle = NULL; | |
| 225 CONN_LOCK(conn->data); | |
| 226 if(connc) { | |
| 227 char key[HASHKEY_SIZE]; | |
| 228 hashkey(conn, key, sizeof(key), hostp); | |
| 229 bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); | |
| 230 } | |
| 231 | |
| 232 return bundle; | |
| 233 } | |
| 234 | |
| 235 static bool conncache_add_bundle(struct conncache *connc, | |
| 236 char *key, | |
| 237 struct connectbundle *bundle) | |
| 238 { | |
| 239 void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle); | |
| 240 | |
| 241 return p?TRUE:FALSE; | |
| 242 } | |
| 243 | |
| 244 static void conncache_remove_bundle(struct conncache *connc, | |
| 245 struct connectbundle *bundle) | |
| 246 { | |
| 247 struct curl_hash_iterator iter; | |
| 248 struct curl_hash_element *he; | |
| 249 | |
| 250 if(!connc) | |
| 251 return; | |
| 252 | |
| 253 Curl_hash_start_iterate(&connc->hash, &iter); | |
| 254 | |
| 255 he = Curl_hash_next_element(&iter); | |
| 256 while(he) { | |
| 257 if(he->ptr == bundle) { | |
| 258 /* The bundle is destroyed by the hash destructor function, | |
| 259 free_bundle_hash_entry() */ | |
| 260 Curl_hash_delete(&connc->hash, he->key, he->key_len); | |
| 261 return; | |
| 262 } | |
| 263 | |
| 264 he = Curl_hash_next_element(&iter); | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 CURLcode Curl_conncache_add_conn(struct conncache *connc, | |
| 269 struct connectdata *conn) | |
| 270 { | |
| 271 CURLcode result = CURLE_OK; | |
| 272 struct connectbundle *bundle; | |
| 273 struct connectbundle *new_bundle = NULL; | |
| 274 struct Curl_easy *data = conn->data; | |
| 275 | |
| 276 /* *find_bundle() locks the connection cache */ | |
| 277 bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache, NULL); | |
| 278 if(!bundle) { | |
| 279 int rc; | |
| 280 char key[HASHKEY_SIZE]; | |
| 281 | |
| 282 result = bundle_create(data, &new_bundle); | |
| 283 if(result) { | |
| 284 goto unlock; | |
| 285 } | |
| 286 | |
| 287 hashkey(conn, key, sizeof(key), NULL); | |
| 288 rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); | |
| 289 | |
| 290 if(!rc) { | |
| 291 bundle_destroy(new_bundle); | |
| 292 result = CURLE_OUT_OF_MEMORY; | |
| 293 goto unlock; | |
| 294 } | |
| 295 bundle = new_bundle; | |
| 296 } | |
| 297 | |
| 298 bundle_add_conn(bundle, conn); | |
| 299 conn->connection_id = connc->next_connection_id++; | |
| 300 connc->num_conn++; | |
| 301 | |
| 302 DEBUGF(infof(conn->data, "Added connection %ld. " | |
| 303 "The cache now contains %zu members\n", | |
| 304 conn->connection_id, connc->num_conn)); | |
| 305 | |
| 306 unlock: | |
| 307 CONN_UNLOCK(data); | |
| 308 | |
| 309 return result; | |
| 310 } | |
| 311 | |
| 312 /* | |
| 313 * Removes the connectdata object from the connection cache *and* clears the | |
| 314 * ->data pointer association. Pass TRUE/FALSE in the 'lock' argument | |
| 315 * depending on if the parent function already holds the lock or not. | |
| 316 */ | |
| 317 void Curl_conncache_remove_conn(struct Curl_easy *data, | |
| 318 struct connectdata *conn, bool lock) | |
| 319 { | |
| 320 struct connectbundle *bundle = conn->bundle; | |
| 321 struct conncache *connc = data->state.conn_cache; | |
| 322 | |
| 323 /* The bundle pointer can be NULL, since this function can be called | |
| 324 due to a failed connection attempt, before being added to a bundle */ | |
| 325 if(bundle) { | |
| 326 if(lock) { | |
| 327 CONN_LOCK(data); | |
| 328 } | |
| 329 bundle_remove_conn(bundle, conn); | |
| 330 if(bundle->num_connections == 0) | |
| 331 conncache_remove_bundle(connc, bundle); | |
| 332 conn->bundle = NULL; /* removed from it */ | |
| 333 if(connc) { | |
| 334 connc->num_conn--; | |
| 335 DEBUGF(infof(data, "The cache now contains %zu members\n", | |
| 336 connc->num_conn)); | |
| 337 } | |
| 338 conn->data = NULL; /* clear the association */ | |
| 339 if(lock) { | |
| 340 CONN_UNLOCK(data); | |
| 341 } | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 /* This function iterates the entire connection cache and calls the function | |
| 346 func() with the connection pointer as the first argument and the supplied | |
| 347 'param' argument as the other. | |
| 348 | |
| 349 The conncache lock is still held when the callback is called. It needs it, | |
| 350 so that it can safely continue traversing the lists once the callback | |
| 351 returns. | |
| 352 | |
| 353 Returns 1 if the loop was aborted due to the callback's return code. | |
| 354 | |
| 355 Return 0 from func() to continue the loop, return 1 to abort it. | |
| 356 */ | |
| 357 bool Curl_conncache_foreach(struct Curl_easy *data, | |
| 358 struct conncache *connc, | |
| 359 void *param, | |
| 360 int (*func)(struct connectdata *conn, void *param)) | |
| 361 { | |
| 362 struct curl_hash_iterator iter; | |
| 363 struct curl_llist_element *curr; | |
| 364 struct curl_hash_element *he; | |
| 365 | |
| 366 if(!connc) | |
| 367 return FALSE; | |
| 368 | |
| 369 CONN_LOCK(data); | |
| 370 Curl_hash_start_iterate(&connc->hash, &iter); | |
| 371 | |
| 372 he = Curl_hash_next_element(&iter); | |
| 373 while(he) { | |
| 374 struct connectbundle *bundle; | |
| 375 | |
| 376 bundle = he->ptr; | |
| 377 he = Curl_hash_next_element(&iter); | |
| 378 | |
| 379 curr = bundle->conn_list.head; | |
| 380 while(curr) { | |
| 381 /* Yes, we need to update curr before calling func(), because func() | |
| 382 might decide to remove the connection */ | |
| 383 struct connectdata *conn = curr->ptr; | |
| 384 curr = curr->next; | |
| 385 | |
| 386 if(1 == func(conn, param)) { | |
| 387 CONN_UNLOCK(data); | |
| 388 return TRUE; | |
| 389 } | |
| 390 } | |
| 391 } | |
| 392 CONN_UNLOCK(data); | |
| 393 return FALSE; | |
| 394 } | |
| 395 | |
| 396 /* Return the first connection found in the cache. Used when closing all | |
| 397 connections. | |
| 398 | |
| 399 NOTE: no locking is done here as this is presumably only done when cleaning | |
| 400 up a cache! | |
| 401 */ | |
| 402 static struct connectdata * | |
| 403 conncache_find_first_connection(struct conncache *connc) | |
| 404 { | |
| 405 struct curl_hash_iterator iter; | |
| 406 struct curl_hash_element *he; | |
| 407 struct connectbundle *bundle; | |
| 408 | |
| 409 Curl_hash_start_iterate(&connc->hash, &iter); | |
| 410 | |
| 411 he = Curl_hash_next_element(&iter); | |
| 412 while(he) { | |
| 413 struct curl_llist_element *curr; | |
| 414 bundle = he->ptr; | |
| 415 | |
| 416 curr = bundle->conn_list.head; | |
| 417 if(curr) { | |
| 418 return curr->ptr; | |
| 419 } | |
| 420 | |
| 421 he = Curl_hash_next_element(&iter); | |
| 422 } | |
| 423 | |
| 424 return NULL; | |
| 425 } | |
| 426 | |
| 427 /* | |
| 428 * Give ownership of a connection back to the connection cache. Might | |
| 429 * disconnect the oldest existing in there to make space. | |
| 430 * | |
| 431 * Return TRUE if stored, FALSE if closed. | |
| 432 */ | |
| 433 bool Curl_conncache_return_conn(struct connectdata *conn) | |
| 434 { | |
| 435 struct Curl_easy *data = conn->data; | |
| 436 | |
| 437 /* data->multi->maxconnects can be negative, deal with it. */ | |
| 438 size_t maxconnects = | |
| 439 (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: | |
| 440 data->multi->maxconnects; | |
| 441 struct connectdata *conn_candidate = NULL; | |
| 442 | |
| 443 conn->data = NULL; /* no owner anymore */ | |
| 444 conn->lastused = Curl_now(); /* it was used up until now */ | |
| 445 if(maxconnects > 0 && | |
| 446 Curl_conncache_size(data) > maxconnects) { | |
| 447 infof(data, "Connection cache is full, closing the oldest one.\n"); | |
| 448 | |
| 449 conn_candidate = Curl_conncache_extract_oldest(data); | |
| 450 if(conn_candidate) { | |
| 451 /* the winner gets the honour of being disconnected */ | |
| 452 (void)Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE); | |
| 453 } | |
| 454 } | |
| 455 | |
| 456 return (conn_candidate == conn) ? FALSE : TRUE; | |
| 457 | |
| 458 } | |
| 459 | |
| 460 /* | |
| 461 * This function finds the connection in the connection bundle that has been | |
| 462 * unused for the longest time. | |
| 463 * | |
| 464 * Does not lock the connection cache! | |
| 465 * | |
| 466 * Returns the pointer to the oldest idle connection, or NULL if none was | |
| 467 * found. | |
| 468 */ | |
| 469 struct connectdata * | |
| 470 Curl_conncache_extract_bundle(struct Curl_easy *data, | |
| 471 struct connectbundle *bundle) | |
| 472 { | |
| 473 struct curl_llist_element *curr; | |
| 474 timediff_t highscore = -1; | |
| 475 timediff_t score; | |
| 476 struct curltime now; | |
| 477 struct connectdata *conn_candidate = NULL; | |
| 478 struct connectdata *conn; | |
| 479 | |
| 480 (void)data; | |
| 481 | |
| 482 now = Curl_now(); | |
| 483 | |
| 484 curr = bundle->conn_list.head; | |
| 485 while(curr) { | |
| 486 conn = curr->ptr; | |
| 487 | |
| 488 if(!CONN_INUSE(conn) && !conn->data) { | |
| 489 /* Set higher score for the age passed since the connection was used */ | |
| 490 score = Curl_timediff(now, conn->lastused); | |
| 491 | |
| 492 if(score > highscore) { | |
| 493 highscore = score; | |
| 494 conn_candidate = conn; | |
| 495 } | |
| 496 } | |
| 497 curr = curr->next; | |
| 498 } | |
| 499 if(conn_candidate) { | |
| 500 /* remove it to prevent another thread from nicking it */ | |
| 501 bundle_remove_conn(bundle, conn_candidate); | |
| 502 data->state.conn_cache->num_conn--; | |
| 503 DEBUGF(infof(data, "The cache now contains %zu members\n", | |
| 504 data->state.conn_cache->num_conn)); | |
| 505 conn_candidate->data = data; /* associate! */ | |
| 506 } | |
| 507 | |
| 508 return conn_candidate; | |
| 509 } | |
| 510 | |
| 511 /* | |
| 512 * This function finds the connection in the connection cache that has been | |
| 513 * unused for the longest time and extracts that from the bundle. | |
| 514 * | |
| 515 * Returns the pointer to the connection, or NULL if none was found. | |
| 516 */ | |
| 517 struct connectdata * | |
| 518 Curl_conncache_extract_oldest(struct Curl_easy *data) | |
| 519 { | |
| 520 struct conncache *connc = data->state.conn_cache; | |
| 521 struct curl_hash_iterator iter; | |
| 522 struct curl_llist_element *curr; | |
| 523 struct curl_hash_element *he; | |
| 524 timediff_t highscore =- 1; | |
| 525 timediff_t score; | |
| 526 struct curltime now; | |
| 527 struct connectdata *conn_candidate = NULL; | |
| 528 struct connectbundle *bundle; | |
| 529 struct connectbundle *bundle_candidate = NULL; | |
| 530 | |
| 531 now = Curl_now(); | |
| 532 | |
| 533 CONN_LOCK(data); | |
| 534 Curl_hash_start_iterate(&connc->hash, &iter); | |
| 535 | |
| 536 he = Curl_hash_next_element(&iter); | |
| 537 while(he) { | |
| 538 struct connectdata *conn; | |
| 539 | |
| 540 bundle = he->ptr; | |
| 541 | |
| 542 curr = bundle->conn_list.head; | |
| 543 while(curr) { | |
| 544 conn = curr->ptr; | |
| 545 | |
| 546 if(!CONN_INUSE(conn) && !conn->data) { | |
| 547 /* Set higher score for the age passed since the connection was used */ | |
| 548 score = Curl_timediff(now, conn->lastused); | |
| 549 | |
| 550 if(score > highscore) { | |
| 551 highscore = score; | |
| 552 conn_candidate = conn; | |
| 553 bundle_candidate = bundle; | |
| 554 } | |
| 555 } | |
| 556 curr = curr->next; | |
| 557 } | |
| 558 | |
| 559 he = Curl_hash_next_element(&iter); | |
| 560 } | |
| 561 if(conn_candidate) { | |
| 562 /* remove it to prevent another thread from nicking it */ | |
| 563 bundle_remove_conn(bundle_candidate, conn_candidate); | |
| 564 connc->num_conn--; | |
| 565 DEBUGF(infof(data, "The cache now contains %zu members\n", | |
| 566 connc->num_conn)); | |
| 567 conn_candidate->data = data; /* associate! */ | |
| 568 } | |
| 569 CONN_UNLOCK(data); | |
| 570 | |
| 571 return conn_candidate; | |
| 572 } | |
| 573 | |
| 574 void Curl_conncache_close_all_connections(struct conncache *connc) | |
| 575 { | |
| 576 struct connectdata *conn; | |
| 577 | |
| 578 conn = conncache_find_first_connection(connc); | |
| 579 while(conn) { | |
| 580 SIGPIPE_VARIABLE(pipe_st); | |
| 581 conn->data = connc->closure_handle; | |
| 582 | |
| 583 sigpipe_ignore(conn->data, &pipe_st); | |
| 584 /* This will remove the connection from the cache */ | |
| 585 connclose(conn, "kill all"); | |
| 586 (void)Curl_disconnect(connc->closure_handle, conn, FALSE); | |
| 587 sigpipe_restore(&pipe_st); | |
| 588 | |
| 589 conn = conncache_find_first_connection(connc); | |
| 590 } | |
| 591 | |
| 592 if(connc->closure_handle) { | |
| 593 SIGPIPE_VARIABLE(pipe_st); | |
| 594 sigpipe_ignore(connc->closure_handle, &pipe_st); | |
| 595 | |
| 596 Curl_hostcache_clean(connc->closure_handle, | |
| 597 connc->closure_handle->dns.hostcache); | |
| 598 Curl_close(connc->closure_handle); | |
| 599 sigpipe_restore(&pipe_st); | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 #if 0 | |
| 604 /* Useful for debugging the connection cache */ | |
| 605 void Curl_conncache_print(struct conncache *connc) | |
| 606 { | |
| 607 struct curl_hash_iterator iter; | |
| 608 struct curl_llist_element *curr; | |
| 609 struct curl_hash_element *he; | |
| 610 | |
| 611 if(!connc) | |
| 612 return; | |
| 613 | |
| 614 fprintf(stderr, "=Bundle cache=\n"); | |
| 615 | |
| 616 Curl_hash_start_iterate(connc->hash, &iter); | |
| 617 | |
| 618 he = Curl_hash_next_element(&iter); | |
| 619 while(he) { | |
| 620 struct connectbundle *bundle; | |
| 621 struct connectdata *conn; | |
| 622 | |
| 623 bundle = he->ptr; | |
| 624 | |
| 625 fprintf(stderr, "%s -", he->key); | |
| 626 curr = bundle->conn_list->head; | |
| 627 while(curr) { | |
| 628 conn = curr->ptr; | |
| 629 | |
| 630 fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); | |
| 631 curr = curr->next; | |
| 632 } | |
| 633 fprintf(stderr, "\n"); | |
| 634 | |
| 635 he = Curl_hash_next_element(&iter); | |
| 636 } | |
| 637 } | |
| 638 #endif |
