xref: /curl/lib/share.c (revision 2dbe75bd)
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 "share.h"
30 #include "psl.h"
31 #include "vtls/vtls.h"
32 #include "hsts.h"
33 
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 struct Curl_share *
curl_share_init(void)40 curl_share_init(void)
41 {
42   struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
43   if(share) {
44     share->magic = CURL_GOOD_SHARE;
45     share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
46     Curl_init_dnscache(&share->hostcache, 23);
47   }
48 
49   return share;
50 }
51 
52 #undef curl_share_setopt
53 CURLSHcode
curl_share_setopt(struct Curl_share * share,CURLSHoption option,...)54 curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
55 {
56   va_list param;
57   int type;
58   curl_lock_function lockfunc;
59   curl_unlock_function unlockfunc;
60   void *ptr;
61   CURLSHcode res = CURLSHE_OK;
62 
63   if(!GOOD_SHARE_HANDLE(share))
64     return CURLSHE_INVALID;
65 
66   if(share->dirty)
67     /* don't allow setting options while one or more handles are already
68        using this share */
69     return CURLSHE_IN_USE;
70 
71   va_start(param, option);
72 
73   switch(option) {
74   case CURLSHOPT_SHARE:
75     /* this is a type this share will share */
76     type = va_arg(param, int);
77 
78     switch(type) {
79     case CURL_LOCK_DATA_DNS:
80       break;
81 
82     case CURL_LOCK_DATA_COOKIE:
83 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
84       if(!share->cookies) {
85         share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
86         if(!share->cookies)
87           res = CURLSHE_NOMEM;
88       }
89 #else   /* CURL_DISABLE_HTTP */
90       res = CURLSHE_NOT_BUILT_IN;
91 #endif
92       break;
93 
94     case CURL_LOCK_DATA_HSTS:
95 #ifndef CURL_DISABLE_HSTS
96       if(!share->hsts) {
97         share->hsts = Curl_hsts_init();
98         if(!share->hsts)
99           res = CURLSHE_NOMEM;
100       }
101 #else   /* CURL_DISABLE_HSTS */
102       res = CURLSHE_NOT_BUILT_IN;
103 #endif
104       break;
105 
106     case CURL_LOCK_DATA_SSL_SESSION:
107 #ifdef USE_SSL
108       if(!share->sslsession) {
109         share->max_ssl_sessions = 8;
110         share->sslsession = calloc(share->max_ssl_sessions,
111                                    sizeof(struct Curl_ssl_session));
112         share->sessionage = 0;
113         if(!share->sslsession)
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       if(Curl_conncache_init(&share->conn_cache, 103))
123         res = CURLSHE_NOMEM;
124       break;
125 
126     case CURL_LOCK_DATA_PSL:
127 #ifndef USE_LIBPSL
128       res = CURLSHE_NOT_BUILT_IN;
129 #endif
130       break;
131 
132     default:
133       res = CURLSHE_BAD_OPTION;
134     }
135     if(!res)
136       share->specifier |= (unsigned int)(1<<type);
137     break;
138 
139   case CURLSHOPT_UNSHARE:
140     /* this is a type this share will no longer share */
141     type = va_arg(param, int);
142     share->specifier &= ~(unsigned int)(1<<type);
143     switch(type) {
144     case CURL_LOCK_DATA_DNS:
145       break;
146 
147     case CURL_LOCK_DATA_COOKIE:
148 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
149       if(share->cookies) {
150         Curl_cookie_cleanup(share->cookies);
151         share->cookies = NULL;
152       }
153 #else   /* CURL_DISABLE_HTTP */
154       res = CURLSHE_NOT_BUILT_IN;
155 #endif
156       break;
157 
158     case CURL_LOCK_DATA_HSTS:
159 #ifndef CURL_DISABLE_HSTS
160       if(share->hsts) {
161         Curl_hsts_cleanup(&share->hsts);
162       }
163 #else   /* CURL_DISABLE_HSTS */
164       res = CURLSHE_NOT_BUILT_IN;
165 #endif
166       break;
167 
168     case CURL_LOCK_DATA_SSL_SESSION:
169 #ifdef USE_SSL
170       Curl_safefree(share->sslsession);
171 #else
172       res = CURLSHE_NOT_BUILT_IN;
173 #endif
174       break;
175 
176     case CURL_LOCK_DATA_CONNECT:
177       break;
178 
179     default:
180       res = CURLSHE_BAD_OPTION;
181       break;
182     }
183     break;
184 
185   case CURLSHOPT_LOCKFUNC:
186     lockfunc = va_arg(param, curl_lock_function);
187     share->lockfunc = lockfunc;
188     break;
189 
190   case CURLSHOPT_UNLOCKFUNC:
191     unlockfunc = va_arg(param, curl_unlock_function);
192     share->unlockfunc = unlockfunc;
193     break;
194 
195   case CURLSHOPT_USERDATA:
196     ptr = va_arg(param, void *);
197     share->clientdata = ptr;
198     break;
199 
200   default:
201     res = CURLSHE_BAD_OPTION;
202     break;
203   }
204 
205   va_end(param);
206 
207   return res;
208 }
209 
210 CURLSHcode
curl_share_cleanup(struct Curl_share * share)211 curl_share_cleanup(struct Curl_share *share)
212 {
213   if(!GOOD_SHARE_HANDLE(share))
214     return CURLSHE_INVALID;
215 
216   if(share->lockfunc)
217     share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
218                     share->clientdata);
219 
220   if(share->dirty) {
221     if(share->unlockfunc)
222       share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
223     return CURLSHE_IN_USE;
224   }
225 
226   Curl_conncache_close_all_connections(&share->conn_cache);
227   Curl_conncache_destroy(&share->conn_cache);
228   Curl_hash_destroy(&share->hostcache);
229 
230 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
231   Curl_cookie_cleanup(share->cookies);
232 #endif
233 
234 #ifndef CURL_DISABLE_HSTS
235   Curl_hsts_cleanup(&share->hsts);
236 #endif
237 
238 #ifdef USE_SSL
239   if(share->sslsession) {
240     size_t i;
241     for(i = 0; i < share->max_ssl_sessions; i++)
242       Curl_ssl_kill_session(&(share->sslsession[i]));
243     free(share->sslsession);
244   }
245 #endif
246 
247   Curl_psl_destroy(&share->psl);
248 
249   if(share->unlockfunc)
250     share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
251   share->magic = 0;
252   free(share);
253 
254   return CURLSHE_OK;
255 }
256 
257 
258 CURLSHcode
Curl_share_lock(struct Curl_easy * data,curl_lock_data type,curl_lock_access accesstype)259 Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
260                 curl_lock_access accesstype)
261 {
262   struct Curl_share *share = data->share;
263 
264   if(!share)
265     return CURLSHE_INVALID;
266 
267   if(share->specifier & (unsigned int)(1<<type)) {
268     if(share->lockfunc) /* only call this if set! */
269       share->lockfunc(data, type, accesstype, share->clientdata);
270   }
271   /* else if we don't share this, pretend successful lock */
272 
273   return CURLSHE_OK;
274 }
275 
276 CURLSHcode
Curl_share_unlock(struct Curl_easy * data,curl_lock_data type)277 Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
278 {
279   struct Curl_share *share = data->share;
280 
281   if(!share)
282     return CURLSHE_INVALID;
283 
284   if(share->specifier & (unsigned int)(1<<type)) {
285     if(share->unlockfunc) /* only call this if set! */
286       share->unlockfunc (data, type, share->clientdata);
287   }
288 
289   return CURLSHE_OK;
290 }
291