xref: /curl/lib/share.c (revision fa0ccd9f)
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         if(Curl_ssl_scache_create(8, 2, &share->ssl_scache))
114           res = CURLSHE_NOMEM;
115       }
116 #else
117       res = CURLSHE_NOT_BUILT_IN;
118 #endif
119       break;
120 
121     case CURL_LOCK_DATA_CONNECT:
122       /* It is safe to set this option several times on a share. */
123       if(!share->cpool.idata) {
124         if(Curl_cpool_init(&share->cpool, Curl_on_disconnect,
125                            NULL, share, 103))
126           res = CURLSHE_NOMEM;
127       }
128       break;
129 
130     case CURL_LOCK_DATA_PSL:
131 #ifndef USE_LIBPSL
132       res = CURLSHE_NOT_BUILT_IN;
133 #endif
134       break;
135 
136     default:
137       res = CURLSHE_BAD_OPTION;
138     }
139     if(!res)
140       share->specifier |= (unsigned int)(1 << type);
141     break;
142 
143   case CURLSHOPT_UNSHARE:
144     /* this is a type this share will no longer share */
145     type = va_arg(param, int);
146     share->specifier &= ~(unsigned int)(1 << type);
147     switch(type) {
148     case CURL_LOCK_DATA_DNS:
149       break;
150 
151     case CURL_LOCK_DATA_COOKIE:
152 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
153       if(share->cookies) {
154         Curl_cookie_cleanup(share->cookies);
155         share->cookies = NULL;
156       }
157 #else   /* CURL_DISABLE_HTTP */
158       res = CURLSHE_NOT_BUILT_IN;
159 #endif
160       break;
161 
162     case CURL_LOCK_DATA_HSTS:
163 #ifndef CURL_DISABLE_HSTS
164       if(share->hsts) {
165         Curl_hsts_cleanup(&share->hsts);
166       }
167 #else   /* CURL_DISABLE_HSTS */
168       res = CURLSHE_NOT_BUILT_IN;
169 #endif
170       break;
171 
172     case CURL_LOCK_DATA_SSL_SESSION:
173 #ifdef USE_SSL
174       if(share->ssl_scache) {
175         Curl_ssl_scache_destroy(share->ssl_scache);
176         share->ssl_scache = NULL;
177       }
178 #else
179       res = CURLSHE_NOT_BUILT_IN;
180 #endif
181       break;
182 
183     case CURL_LOCK_DATA_CONNECT:
184       break;
185 
186     default:
187       res = CURLSHE_BAD_OPTION;
188       break;
189     }
190     break;
191 
192   case CURLSHOPT_LOCKFUNC:
193     lockfunc = va_arg(param, curl_lock_function);
194     share->lockfunc = lockfunc;
195     break;
196 
197   case CURLSHOPT_UNLOCKFUNC:
198     unlockfunc = va_arg(param, curl_unlock_function);
199     share->unlockfunc = unlockfunc;
200     break;
201 
202   case CURLSHOPT_USERDATA:
203     ptr = va_arg(param, void *);
204     share->clientdata = ptr;
205     break;
206 
207   default:
208     res = CURLSHE_BAD_OPTION;
209     break;
210   }
211 
212   va_end(param);
213 
214   return res;
215 }
216 
217 CURLSHcode
curl_share_cleanup(CURLSH * sh)218 curl_share_cleanup(CURLSH *sh)
219 {
220   struct Curl_share *share = sh;
221   if(!GOOD_SHARE_HANDLE(share))
222     return CURLSHE_INVALID;
223 
224   if(share->lockfunc)
225     share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
226                     share->clientdata);
227 
228   if(share->dirty) {
229     if(share->unlockfunc)
230       share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
231     return CURLSHE_IN_USE;
232   }
233 
234   if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
235     Curl_cpool_destroy(&share->cpool);
236   }
237   Curl_hash_destroy(&share->hostcache);
238 
239 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
240   Curl_cookie_cleanup(share->cookies);
241 #endif
242 
243 #ifndef CURL_DISABLE_HSTS
244   Curl_hsts_cleanup(&share->hsts);
245 #endif
246 
247 #ifdef USE_SSL
248   if(share->ssl_scache) {
249     Curl_ssl_scache_destroy(share->ssl_scache);
250     share->ssl_scache = NULL;
251   }
252 #endif
253 
254   Curl_psl_destroy(&share->psl);
255 
256   if(share->unlockfunc)
257     share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
258   share->magic = 0;
259   free(share);
260 
261   return CURLSHE_OK;
262 }
263 
264 
265 CURLSHcode
Curl_share_lock(struct Curl_easy * data,curl_lock_data type,curl_lock_access accesstype)266 Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
267                 curl_lock_access accesstype)
268 {
269   struct Curl_share *share = data->share;
270 
271   if(!share)
272     return CURLSHE_INVALID;
273 
274   if(share->specifier & (unsigned int)(1 << type)) {
275     if(share->lockfunc) /* only call this if set! */
276       share->lockfunc(data, type, accesstype, share->clientdata);
277   }
278   /* else if we do not share this, pretend successful lock */
279 
280   return CURLSHE_OK;
281 }
282 
283 CURLSHcode
Curl_share_unlock(struct Curl_easy * data,curl_lock_data type)284 Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
285 {
286   struct Curl_share *share = data->share;
287 
288   if(!share)
289     return CURLSHE_INVALID;
290 
291   if(share->specifier & (unsigned int)(1 << type)) {
292     if(share->unlockfunc) /* only call this if set! */
293       share->unlockfunc (data, type, share->clientdata);
294   }
295 
296   return CURLSHE_OK;
297 }
298