share.c 7.6 KB

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