1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus (at) haxx.se> 9 * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel (at) 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 static void conn_llist_dtor(void *user, void *element) 65 { 66 struct connectdata *data = element; 67 (void)user; 68 69 data->bundle = NULL; 70 } 71 72 static CURLcode bundle_create(struct Curl_easy *data, 73 struct connectbundle **cb_ptr) 74 { 75 (void)data; 76 DEBUGASSERT(*cb_ptr == NULL); 77 *cb_ptr = malloc(sizeof(struct connectbundle)); 78 if(!*cb_ptr) 79 return CURLE_OUT_OF_MEMORY; 80 81 (*cb_ptr)->num_connections = 0; 82 (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; 83 84 Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor); 85 return CURLE_OK; 86 } 87 88 static void bundle_destroy(struct connectbundle *cb_ptr) 89 { 90 if(!cb_ptr) 91 return; 92 93 Curl_llist_destroy(&cb_ptr->conn_list, NULL); 94 95 free(cb_ptr); 96 } 97 98 /* Add a connection to a bundle */ 99 static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, 100 struct connectdata *conn) 101 { 102 Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn, 103 &conn->bundle_node); 104 conn->bundle = cb_ptr; 105 cb_ptr->num_connections++; 106 return CURLE_OK; 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 { 166 const char *hostname; 167 168 if(conn->bits.socksproxy) 169 hostname = conn->socks_proxy.host.name; 170 else if(conn->bits.httpproxy) 171 hostname = conn->http_proxy.host.name; 172 else if(conn->bits.conn_to_host) 173 hostname = conn->conn_to_host.name; 174 else 175 hostname = conn->host.name; 176 177 DEBUGASSERT(len > 32); 178 179 /* put the number first so that the hostname gets cut off if too long */ 180 snprintf(buf, len, "%ld%s", conn->port, hostname); 181 } 182 183 void Curl_conncache_unlock(struct connectdata *conn) 184 { 185 CONN_UNLOCK(conn->data); 186 } 187 188 /* Returns number of connections currently held in the connection cache. 189 Locks/unlocks the cache itself! 190 */ 191 size_t Curl_conncache_size(struct Curl_easy *data) 192 { 193 size_t num; 194 CONN_LOCK(data); 195 num = data->state.conn_cache->num_conn; 196 CONN_UNLOCK(data); 197 return num; 198 } 199 200 /* Returns number of connections currently held in the connections's bundle 201 Locks/unlocks the cache itself! 202 */ 203 size_t Curl_conncache_bundle_size(struct connectdata *conn) 204 { 205 size_t num; 206 CONN_LOCK(conn->data); 207 num = conn->bundle->num_connections; 208 CONN_UNLOCK(conn->data); 209 return num; 210 } 211 212 /* Look up the bundle with all the connections to the same host this 213 connectdata struct is setup to use. 214 215 **NOTE**: When it returns, it holds the connection cache lock! */ 216 struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, 217 struct conncache *connc) 218 { 219 struct connectbundle *bundle = NULL; 220 CONN_LOCK(conn->data); 221 if(connc) { 222 char key[128]; 223 hashkey(conn, key, sizeof(key)); 224 bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); 225 } 226 227 return bundle; 228 } 229 230 static bool conncache_add_bundle(struct conncache *connc, 231 char *key, 232 struct connectbundle *bundle) 233 { 234 void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle); 235 236 return p?TRUE:FALSE; 237 } 238 239 static void conncache_remove_bundle(struct conncache *connc, 240 struct connectbundle *bundle) 241 { 242 struct curl_hash_iterator iter; 243 struct curl_hash_element *he; 244 245 if(!connc) 246 return; 247 248 Curl_hash_start_iterate(&connc->hash, &iter); 249 250 he = Curl_hash_next_element(&iter); 251 while(he) { 252 if(he->ptr == bundle) { 253 /* The bundle is destroyed by the hash destructor function, 254 free_bundle_hash_entry() */ 255 Curl_hash_delete(&connc->hash, he->key, he->key_len); 256 return; 257 } 258 259 he = Curl_hash_next_element(&iter); 260 } 261 } 262 263 CURLcode Curl_conncache_add_conn(struct conncache *connc, 264 struct connectdata *conn) 265 { 266 CURLcode result; 267 struct connectbundle *bundle; 268 struct connectbundle *new_bundle = NULL; 269 struct Curl_easy *data = conn->data; 270 271 /* *find_bundle() locks the connection cache */ 272 bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); 273 if(!bundle) { 274 int rc; 275 char key[128]; 276 277 result = bundle_create(data, &new_bundle); 278 if(result) { 279 goto unlock; 280 } 281 282 hashkey(conn, key, sizeof(key)); 283 rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); 284 285 if(!rc) { 286 bundle_destroy(new_bundle); 287 result = CURLE_OUT_OF_MEMORY; 288 goto unlock; 289 } 290 bundle = new_bundle; 291 } 292 293 result = bundle_add_conn(bundle, conn); 294 if(result) { 295 if(new_bundle) 296 conncache_remove_bundle(data->state.conn_cache, new_bundle); 297 goto unlock; 298 } 299 300 conn->connection_id = connc->next_connection_id++; 301 connc->num_conn++; 302 303 DEBUGF(infof(conn->data, "Added connection %ld. " 304 "The cache now contains %" CURL_FORMAT_CURL_OFF_TU " members\n", 305 conn->connection_id, (curl_off_t) connc->num_conn)); 306 307 unlock: 308 CONN_UNLOCK(data); 309 310 return result; 311 } 312 313 void Curl_conncache_remove_conn(struct connectdata *conn, bool lock) 314 { 315 struct Curl_easy *data = conn->data; 316 struct connectbundle *bundle = conn->bundle; 317 struct conncache *connc = data->state.conn_cache; 318 319 /* The bundle pointer can be NULL, since this function can be called 320 due to a failed connection attempt, before being added to a bundle */ 321 if(bundle) { 322 if(lock) { 323 CONN_LOCK(conn->data); 324 } 325 bundle_remove_conn(bundle, conn); 326 if(bundle->num_connections == 0) 327 conncache_remove_bundle(connc, bundle); 328 conn->bundle = NULL; /* removed from it */ 329 if(connc) { 330 connc->num_conn--; 331 DEBUGF(infof(conn->data, "The cache now contains %" 332 CURL_FORMAT_CURL_OFF_TU " members\n", 333 (curl_off_t) connc->num_conn)); 334 } 335 if(lock) { 336 CONN_UNLOCK(conn->data); 337 } 338 } 339 } 340 341 /* This function iterates the entire connection cache and calls the function 342 func() with the connection pointer as the first argument and the supplied 343 'param' argument as the other. 344 345 The conncache lock is still held when the callback is called. It needs it, 346 so that it can safely continue traversing the lists once the callback 347 returns. 348 349 Returns 1 if the loop was aborted due to the callback's return code. 350 351 Return 0 from func() to continue the loop, return 1 to abort it. 352 */ 353 bool Curl_conncache_foreach(struct Curl_easy *data, 354 struct conncache *connc, 355 void *param, 356 int (*func)(struct connectdata *conn, void *param)) 357 { 358 struct curl_hash_iterator iter; 359 struct curl_llist_element *curr; 360 struct curl_hash_element *he; 361 362 if(!connc) 363 return FALSE; 364 365 CONN_LOCK(data); 366 Curl_hash_start_iterate(&connc->hash, &iter); 367 368 he = Curl_hash_next_element(&iter); 369 while(he) { 370 struct connectbundle *bundle; 371 372 bundle = he->ptr; 373 he = Curl_hash_next_element(&iter); 374 375 curr = bundle->conn_list.head; 376 while(curr) { 377 /* Yes, we need to update curr before calling func(), because func() 378 might decide to remove the connection */ 379 struct connectdata *conn = curr->ptr; 380 curr = curr->next; 381 382 if(1 == func(conn, param)) { 383 CONN_UNLOCK(data); 384 return TRUE; 385 } 386 } 387 } 388 CONN_UNLOCK(data); 389 return FALSE; 390 } 391 392 /* Return the first connection found in the cache. Used when closing all 393 connections. 394 395 NOTE: no locking is done here as this is presumably only done when cleaning 396 up a cache! 397 */ 398 struct connectdata * 399 Curl_conncache_find_first_connection(struct conncache *connc) 400 { 401 struct curl_hash_iterator iter; 402 struct curl_hash_element *he; 403 struct connectbundle *bundle; 404 405 Curl_hash_start_iterate(&connc->hash, &iter); 406 407 he = Curl_hash_next_element(&iter); 408 while(he) { 409 struct curl_llist_element *curr; 410 bundle = he->ptr; 411 412 curr = bundle->conn_list.head; 413 if(curr) { 414 return curr->ptr; 415 } 416 417 he = Curl_hash_next_element(&iter); 418 } 419 420 return NULL; 421 } 422 423 /* 424 * Give ownership of a connection back to the connection cache. Might 425 * disconnect the oldest existing in there to make space. 426 * 427 * Return TRUE if stored, FALSE if closed. 428 */ 429 bool Curl_conncache_return_conn(struct connectdata *conn) 430 { 431 struct Curl_easy *data = conn->data; 432 433 /* data->multi->maxconnects can be negative, deal with it. */ 434 size_t maxconnects = 435 (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: 436 data->multi->maxconnects; 437 struct connectdata *conn_candidate = NULL; 438 439 if(maxconnects > 0 && 440 Curl_conncache_size(data) > maxconnects) { 441 infof(data, "Connection cache is full, closing the oldest one.\n"); 442 443 conn_candidate = Curl_conncache_extract_oldest(data); 444 445 if(conn_candidate) { 446 /* Set the connection's owner correctly */ 447 conn_candidate->data = data; 448 449 /* the winner gets the honour of being disconnected */ 450 (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); 451 } 452 } 453 CONN_LOCK(data); 454 conn->inuse = FALSE; /* Mark the connection unused */ 455 CONN_UNLOCK(data); 456 457 return (conn_candidate == conn) ? FALSE : TRUE; 458 459 } 460 461 /* 462 * This function finds the connection in the connection bundle that has been 463 * unused for the longest time. 464 * 465 * Does not lock the connection cache! 466 * 467 * Returns the pointer to the oldest idle connection, or NULL if none was 468 * found. 469 */ 470 struct connectdata * 471 Curl_conncache_extract_bundle(struct Curl_easy *data, 472 struct connectbundle *bundle) 473 { 474 struct curl_llist_element *curr; 475 timediff_t highscore = -1; 476 timediff_t score; 477 struct curltime now; 478 struct connectdata *conn_candidate = NULL; 479 struct connectdata *conn; 480 481 (void)data; 482 483 now = Curl_now(); 484 485 curr = bundle->conn_list.head; 486 while(curr) { 487 conn = curr->ptr; 488 489 if(!conn->inuse) { 490 /* Set higher score for the age passed since the connection was used */ 491 score = Curl_timediff(now, conn->now); 492 493 if(score > highscore) { 494 highscore = score; 495 conn_candidate = conn; 496 } 497 } 498 curr = curr->next; 499 } 500 if(conn_candidate) { 501 /* remove it to prevent another thread from nicking it */ 502 bundle_remove_conn(bundle, conn_candidate); 503 data->state.conn_cache->num_conn--; 504 DEBUGF(infof(data, "The cache now contains %" 505 CURL_FORMAT_CURL_OFF_TU " members\n", 506 (curl_off_t) data->state.conn_cache->num_conn)); 507 } 508 509 return conn_candidate; 510 } 511 512 /* 513 * This function finds the connection in the connection cache that has been 514 * unused for the longest time and extracts that from the bundle. 515 * 516 * Returns the pointer to the connection, or NULL if none was found. 517 */ 518 struct connectdata * 519 Curl_conncache_extract_oldest(struct Curl_easy *data) 520 { 521 struct conncache *connc = data->state.conn_cache; 522 struct curl_hash_iterator iter; 523 struct curl_llist_element *curr; 524 struct curl_hash_element *he; 525 timediff_t highscore =- 1; 526 timediff_t score; 527 struct curltime now; 528 struct connectdata *conn_candidate = NULL; 529 struct connectbundle *bundle; 530 struct connectbundle *bundle_candidate = NULL; 531 532 now = Curl_now(); 533 534 CONN_LOCK(data); 535 Curl_hash_start_iterate(&connc->hash, &iter); 536 537 he = Curl_hash_next_element(&iter); 538 while(he) { 539 struct connectdata *conn; 540 541 bundle = he->ptr; 542 543 curr = bundle->conn_list.head; 544 while(curr) { 545 conn = curr->ptr; 546 547 if(!conn->inuse) { 548 /* Set higher score for the age passed since the connection was used */ 549 score = Curl_timediff(now, conn->now); 550 551 if(score > highscore) { 552 highscore = score; 553 conn_candidate = conn; 554 bundle_candidate = bundle; 555 } 556 } 557 curr = curr->next; 558 } 559 560 he = Curl_hash_next_element(&iter); 561 } 562 if(conn_candidate) { 563 /* remove it to prevent another thread from nicking it */ 564 bundle_remove_conn(bundle_candidate, conn_candidate); 565 connc->num_conn--; 566 DEBUGF(infof(data, "The cache now contains %" 567 CURL_FORMAT_CURL_OFF_TU " members\n", 568 (curl_off_t) connc->num_conn)); 569 } 570 CONN_UNLOCK(data); 571 572 return conn_candidate; 573 } 574 575 void Curl_conncache_close_all_connections(struct conncache *connc) 576 { 577 struct connectdata *conn; 578 579 conn = Curl_conncache_find_first_connection(connc); 580 while(conn) { 581 SIGPIPE_VARIABLE(pipe_st); 582 conn->data = connc->closure_handle; 583 584 sigpipe_ignore(conn->data, &pipe_st); 585 conn->data->easy_conn = NULL; /* clear the easy handle's connection 586 pointer */ 587 /* This will remove the connection from the cache */ 588 connclose(conn, "kill all"); 589 (void)Curl_disconnect(conn, FALSE); 590 sigpipe_restore(&pipe_st); 591 592 conn = Curl_conncache_find_first_connection(connc); 593 } 594 595 if(connc->closure_handle) { 596 SIGPIPE_VARIABLE(pipe_st); 597 sigpipe_ignore(connc->closure_handle, &pipe_st); 598 599 Curl_hostcache_clean(connc->closure_handle, 600 connc->closure_handle->dns.hostcache); 601 Curl_close(connc->closure_handle); 602 sigpipe_restore(&pipe_st); 603 } 604 } 605 606 #if 0 607 /* Useful for debugging the connection cache */ 608 void Curl_conncache_print(struct conncache *connc) 609 { 610 struct curl_hash_iterator iter; 611 struct curl_llist_element *curr; 612 struct curl_hash_element *he; 613 614 if(!connc) 615 return; 616 617 fprintf(stderr, "=Bundle cache=\n"); 618 619 Curl_hash_start_iterate(connc->hash, &iter); 620 621 he = Curl_hash_next_element(&iter); 622 while(he) { 623 struct connectbundle *bundle; 624 struct connectdata *conn; 625 626 bundle = he->ptr; 627 628 fprintf(stderr, "%s -", he->key); 629 curr = bundle->conn_list->head; 630 while(curr) { 631 conn = curr->ptr; 632 633 fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); 634 curr = curr->next; 635 } 636 fprintf(stderr, "\n"); 637 638 he = Curl_hash_next_element(&iter); 639 } 640 } 641 #endif 642