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