xref: /third_party/curl/lib/share.c (revision 13498266)
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 "share.h"
30#include "psl.h"
31#include "vtls/vtls.h"
32#include "hsts.h"
33
34/* The last 3 #include files should be in this order */
35#include "curl_printf.h"
36#include "curl_memory.h"
37#include "memdebug.h"
38
39struct Curl_share *
40curl_share_init(void)
41{
42  struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
43  if(share) {
44    share->magic = CURL_GOOD_SHARE;
45    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
46    Curl_init_dnscache(&share->hostcache, 23);
47  }
48
49  return share;
50}
51
52#undef curl_share_setopt
53CURLSHcode
54curl_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_HSTS:
95#ifndef CURL_DISABLE_HSTS
96      if(!share->hsts) {
97        share->hsts = Curl_hsts_init();
98        if(!share->hsts)
99          res = CURLSHE_NOMEM;
100      }
101#else   /* CURL_DISABLE_HSTS */
102      res = CURLSHE_NOT_BUILT_IN;
103#endif
104      break;
105
106    case CURL_LOCK_DATA_SSL_SESSION:
107#ifdef USE_SSL
108      if(!share->sslsession) {
109        share->max_ssl_sessions = 8;
110        share->sslsession = calloc(share->max_ssl_sessions,
111                                   sizeof(struct Curl_ssl_session));
112        share->sessionage = 0;
113        if(!share->sslsession)
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      if(Curl_conncache_init(&share->conn_cache, 103))
123        res = CURLSHE_NOMEM;
124      break;
125
126    case CURL_LOCK_DATA_PSL:
127#ifndef USE_LIBPSL
128      res = CURLSHE_NOT_BUILT_IN;
129#endif
130      break;
131
132    default:
133      res = CURLSHE_BAD_OPTION;
134    }
135    if(!res)
136      share->specifier |= (unsigned int)(1<<type);
137    break;
138
139  case CURLSHOPT_UNSHARE:
140    /* this is a type this share will no longer share */
141    type = va_arg(param, int);
142    share->specifier &= ~(unsigned int)(1<<type);
143    switch(type) {
144    case CURL_LOCK_DATA_DNS:
145      break;
146
147    case CURL_LOCK_DATA_COOKIE:
148#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
149      if(share->cookies) {
150        Curl_cookie_cleanup(share->cookies);
151        share->cookies = NULL;
152      }
153#else   /* CURL_DISABLE_HTTP */
154      res = CURLSHE_NOT_BUILT_IN;
155#endif
156      break;
157
158    case CURL_LOCK_DATA_HSTS:
159#ifndef CURL_DISABLE_HSTS
160      if(share->hsts) {
161        Curl_hsts_cleanup(&share->hsts);
162      }
163#else   /* CURL_DISABLE_HSTS */
164      res = CURLSHE_NOT_BUILT_IN;
165#endif
166      break;
167
168    case CURL_LOCK_DATA_SSL_SESSION:
169#ifdef USE_SSL
170      Curl_safefree(share->sslsession);
171#else
172      res = CURLSHE_NOT_BUILT_IN;
173#endif
174      break;
175
176    case CURL_LOCK_DATA_CONNECT:
177      break;
178
179    default:
180      res = CURLSHE_BAD_OPTION;
181      break;
182    }
183    break;
184
185  case CURLSHOPT_LOCKFUNC:
186    lockfunc = va_arg(param, curl_lock_function);
187    share->lockfunc = lockfunc;
188    break;
189
190  case CURLSHOPT_UNLOCKFUNC:
191    unlockfunc = va_arg(param, curl_unlock_function);
192    share->unlockfunc = unlockfunc;
193    break;
194
195  case CURLSHOPT_USERDATA:
196    ptr = va_arg(param, void *);
197    share->clientdata = ptr;
198    break;
199
200  default:
201    res = CURLSHE_BAD_OPTION;
202    break;
203  }
204
205  va_end(param);
206
207  return res;
208}
209
210CURLSHcode
211curl_share_cleanup(struct Curl_share *share)
212{
213  if(!GOOD_SHARE_HANDLE(share))
214    return CURLSHE_INVALID;
215
216  if(share->lockfunc)
217    share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
218                    share->clientdata);
219
220  if(share->dirty) {
221    if(share->unlockfunc)
222      share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
223    return CURLSHE_IN_USE;
224  }
225
226  Curl_conncache_close_all_connections(&share->conn_cache);
227  Curl_conncache_destroy(&share->conn_cache);
228  Curl_hash_destroy(&share->hostcache);
229
230#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
231  Curl_cookie_cleanup(share->cookies);
232#endif
233
234#ifndef CURL_DISABLE_HSTS
235  Curl_hsts_cleanup(&share->hsts);
236#endif
237
238#ifdef USE_SSL
239  if(share->sslsession) {
240    size_t i;
241    for(i = 0; i < share->max_ssl_sessions; i++)
242      Curl_ssl_kill_session(&(share->sslsession[i]));
243    free(share->sslsession);
244  }
245#endif
246
247  Curl_psl_destroy(&share->psl);
248
249  if(share->unlockfunc)
250    share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
251  share->magic = 0;
252  free(share);
253
254  return CURLSHE_OK;
255}
256
257
258CURLSHcode
259Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
260                curl_lock_access accesstype)
261{
262  struct Curl_share *share = data->share;
263
264  if(!share)
265    return CURLSHE_INVALID;
266
267  if(share->specifier & (unsigned int)(1<<type)) {
268    if(share->lockfunc) /* only call this if set! */
269      share->lockfunc(data, type, accesstype, share->clientdata);
270  }
271  /* else if we don't share this, pretend successful lock */
272
273  return CURLSHE_OK;
274}
275
276CURLSHcode
277Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
278{
279  struct Curl_share *share = data->share;
280
281  if(!share)
282    return CURLSHE_INVALID;
283
284  if(share->specifier & (unsigned int)(1<<type)) {
285    if(share->unlockfunc) /* only call this if set! */
286      share->unlockfunc (data, type, share->clientdata);
287  }
288
289  return CURLSHE_OK;
290}
291