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