build: make use of 76 lib/*.h renamed files
[platform/upstream/curl.git] / lib / conncache.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
9  * Copyright (C) 2012, 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 http://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 "curl_urldata.h"
29 #include "curl_url.h"
30 #include "curl_progress.h"
31 #include "curl_multiif.h"
32 #include "curl_sendf.h"
33 #include "curl_rawstr.h"
34 #include "curl_bundles.h"
35 #include "curl_conncache.h"
36
37 #include "curl_memory.h"
38 /* The last #include file should be: */
39 #include "curl_memdebug.h"
40
41 #define CONNECTION_HASH_SIZE 97
42
43 static void free_bundle_hash_entry(void *freethis)
44 {
45   struct connectbundle *b = (struct connectbundle *) freethis;
46
47   Curl_bundle_destroy(b);
48 }
49
50 struct conncache *Curl_conncache_init(conncachetype type)
51 {
52   struct conncache *connc;
53
54   connc = calloc(1, sizeof(struct conncache));
55   if(!connc)
56     return NULL;
57
58   connc->hash = Curl_hash_alloc(CONNECTION_HASH_SIZE, Curl_hash_str,
59                                 Curl_str_key_compare, free_bundle_hash_entry);
60
61   if(!connc->hash) {
62     free(connc);
63     return NULL;
64   }
65
66   connc->type = type;
67   connc->num_connections = 0;
68
69   return connc;
70 }
71
72 void Curl_conncache_destroy(struct conncache *connc)
73 {
74   if(connc) {
75     Curl_hash_destroy(connc->hash);
76     connc->hash = NULL;
77     free(connc);
78   }
79 }
80
81 struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc,
82                                                  char *hostname)
83 {
84   struct connectbundle *bundle = NULL;
85
86   if(connc)
87     bundle = Curl_hash_pick(connc->hash, hostname, strlen(hostname)+1);
88
89   return bundle;
90 }
91
92 static bool conncache_add_bundle(struct conncache *connc,
93                                  char *hostname,
94                                  struct connectbundle *bundle)
95 {
96   void *p;
97
98   p = Curl_hash_add(connc->hash, hostname, strlen(hostname)+1, bundle);
99
100   return p?TRUE:FALSE;
101 }
102
103 static void conncache_remove_bundle(struct conncache *connc,
104                                     struct connectbundle *bundle)
105 {
106   struct curl_hash_iterator iter;
107   struct curl_hash_element *he;
108
109   if(!connc)
110     return;
111
112   Curl_hash_start_iterate(connc->hash, &iter);
113
114   he = Curl_hash_next_element(&iter);
115   while(he) {
116     if(he->ptr == bundle) {
117       /* The bundle is destroyed by the hash destructor function,
118          free_bundle_hash_entry() */
119       Curl_hash_delete(connc->hash, he->key, he->key_len);
120       return;
121     }
122
123     he = Curl_hash_next_element(&iter);
124   }
125 }
126
127 CURLcode Curl_conncache_add_conn(struct conncache *connc,
128                                  struct connectdata *conn)
129 {
130   CURLcode result;
131   struct connectbundle *bundle;
132   struct connectbundle *new_bundle = NULL;
133   struct SessionHandle *data = conn->data;
134
135   bundle = Curl_conncache_find_bundle(data->state.conn_cache,
136                                       conn->host.name);
137   if(!bundle) {
138     result = Curl_bundle_create(data, &new_bundle);
139     if(result != CURLE_OK)
140       return result;
141
142     if(!conncache_add_bundle(data->state.conn_cache,
143                              conn->host.name, new_bundle)) {
144       Curl_bundle_destroy(new_bundle);
145       return CURLE_OUT_OF_MEMORY;
146     }
147     bundle = new_bundle;
148   }
149
150   result = Curl_bundle_add_conn(bundle, conn);
151   if(result != CURLE_OK) {
152     if(new_bundle)
153       conncache_remove_bundle(data->state.conn_cache, new_bundle);
154     return result;
155   }
156
157   connc->num_connections++;
158
159   return CURLE_OK;
160 }
161
162 void Curl_conncache_remove_conn(struct conncache *connc,
163                                 struct connectdata *conn)
164 {
165   struct connectbundle *bundle = conn->bundle;
166
167   /* The bundle pointer can be NULL, since this function can be called
168      due to a failed connection attempt, before being added to a bundle */
169   if(bundle) {
170     Curl_bundle_remove_conn(bundle, conn);
171     if(bundle->num_connections == 0) {
172       conncache_remove_bundle(connc, bundle);
173     }
174     connc->num_connections--;
175
176     DEBUGF(infof(conn->data, "The cache now contains %d members\n",
177                  connc->num_connections));
178   }
179 }
180
181 /* This function iterates the entire connection cache and calls the
182    function func() with the connection pointer as the first argument
183    and the supplied 'param' argument as the other,
184
185    Return 0 from func() to continue the loop, return 1 to abort it.
186  */
187 void Curl_conncache_foreach(struct conncache *connc,
188                             void *param,
189                             int (*func)(struct connectdata *conn, void *param))
190 {
191   struct curl_hash_iterator iter;
192   struct curl_llist_element *curr;
193   struct curl_hash_element *he;
194
195   if(!connc)
196     return;
197
198   Curl_hash_start_iterate(connc->hash, &iter);
199
200   he = Curl_hash_next_element(&iter);
201   while(he) {
202     struct connectbundle *bundle;
203     struct connectdata *conn;
204
205     bundle = he->ptr;
206
207     curr = bundle->conn_list->head;
208     while(curr) {
209       /* Yes, we need to update curr before calling func(), because func()
210          might decide to remove the connection */
211       conn = curr->ptr;
212       curr = curr->next;
213
214       if(1 == func(conn, param))
215         return;
216     }
217
218     he = Curl_hash_next_element(&iter);
219   }
220 }
221
222 /* Return the first connection found in the cache. Used when closing all
223    connections */
224 struct connectdata *
225 Curl_conncache_find_first_connection(struct conncache *connc)
226 {
227   struct curl_hash_iterator iter;
228   struct curl_llist_element *curr;
229   struct curl_hash_element *he;
230   struct connectbundle *bundle;
231
232   Curl_hash_start_iterate(connc->hash, &iter);
233
234   he = Curl_hash_next_element(&iter);
235   while(he) {
236     bundle = he->ptr;
237
238     curr = bundle->conn_list->head;
239     if(curr) {
240       return curr->ptr;
241     }
242
243     he = Curl_hash_next_element(&iter);
244   }
245
246   return NULL;
247 }
248
249
250 #if 0
251 /* Useful for debugging the connection cache */
252 void Curl_conncache_print(struct conncache *connc)
253 {
254   struct curl_hash_iterator iter;
255   struct curl_llist_element *curr;
256   struct curl_hash_element *he;
257
258   if(!connc)
259     return;
260
261   fprintf(stderr, "=Bundle cache=\n");
262
263   Curl_hash_start_iterate(connc->hash, &iter);
264
265   he = Curl_hash_next_element(&iter);
266   while(he) {
267     struct connectbundle *bundle;
268     struct connectdata *conn;
269
270     bundle = he->ptr;
271
272     fprintf(stderr, "%s -", he->key);
273     curr = bundle->conn_list->head;
274     while(curr) {
275       conn = curr->ptr;
276
277       fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
278       curr = curr->next;
279     }
280     fprintf(stderr, "\n");
281
282     he = Curl_hash_next_element(&iter);
283   }
284 }
285 #endif