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