share.c (7777B)
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 "connect.h" 30 #include "share.h" 31 #include "psl.h" 32 #include "vtls/vtls.h" 33 #include "vtls/vtls_scache.h" 34 #include "hsts.h" 35 #include "url.h" 36 37 /* The last 3 #include files should be in this order */ 38 #include "curl_printf.h" 39 #include "curl_memory.h" 40 #include "memdebug.h" 41 42 CURLSH * 43 curl_share_init(void) 44 { 45 struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); 46 if(share) { 47 share->magic = CURL_GOOD_SHARE; 48 share->specifier |= (1 << CURL_LOCK_DATA_SHARE); 49 Curl_dnscache_init(&share->dnscache, 23); 50 share->admin = curl_easy_init(); 51 if(!share->admin) { 52 free(share); 53 return NULL; 54 } 55 /* admin handles have mid 0 */ 56 share->admin->mid = 0; 57 share->admin->state.internal = TRUE; 58 #ifdef DEBUGBUILD 59 if(getenv("CURL_DEBUG")) 60 share->admin->set.verbose = TRUE; 61 #endif 62 } 63 64 return share; 65 } 66 67 #undef curl_share_setopt 68 CURLSHcode 69 curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) 70 { 71 va_list param; 72 int type; 73 curl_lock_function lockfunc; 74 curl_unlock_function unlockfunc; 75 void *ptr; 76 CURLSHcode res = CURLSHE_OK; 77 struct Curl_share *share = sh; 78 79 if(!GOOD_SHARE_HANDLE(share)) 80 return CURLSHE_INVALID; 81 82 if(share->dirty) 83 /* do not allow setting options while one or more handles are already 84 using this share */ 85 return CURLSHE_IN_USE; 86 87 va_start(param, option); 88 89 switch(option) { 90 case CURLSHOPT_SHARE: 91 /* this is a type this share will share */ 92 type = va_arg(param, int); 93 94 switch(type) { 95 case CURL_LOCK_DATA_DNS: 96 break; 97 98 case CURL_LOCK_DATA_COOKIE: 99 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) 100 if(!share->cookies) { 101 share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE); 102 if(!share->cookies) 103 res = CURLSHE_NOMEM; 104 } 105 #else /* CURL_DISABLE_HTTP */ 106 res = CURLSHE_NOT_BUILT_IN; 107 #endif 108 break; 109 110 case CURL_LOCK_DATA_HSTS: 111 #ifndef CURL_DISABLE_HSTS 112 if(!share->hsts) { 113 share->hsts = Curl_hsts_init(); 114 if(!share->hsts) 115 res = CURLSHE_NOMEM; 116 } 117 #else /* CURL_DISABLE_HSTS */ 118 res = CURLSHE_NOT_BUILT_IN; 119 #endif 120 break; 121 122 case CURL_LOCK_DATA_SSL_SESSION: 123 #ifdef USE_SSL 124 if(!share->ssl_scache) { 125 /* There is no way (yet) for the application to configure the 126 * session cache size, shared between many transfers. As for curl 127 * itself, a high session count will impact startup time. Also, the 128 * scache is not optimized for several hundreds of peers. So, 129 * keep it at a reasonable level. */ 130 if(Curl_ssl_scache_create(25, 2, &share->ssl_scache)) 131 res = CURLSHE_NOMEM; 132 } 133 #else 134 res = CURLSHE_NOT_BUILT_IN; 135 #endif 136 break; 137 138 case CURL_LOCK_DATA_CONNECT: 139 /* It is safe to set this option several times on a share. */ 140 if(!share->cpool.initialised) { 141 Curl_cpool_init(&share->cpool, share->admin, share, 103); 142 } 143 break; 144 145 case CURL_LOCK_DATA_PSL: 146 #ifndef USE_LIBPSL 147 res = CURLSHE_NOT_BUILT_IN; 148 #endif 149 break; 150 151 default: 152 res = CURLSHE_BAD_OPTION; 153 } 154 if(!res) 155 share->specifier |= (unsigned int)(1 << type); 156 break; 157 158 case CURLSHOPT_UNSHARE: 159 /* this is a type this share will no longer share */ 160 type = va_arg(param, int); 161 share->specifier &= ~(unsigned int)(1 << type); 162 switch(type) { 163 case CURL_LOCK_DATA_DNS: 164 break; 165 166 case CURL_LOCK_DATA_COOKIE: 167 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) 168 if(share->cookies) { 169 Curl_cookie_cleanup(share->cookies); 170 share->cookies = NULL; 171 } 172 #else /* CURL_DISABLE_HTTP */ 173 res = CURLSHE_NOT_BUILT_IN; 174 #endif 175 break; 176 177 case CURL_LOCK_DATA_HSTS: 178 #ifndef CURL_DISABLE_HSTS 179 if(share->hsts) { 180 Curl_hsts_cleanup(&share->hsts); 181 } 182 #else /* CURL_DISABLE_HSTS */ 183 res = CURLSHE_NOT_BUILT_IN; 184 #endif 185 break; 186 187 case CURL_LOCK_DATA_SSL_SESSION: 188 #ifdef USE_SSL 189 if(share->ssl_scache) { 190 Curl_ssl_scache_destroy(share->ssl_scache); 191 share->ssl_scache = NULL; 192 } 193 #else 194 res = CURLSHE_NOT_BUILT_IN; 195 #endif 196 break; 197 198 case CURL_LOCK_DATA_CONNECT: 199 break; 200 201 default: 202 res = CURLSHE_BAD_OPTION; 203 break; 204 } 205 break; 206 207 case CURLSHOPT_LOCKFUNC: 208 lockfunc = va_arg(param, curl_lock_function); 209 share->lockfunc = lockfunc; 210 break; 211 212 case CURLSHOPT_UNLOCKFUNC: 213 unlockfunc = va_arg(param, curl_unlock_function); 214 share->unlockfunc = unlockfunc; 215 break; 216 217 case CURLSHOPT_USERDATA: 218 ptr = va_arg(param, void *); 219 share->clientdata = ptr; 220 break; 221 222 default: 223 res = CURLSHE_BAD_OPTION; 224 break; 225 } 226 227 va_end(param); 228 229 return res; 230 } 231 232 CURLSHcode 233 curl_share_cleanup(CURLSH *sh) 234 { 235 struct Curl_share *share = sh; 236 if(!GOOD_SHARE_HANDLE(share)) 237 return CURLSHE_INVALID; 238 239 if(share->lockfunc) 240 share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE, 241 share->clientdata); 242 243 if(share->dirty) { 244 if(share->unlockfunc) 245 share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); 246 return CURLSHE_IN_USE; 247 } 248 249 if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) { 250 Curl_cpool_destroy(&share->cpool); 251 } 252 253 Curl_dnscache_destroy(&share->dnscache); 254 255 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) 256 Curl_cookie_cleanup(share->cookies); 257 #endif 258 259 #ifndef CURL_DISABLE_HSTS 260 Curl_hsts_cleanup(&share->hsts); 261 #endif 262 263 #ifdef USE_SSL 264 if(share->ssl_scache) { 265 Curl_ssl_scache_destroy(share->ssl_scache); 266 share->ssl_scache = NULL; 267 } 268 #endif 269 270 Curl_psl_destroy(&share->psl); 271 Curl_close(&share->admin); 272 273 if(share->unlockfunc) 274 share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); 275 share->magic = 0; 276 free(share); 277 278 return CURLSHE_OK; 279 } 280 281 282 CURLSHcode 283 Curl_share_lock(struct Curl_easy *data, curl_lock_data type, 284 curl_lock_access accesstype) 285 { 286 struct Curl_share *share = data->share; 287 288 if(!share) 289 return CURLSHE_INVALID; 290 291 if(share->specifier & (unsigned int)(1 << type)) { 292 if(share->lockfunc) /* only call this if set! */ 293 share->lockfunc(data, type, accesstype, share->clientdata); 294 } 295 /* else if we do not share this, pretend successful lock */ 296 297 return CURLSHE_OK; 298 } 299 300 CURLSHcode 301 Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) 302 { 303 struct Curl_share *share = data->share; 304 305 if(!share) 306 return CURLSHE_INVALID; 307 308 if(share->specifier & (unsigned int)(1 << type)) { 309 if(share->unlockfunc) /* only call this if set! */ 310 share->unlockfunc (data, type, share->clientdata); 311 } 312 313 return CURLSHE_OK; 314 }