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