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