conncache.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se>
9  * Copyright (C) 2012 - 2017, 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 /* The last 3 #include files should be in this order */
35 #include "curl_printf.h"
36 #include "curl_memory.h"
37 #include "memdebug.h"
38 
39 static void conn_llist_dtor(void *user, void *element)
40 {
41  struct connectdata *data = element;
42  (void)user;
43 
44  data->bundle = NULL;
45 }
46 
48  struct connectbundle **cb_ptr)
49 {
50  (void)data;
51  DEBUGASSERT(*cb_ptr == NULL);
52  *cb_ptr = malloc(sizeof(struct connectbundle));
53  if(!*cb_ptr)
54  return CURLE_OUT_OF_MEMORY;
55 
56  (*cb_ptr)->num_connections = 0;
57  (*cb_ptr)->multiuse = BUNDLE_UNKNOWN;
58 
59  Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor);
60  return CURLE_OK;
61 }
62 
63 static void bundle_destroy(struct connectbundle *cb_ptr)
64 {
65  if(!cb_ptr)
66  return;
67 
68  Curl_llist_destroy(&cb_ptr->conn_list, NULL);
69 
70  free(cb_ptr);
71 }
72 
73 /* Add a connection to a bundle */
74 static CURLcode bundle_add_conn(struct connectbundle *cb_ptr,
75  struct connectdata *conn)
76 {
77  Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn,
78  &conn->bundle_node);
79  conn->bundle = cb_ptr;
80  cb_ptr->num_connections++;
81  return CURLE_OK;
82 }
83 
84 /* Remove a connection from a bundle */
85 static int bundle_remove_conn(struct connectbundle *cb_ptr,
86  struct connectdata *conn)
87 {
88  struct curl_llist_element *curr;
89 
90  curr = cb_ptr->conn_list.head;
91  while(curr) {
92  if(curr->ptr == conn) {
93  Curl_llist_remove(&cb_ptr->conn_list, curr, NULL);
94  cb_ptr->num_connections--;
95  conn->bundle = NULL;
96  return 1; /* we removed a handle */
97  }
98  curr = curr->next;
99  }
100  return 0;
101 }
102 
103 static void free_bundle_hash_entry(void *freethis)
104 {
105  struct connectbundle *b = (struct connectbundle *) freethis;
106 
107  bundle_destroy(b);
108 }
109 
110 int Curl_conncache_init(struct conncache *connc, int size)
111 {
112  return Curl_hash_init(&connc->hash, size, Curl_hash_str,
114 }
115 
117 {
118  if(connc)
119  Curl_hash_destroy(&connc->hash);
120 }
121 
122 /* creates a key to find a bundle for this connection */
123 static void hashkey(struct connectdata *conn, char *buf,
124  size_t len) /* something like 128 is fine */
125 {
126  const char *hostname;
127 
128  if(conn->bits.socksproxy)
129  hostname = conn->socks_proxy.host.name;
130  else if(conn->bits.httpproxy)
131  hostname = conn->http_proxy.host.name;
132  else if(conn->bits.conn_to_host)
133  hostname = conn->conn_to_host.name;
134  else
135  hostname = conn->host.name;
136 
137  DEBUGASSERT(len > 32);
138 
139  /* put the number first so that the hostname gets cut off if too long */
140  snprintf(buf, len, "%ld%s", conn->port, hostname);
141 }
142 
143 /* Look up the bundle with all the connections to the same host this
144  connectdata struct is setup to use. */
146  struct conncache *connc)
147 {
148  struct connectbundle *bundle = NULL;
149  if(connc) {
150  char key[128];
151  hashkey(conn, key, sizeof(key));
152  bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
153  }
154 
155  return bundle;
156 }
157 
158 static bool conncache_add_bundle(struct conncache *connc,
159  char *key,
160  struct connectbundle *bundle)
161 {
162  void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle);
163 
164  return p?TRUE:FALSE;
165 }
166 
167 static void conncache_remove_bundle(struct conncache *connc,
168  struct connectbundle *bundle)
169 {
170  struct curl_hash_iterator iter;
171  struct curl_hash_element *he;
172 
173  if(!connc)
174  return;
175 
176  Curl_hash_start_iterate(&connc->hash, &iter);
177 
178  he = Curl_hash_next_element(&iter);
179  while(he) {
180  if(he->ptr == bundle) {
181  /* The bundle is destroyed by the hash destructor function,
182  free_bundle_hash_entry() */
183  Curl_hash_delete(&connc->hash, he->key, he->key_len);
184  return;
185  }
186 
187  he = Curl_hash_next_element(&iter);
188  }
189 }
190 
192  struct connectdata *conn)
193 {
195  struct connectbundle *bundle;
196  struct connectbundle *new_bundle = NULL;
197  struct Curl_easy *data = conn->data;
198 
199  bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
200  if(!bundle) {
201  int rc;
202  char key[128];
203 
204  result = bundle_create(data, &new_bundle);
205  if(result)
206  return result;
207 
208  hashkey(conn, key, sizeof(key));
209  rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
210 
211  if(!rc) {
212  bundle_destroy(new_bundle);
213  return CURLE_OUT_OF_MEMORY;
214  }
215  bundle = new_bundle;
216  }
217 
218  result = bundle_add_conn(bundle, conn);
219  if(result) {
220  if(new_bundle)
221  conncache_remove_bundle(data->state.conn_cache, new_bundle);
222  return result;
223  }
224 
225  conn->connection_id = connc->next_connection_id++;
226  connc->num_connections++;
227 
228  DEBUGF(infof(conn->data, "Added connection %ld. "
229  "The cache now contains %" CURL_FORMAT_CURL_OFF_TU " members\n",
230  conn->connection_id, (curl_off_t) connc->num_connections));
231 
232  return CURLE_OK;
233 }
234 
236  struct connectdata *conn)
237 {
238  struct connectbundle *bundle = conn->bundle;
239 
240  /* The bundle pointer can be NULL, since this function can be called
241  due to a failed connection attempt, before being added to a bundle */
242  if(bundle) {
243  bundle_remove_conn(bundle, conn);
244  if(bundle->num_connections == 0) {
245  conncache_remove_bundle(connc, bundle);
246  }
247 
248  if(connc) {
249  connc->num_connections--;
250 
251  DEBUGF(infof(conn->data, "The cache now contains %"
252  CURL_FORMAT_CURL_OFF_TU " members\n",
253  (curl_off_t) connc->num_connections));
254  }
255  }
256 }
257 
258 /* This function iterates the entire connection cache and calls the
259  function func() with the connection pointer as the first argument
260  and the supplied 'param' argument as the other,
261 
262  Return 0 from func() to continue the loop, return 1 to abort it.
263  */
265  void *param,
266  int (*func)(struct connectdata *conn, void *param))
267 {
268  struct curl_hash_iterator iter;
269  struct curl_llist_element *curr;
270  struct curl_hash_element *he;
271 
272  if(!connc)
273  return;
274 
275  Curl_hash_start_iterate(&connc->hash, &iter);
276 
277  he = Curl_hash_next_element(&iter);
278  while(he) {
279  struct connectbundle *bundle;
280 
281  bundle = he->ptr;
282  he = Curl_hash_next_element(&iter);
283 
284  curr = bundle->conn_list.head;
285  while(curr) {
286  /* Yes, we need to update curr before calling func(), because func()
287  might decide to remove the connection */
288  struct connectdata *conn = curr->ptr;
289  curr = curr->next;
290 
291  if(1 == func(conn, param))
292  return;
293  }
294  }
295 }
296 
297 /* Return the first connection found in the cache. Used when closing all
298  connections */
299 struct connectdata *
301 {
302  struct curl_hash_iterator iter;
303  struct curl_hash_element *he;
304  struct connectbundle *bundle;
305 
306  Curl_hash_start_iterate(&connc->hash, &iter);
307 
308  he = Curl_hash_next_element(&iter);
309  while(he) {
310  struct curl_llist_element *curr;
311  bundle = he->ptr;
312 
313  curr = bundle->conn_list.head;
314  if(curr) {
315  return curr->ptr;
316  }
317 
318  he = Curl_hash_next_element(&iter);
319  }
320 
321  return NULL;
322 }
323 
324 
325 #if 0
326 /* Useful for debugging the connection cache */
327 void Curl_conncache_print(struct conncache *connc)
328 {
329  struct curl_hash_iterator iter;
330  struct curl_llist_element *curr;
331  struct curl_hash_element *he;
332 
333  if(!connc)
334  return;
335 
336  fprintf(stderr, "=Bundle cache=\n");
337 
338  Curl_hash_start_iterate(connc->hash, &iter);
339 
340  he = Curl_hash_next_element(&iter);
341  while(he) {
342  struct connectbundle *bundle;
343  struct connectdata *conn;
344 
345  bundle = he->ptr;
346 
347  fprintf(stderr, "%s -", he->key);
348  curr = bundle->conn_list->head;
349  while(curr) {
350  conn = curr->ptr;
351 
352  fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
353  curr = curr->next;
354  }
355  fprintf(stderr, "\n");
356 
357  he = Curl_hash_next_element(&iter);
358  }
359 }
360 #endif
#define free(ptr)
Definition: curl_memory.h:130
CURLcode Curl_conncache_add_conn(struct conncache *connc, struct connectdata *conn)
Definition: conncache.c:191
struct ConnectBits bits
Definition: urldata.h:893
int Curl_hash_init(struct curl_hash *h, int slots, hash_function hfunc, comp_function comparator, curl_hash_dtor dtor)
Definition: hash.c:57
void(* curl_llist_dtor)(void *, void *)
Definition: llist.h:28
static int bundle_remove_conn(struct connectbundle *cb_ptr, struct connectdata *conn)
Definition: conncache.c:85
void Curl_conncache_foreach(struct conncache *connc, void *param, int(*func)(struct connectdata *conn, void *param))
Definition: conncache.c:264
#define CURL_FORMAT_CURL_OFF_TU
Definition: system.h:374
struct hostname host
Definition: urldata.h:758
struct curl_hash hash
Definition: conncache.h:27
#define BUNDLE_UNKNOWN
Definition: conncache.h:34
int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
Definition: hash.c:140
#define DEBUGASSERT(x)
bool inuse
Definition: urldata.h:803
struct curl_llist_element * tail
Definition: llist.h:38
CURLcode
Definition: curl.h:454
static CURLcode bundle_create(struct Curl_easy *data, struct connectbundle **cb_ptr)
Definition: conncache.c:47
void Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
Definition: llist.c:37
static void bundle_destroy(struct connectbundle *cb_ptr)
Definition: conncache.c:63
void Curl_hash_destroy(struct curl_hash *h)
Definition: hash.c:208
struct hostname host
Definition: urldata.h:833
static bool conncache_add_bundle(struct conncache *connc, char *key, struct connectbundle *bundle)
Definition: conncache.c:158
long next_connection_id
Definition: conncache.h:29
#define malloc(size)
Definition: curl_memory.h:124
char * name
Definition: urldata.h:444
UNITTEST_START int result
Definition: unit1304.c:49
const char ** p
Definition: unit1394.c:76
void Curl_conncache_remove_conn(struct conncache *connc, struct connectdata *conn)
Definition: conncache.c:235
size_t len
Definition: curl_sasl.c:55
struct proxy_info http_proxy
Definition: urldata.h:839
void Curl_hash_start_iterate(struct curl_hash *hash, struct curl_hash_iterator *iter)
Definition: hash.c:283
#define FALSE
struct connectbundle * Curl_conncache_find_bundle(struct connectdata *conn, struct conncache *connc)
Definition: conncache.c:145
struct curl_llist_element bundle_node
Definition: urldata.h:793
size_t key_len
Definition: hash.h:62
UNITTEST_START int rc
Definition: unit1301.c:31
size_t num_connections
Definition: conncache.h:40
void * ptr
Definition: llist.h:31
bool httpproxy
Definition: urldata.h:383
static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, struct connectdata *conn)
Definition: conncache.c:74
size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2, size_t key2_len)
Definition: hash.c:274
static void conn_llist_dtor(void *user, void *element)
Definition: conncache.c:39
void Curl_conncache_print(struct conncache *connc)
long connection_id
Definition: urldata.h:809
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition: system.h:420
static void hashkey(struct connectdata *conn, char *buf, size_t len)
Definition: conncache.c:123
Definition: curl.h:455
struct proxy_info socks_proxy
Definition: urldata.h:838
bool conn_to_host
Definition: urldata.h:378
struct curl_llist_element * head
Definition: llist.h:37
static void conncache_remove_bundle(struct conncache *connc, struct connectbundle *bundle)
Definition: conncache.c:167
char key[1]
Definition: hash.h:63
struct UrlState state
Definition: urldata.h:1769
void Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, void *user)
Definition: llist.c:93
size_t num_connections
Definition: conncache.h:28
struct hostname conn_to_host
Definition: urldata.h:835
char buf[3]
Definition: unit1398.c:32
void Curl_llist_destroy(struct curl_llist *list, void *user)
Definition: llist.c:130
struct connectbundle * bundle
Definition: urldata.h:1026
#define infof
Definition: sendf.h:44
size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
Definition: hash.c:260
static void free_bundle_hash_entry(void *freethis)
Definition: conncache.c:103
void * Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
Definition: hash.c:110
long port
Definition: urldata.h:841
void Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, const void *p, struct curl_llist_element *ne)
Definition: llist.c:57
struct curl_hash_element * Curl_hash_next_element(struct curl_hash_iterator *iter)
Definition: hash.c:292
size_t size
Definition: unit1302.c:52
#define fprintf
Definition: curl_printf.h:41
#define snprintf
Definition: curl_printf.h:42
int Curl_conncache_init(struct conncache *connc, int size)
Definition: conncache.c:110
#define TRUE
void Curl_conncache_destroy(struct conncache *connc)
Definition: conncache.c:116
struct curl_llist conn_list
Definition: conncache.h:41
bool socksproxy
Definition: urldata.h:384
struct conncache * conn_cache
Definition: urldata.h:1238
struct connectdata * Curl_conncache_find_first_connection(struct conncache *connc)
Definition: conncache.c:300
int key
Definition: unit1602.c:56
void * ptr
Definition: hash.h:61
Definition: debug.c:29
void * Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
Definition: hash.c:162
struct curl_llist_element * next
Definition: llist.h:33
#define DEBUGF(x)
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:08