• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #include <curl/curl.h>
28 #include "urldata.h"
29 #include "connect.h"
30 #include "share.h"
31 #include "psl.h"
32 #include "vtls/vtls.h"
33 #include "vtls/vtls_scache.h"
34 #include "hsts.h"
35 #include "url.h"
36 
37 /* The last 3 #include files should be in this order */
38 #include "curl_printf.h"
39 #include "curl_memory.h"
40 #include "memdebug.h"
41 
42 CURLSH *
curl_share_init(void)43 curl_share_init(void)
44 {
45   struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
46   if(share) {
47     share->magic = CURL_GOOD_SHARE;
48     share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
49     Curl_init_dnscache(&share->hostcache, 23);
50   }
51 
52   return share;
53 }
54 
55 #undef curl_share_setopt
56 CURLSHcode
curl_share_setopt(CURLSH * sh,CURLSHoption option,...)57 curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
58 {
59   va_list param;
60   int type;
61   curl_lock_function lockfunc;
62   curl_unlock_function unlockfunc;
63   void *ptr;
64   CURLSHcode res = CURLSHE_OK;
65   struct Curl_share *share = sh;
66 
67   if(!GOOD_SHARE_HANDLE(share))
68     return CURLSHE_INVALID;
69 
70   if(share->dirty)
71     /* do not allow setting options while one or more handles are already
72        using this share */
73     return CURLSHE_IN_USE;
74 
75   va_start(param, option);
76 
77   switch(option) {
78   case CURLSHOPT_SHARE:
79     /* this is a type this share will share */
80     type = va_arg(param, int);
81 
82     switch(type) {
83     case CURL_LOCK_DATA_DNS:
84       break;
85 
86     case CURL_LOCK_DATA_COOKIE:
87 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
88       if(!share->cookies) {
89         share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
90         if(!share->cookies)
91           res = CURLSHE_NOMEM;
92       }
93 #else   /* CURL_DISABLE_HTTP */
94       res = CURLSHE_NOT_BUILT_IN;
95 #endif
96       break;
97 
98     case CURL_LOCK_DATA_HSTS:
99 #ifndef CURL_DISABLE_HSTS
100       if(!share->hsts) {
101         share->hsts = Curl_hsts_init();
102         if(!share->hsts)
103           res = CURLSHE_NOMEM;
104       }
105 #else   /* CURL_DISABLE_HSTS */
106       res = CURLSHE_NOT_BUILT_IN;
107 #endif
108       break;
109 
110     case CURL_LOCK_DATA_SSL_SESSION:
111 #ifdef USE_SSL
112       if(!share->ssl_scache) {
113         /* There is no way (yet) for the application to configure the
114          * session cache size, shared between many transfers. As for curl
115          * itself, a high session count will impact startup time. Also, the
116          * scache is not optimized for several hundreds of peers. So,
117          * keep it at a reasonable level. */
118         if(Curl_ssl_scache_create(25, 2, &share->ssl_scache))
119           res = CURLSHE_NOMEM;
120       }
121 #else
122       res = CURLSHE_NOT_BUILT_IN;
123 #endif
124       break;
125 
126     case CURL_LOCK_DATA_CONNECT:
127       /* It is safe to set this option several times on a share. */
128       if(!share->cpool.idata) {
129         if(Curl_cpool_init(&share->cpool, Curl_on_disconnect,
130                            NULL, share, 103))
131           res = CURLSHE_NOMEM;
132       }
133       break;
134 
135     case CURL_LOCK_DATA_PSL:
136 #ifndef USE_LIBPSL
137       res = CURLSHE_NOT_BUILT_IN;
138 #endif
139       break;
140 
141     default:
142       res = CURLSHE_BAD_OPTION;
143     }
144     if(!res)
145       share->specifier |= (unsigned int)(1 << type);
146     break;
147 
148   case CURLSHOPT_UNSHARE:
149     /* this is a type this share will no longer share */
150     type = va_arg(param, int);
151     share->specifier &= ~(unsigned int)(1 << type);
152     switch(type) {
153     case CURL_LOCK_DATA_DNS:
154       break;
155 
156     case CURL_LOCK_DATA_COOKIE:
157 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
158       if(share->cookies) {
159         Curl_cookie_cleanup(share->cookies);
160         share->cookies = NULL;
161       }
162 #else   /* CURL_DISABLE_HTTP */
163       res = CURLSHE_NOT_BUILT_IN;
164 #endif
165       break;
166 
167     case CURL_LOCK_DATA_HSTS:
168 #ifndef CURL_DISABLE_HSTS
169       if(share->hsts) {
170         Curl_hsts_cleanup(&share->hsts);
171       }
172 #else   /* CURL_DISABLE_HSTS */
173       res = CURLSHE_NOT_BUILT_IN;
174 #endif
175       break;
176 
177     case CURL_LOCK_DATA_SSL_SESSION:
178 #ifdef USE_SSL
179       if(share->ssl_scache) {
180         Curl_ssl_scache_destroy(share->ssl_scache);
181         share->ssl_scache = NULL;
182       }
183 #else
184       res = CURLSHE_NOT_BUILT_IN;
185 #endif
186       break;
187 
188     case CURL_LOCK_DATA_CONNECT:
189       break;
190 
191     default:
192       res = CURLSHE_BAD_OPTION;
193       break;
194     }
195     break;
196 
197   case CURLSHOPT_LOCKFUNC:
198     lockfunc = va_arg(param, curl_lock_function);
199     share->lockfunc = lockfunc;
200     break;
201 
202   case CURLSHOPT_UNLOCKFUNC:
203     unlockfunc = va_arg(param, curl_unlock_function);
204     share->unlockfunc = unlockfunc;
205     break;
206 
207   case CURLSHOPT_USERDATA:
208     ptr = va_arg(param, void *);
209     share->clientdata = ptr;
210     break;
211 
212   default:
213     res = CURLSHE_BAD_OPTION;
214     break;
215   }
216 
217   va_end(param);
218 
219   return res;
220 }
221 
222 CURLSHcode
curl_share_cleanup(CURLSH * sh)223 curl_share_cleanup(CURLSH *sh)
224 {
225   struct Curl_share *share = sh;
226   if(!GOOD_SHARE_HANDLE(share))
227     return CURLSHE_INVALID;
228 
229   if(share->lockfunc)
230     share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
231                     share->clientdata);
232 
233   if(share->dirty) {
234     if(share->unlockfunc)
235       share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
236     return CURLSHE_IN_USE;
237   }
238 
239   if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
240     Curl_cpool_destroy(&share->cpool);
241   }
242   Curl_hash_destroy(&share->hostcache);
243 
244 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
245   Curl_cookie_cleanup(share->cookies);
246 #endif
247 
248 #ifndef CURL_DISABLE_HSTS
249   Curl_hsts_cleanup(&share->hsts);
250 #endif
251 
252 #ifdef USE_SSL
253   if(share->ssl_scache) {
254     Curl_ssl_scache_destroy(share->ssl_scache);
255     share->ssl_scache = NULL;
256   }
257 #endif
258 
259   Curl_psl_destroy(&share->psl);
260 
261   if(share->unlockfunc)
262     share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
263   share->magic = 0;
264   free(share);
265 
266   return CURLSHE_OK;
267 }
268 
269 
270 CURLSHcode
Curl_share_lock(struct Curl_easy * data,curl_lock_data type,curl_lock_access accesstype)271 Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
272                 curl_lock_access accesstype)
273 {
274   struct Curl_share *share = data->share;
275 
276   if(!share)
277     return CURLSHE_INVALID;
278 
279   if(share->specifier & (unsigned int)(1 << type)) {
280     if(share->lockfunc) /* only call this if set! */
281       share->lockfunc(data, type, accesstype, share->clientdata);
282   }
283   /* else if we do not share this, pretend successful lock */
284 
285   return CURLSHE_OK;
286 }
287 
288 CURLSHcode
Curl_share_unlock(struct Curl_easy * data,curl_lock_data type)289 Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
290 {
291   struct Curl_share *share = data->share;
292 
293   if(!share)
294     return CURLSHE_INVALID;
295 
296   if(share->specifier & (unsigned int)(1 << type)) {
297     if(share->unlockfunc) /* only call this if set! */
298       share->unlockfunc (data, type, share->clientdata);
299   }
300 
301   return CURLSHE_OK;
302 }
303