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