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 "hsts.h"
34 #include "url.h"
35
36 /* The last 3 #include files should be in this order */
37 #include "curl_printf.h"
38 #include "curl_memory.h"
39 #include "memdebug.h"
40
41 struct Curl_share *
curl_share_init(void)42 curl_share_init(void)
43 {
44 struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
45 if(share) {
46 share->magic = CURL_GOOD_SHARE;
47 share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
48 Curl_init_dnscache(&share->hostcache, 23);
49 }
50
51 return share;
52 }
53
54 #undef curl_share_setopt
55 CURLSHcode
curl_share_setopt(struct Curl_share * share,CURLSHoption option,...)56 curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
57 {
58 va_list param;
59 int type;
60 curl_lock_function lockfunc;
61 curl_unlock_function unlockfunc;
62 void *ptr;
63 CURLSHcode res = CURLSHE_OK;
64
65 if(!GOOD_SHARE_HANDLE(share))
66 return CURLSHE_INVALID;
67
68 if(share->dirty)
69 /* do not allow setting options while one or more handles are already
70 using this share */
71 return CURLSHE_IN_USE;
72
73 va_start(param, option);
74
75 switch(option) {
76 case CURLSHOPT_SHARE:
77 /* this is a type this share will share */
78 type = va_arg(param, int);
79
80 switch(type) {
81 case CURL_LOCK_DATA_DNS:
82 break;
83
84 case CURL_LOCK_DATA_COOKIE:
85 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
86 if(!share->cookies) {
87 share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
88 if(!share->cookies)
89 res = CURLSHE_NOMEM;
90 }
91 #else /* CURL_DISABLE_HTTP */
92 res = CURLSHE_NOT_BUILT_IN;
93 #endif
94 break;
95
96 case CURL_LOCK_DATA_HSTS:
97 #ifndef CURL_DISABLE_HSTS
98 if(!share->hsts) {
99 share->hsts = Curl_hsts_init();
100 if(!share->hsts)
101 res = CURLSHE_NOMEM;
102 }
103 #else /* CURL_DISABLE_HSTS */
104 res = CURLSHE_NOT_BUILT_IN;
105 #endif
106 break;
107
108 case CURL_LOCK_DATA_SSL_SESSION:
109 #ifdef USE_SSL
110 if(!share->sslsession) {
111 share->max_ssl_sessions = 8;
112 share->sslsession = calloc(share->max_ssl_sessions,
113 sizeof(struct Curl_ssl_session));
114 share->sessionage = 0;
115 if(!share->sslsession)
116 res = CURLSHE_NOMEM;
117 }
118 #else
119 res = CURLSHE_NOT_BUILT_IN;
120 #endif
121 break;
122
123 case CURL_LOCK_DATA_CONNECT:
124 /* It is safe to set this option several times on a share. */
125 if(!share->cpool.idata) {
126 if(Curl_cpool_init(&share->cpool, Curl_on_disconnect,
127 NULL, share, 103))
128 res = CURLSHE_NOMEM;
129 }
130 break;
131
132 case CURL_LOCK_DATA_PSL:
133 #ifndef USE_LIBPSL
134 res = CURLSHE_NOT_BUILT_IN;
135 #endif
136 break;
137
138 default:
139 res = CURLSHE_BAD_OPTION;
140 }
141 if(!res)
142 share->specifier |= (unsigned int)(1 << type);
143 break;
144
145 case CURLSHOPT_UNSHARE:
146 /* this is a type this share will no longer share */
147 type = va_arg(param, int);
148 share->specifier &= ~(unsigned int)(1 << type);
149 switch(type) {
150 case CURL_LOCK_DATA_DNS:
151 break;
152
153 case CURL_LOCK_DATA_COOKIE:
154 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
155 if(share->cookies) {
156 Curl_cookie_cleanup(share->cookies);
157 share->cookies = NULL;
158 }
159 #else /* CURL_DISABLE_HTTP */
160 res = CURLSHE_NOT_BUILT_IN;
161 #endif
162 break;
163
164 case CURL_LOCK_DATA_HSTS:
165 #ifndef CURL_DISABLE_HSTS
166 if(share->hsts) {
167 Curl_hsts_cleanup(&share->hsts);
168 }
169 #else /* CURL_DISABLE_HSTS */
170 res = CURLSHE_NOT_BUILT_IN;
171 #endif
172 break;
173
174 case CURL_LOCK_DATA_SSL_SESSION:
175 #ifdef USE_SSL
176 Curl_safefree(share->sslsession);
177 #else
178 res = CURLSHE_NOT_BUILT_IN;
179 #endif
180 break;
181
182 case CURL_LOCK_DATA_CONNECT:
183 break;
184
185 default:
186 res = CURLSHE_BAD_OPTION;
187 break;
188 }
189 break;
190
191 case CURLSHOPT_LOCKFUNC:
192 lockfunc = va_arg(param, curl_lock_function);
193 share->lockfunc = lockfunc;
194 break;
195
196 case CURLSHOPT_UNLOCKFUNC:
197 unlockfunc = va_arg(param, curl_unlock_function);
198 share->unlockfunc = unlockfunc;
199 break;
200
201 case CURLSHOPT_USERDATA:
202 ptr = va_arg(param, void *);
203 share->clientdata = ptr;
204 break;
205
206 default:
207 res = CURLSHE_BAD_OPTION;
208 break;
209 }
210
211 va_end(param);
212
213 return res;
214 }
215
216 CURLSHcode
curl_share_cleanup(struct Curl_share * share)217 curl_share_cleanup(struct Curl_share *share)
218 {
219 if(!GOOD_SHARE_HANDLE(share))
220 return CURLSHE_INVALID;
221
222 if(share->lockfunc)
223 share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
224 share->clientdata);
225
226 if(share->dirty) {
227 if(share->unlockfunc)
228 share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
229 return CURLSHE_IN_USE;
230 }
231
232 if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
233 Curl_cpool_destroy(&share->cpool);
234 }
235 Curl_hash_destroy(&share->hostcache);
236
237 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
238 Curl_cookie_cleanup(share->cookies);
239 #endif
240
241 #ifndef CURL_DISABLE_HSTS
242 Curl_hsts_cleanup(&share->hsts);
243 #endif
244
245 #ifdef USE_SSL
246 if(share->sslsession) {
247 size_t i;
248 for(i = 0; i < share->max_ssl_sessions; i++)
249 Curl_ssl_kill_session(&(share->sslsession[i]));
250 free(share->sslsession);
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