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