• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, 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  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #include <curl/curl.h>
26 #include "urldata.h"
27 #include "share.h"
28 #include "psl.h"
29 #include "vtls/vtls.h"
30 #include "hsts.h"
31 
32 /* The last 3 #include files should be in this order */
33 #include "curl_printf.h"
34 #include "curl_memory.h"
35 #include "memdebug.h"
36 
37 struct Curl_share *
curl_share_init(void)38 curl_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 
45     if(Curl_mk_dnscache(&share->hostcache)) {
46       free(share);
47       return NULL;
48     }
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     /* don't 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       if(Curl_conncache_init(&share->conn_cache, 103))
125         res = CURLSHE_NOMEM;
126       break;
127 
128     case CURL_LOCK_DATA_PSL:
129 #ifndef USE_LIBPSL
130       res = CURLSHE_NOT_BUILT_IN;
131 #endif
132       break;
133 
134     default:
135       res = CURLSHE_BAD_OPTION;
136     }
137     if(!res)
138       share->specifier |= (1<<type);
139     break;
140 
141   case CURLSHOPT_UNSHARE:
142     /* this is a type this share will no longer share */
143     type = va_arg(param, int);
144     share->specifier &= ~(1<<type);
145     switch(type) {
146     case CURL_LOCK_DATA_DNS:
147       break;
148 
149     case CURL_LOCK_DATA_COOKIE:
150 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
151       if(share->cookies) {
152         Curl_cookie_cleanup(share->cookies);
153         share->cookies = NULL;
154       }
155 #else   /* CURL_DISABLE_HTTP */
156       res = CURLSHE_NOT_BUILT_IN;
157 #endif
158       break;
159 
160     case CURL_LOCK_DATA_HSTS:
161 #ifndef CURL_DISABLE_HSTS
162       if(share->hsts) {
163         Curl_hsts_cleanup(&share->hsts);
164       }
165 #else   /* CURL_DISABLE_HSTS */
166       res = CURLSHE_NOT_BUILT_IN;
167 #endif
168       break;
169 
170     case CURL_LOCK_DATA_SSL_SESSION:
171 #ifdef USE_SSL
172       Curl_safefree(share->sslsession);
173 #else
174       res = CURLSHE_NOT_BUILT_IN;
175 #endif
176       break;
177 
178     case CURL_LOCK_DATA_CONNECT:
179       break;
180 
181     default:
182       res = CURLSHE_BAD_OPTION;
183       break;
184     }
185     break;
186 
187   case CURLSHOPT_LOCKFUNC:
188     lockfunc = va_arg(param, curl_lock_function);
189     share->lockfunc = lockfunc;
190     break;
191 
192   case CURLSHOPT_UNLOCKFUNC:
193     unlockfunc = va_arg(param, curl_unlock_function);
194     share->unlockfunc = unlockfunc;
195     break;
196 
197   case CURLSHOPT_USERDATA:
198     ptr = va_arg(param, void *);
199     share->clientdata = ptr;
200     break;
201 
202   default:
203     res = CURLSHE_BAD_OPTION;
204     break;
205   }
206 
207   va_end(param);
208 
209   return res;
210 }
211 
212 CURLSHcode
curl_share_cleanup(struct Curl_share * share)213 curl_share_cleanup(struct Curl_share *share)
214 {
215   if(!GOOD_SHARE_HANDLE(share))
216     return CURLSHE_INVALID;
217 
218   if(share->lockfunc)
219     share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
220                     share->clientdata);
221 
222   if(share->dirty) {
223     if(share->unlockfunc)
224       share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
225     return CURLSHE_IN_USE;
226   }
227 
228   Curl_conncache_close_all_connections(&share->conn_cache);
229   Curl_conncache_destroy(&share->conn_cache);
230   Curl_hash_destroy(&share->hostcache);
231 
232 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
233   Curl_cookie_cleanup(share->cookies);
234 #endif
235 
236 #ifndef CURL_DISABLE_HSTS
237   Curl_hsts_cleanup(&share->hsts);
238 #endif
239 
240 #ifdef USE_SSL
241   if(share->sslsession) {
242     size_t i;
243     for(i = 0; i < share->max_ssl_sessions; i++)
244       Curl_ssl_kill_session(&(share->sslsession[i]));
245     free(share->sslsession);
246   }
247 #endif
248 
249   Curl_psl_destroy(&share->psl);
250 
251   if(share->unlockfunc)
252     share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
253   share->magic = 0;
254   free(share);
255 
256   return CURLSHE_OK;
257 }
258 
259 
260 CURLSHcode
Curl_share_lock(struct Curl_easy * data,curl_lock_data type,curl_lock_access accesstype)261 Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
262                 curl_lock_access accesstype)
263 {
264   struct Curl_share *share = data->share;
265 
266   if(!share)
267     return CURLSHE_INVALID;
268 
269   if(share->specifier & (1<<type)) {
270     if(share->lockfunc) /* only call this if set! */
271       share->lockfunc(data, type, accesstype, share->clientdata);
272   }
273   /* else if we don't share this, pretend successful lock */
274 
275   return CURLSHE_OK;
276 }
277 
278 CURLSHcode
Curl_share_unlock(struct Curl_easy * data,curl_lock_data type)279 Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
280 {
281   struct Curl_share *share = data->share;
282 
283   if(!share)
284     return CURLSHE_INVALID;
285 
286   if(share->specifier & (1<<type)) {
287     if(share->unlockfunc) /* only call this if set! */
288       share->unlockfunc (data, type, share->clientdata);
289   }
290 
291   return CURLSHE_OK;
292 }
293