mirror of
https://github.com/curl/curl.git
synced 2024-12-15 06:40:09 +08:00
942cf12c2f
By making the `magic` identifier the same size and at the same place within the structs (easy, multi, share), libcurl will be able to more reliably detect and safely error out if an application passes in the wrong handle to APIs. Easier to detect and less likely to cause crashes if done. Such mixups can't be detected at compile-time due to them being typedefed void pointers - unless `CURL_STRICTER` is defined. Closes #6484
265 lines
6.3 KiB
C
265 lines
6.3 KiB
C
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "curl_setup.h"
|
|
|
|
#include <curl/curl.h>
|
|
#include "urldata.h"
|
|
#include "share.h"
|
|
#include "psl.h"
|
|
#include "vtls/vtls.h"
|
|
#include "curl_memory.h"
|
|
|
|
/* The last #include file should be: */
|
|
#include "memdebug.h"
|
|
|
|
struct Curl_share *
|
|
curl_share_init(void)
|
|
{
|
|
struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
|
|
if(share) {
|
|
share->magic = CURL_GOOD_SHARE;
|
|
share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
|
|
|
|
if(Curl_mk_dnscache(&share->hostcache)) {
|
|
free(share);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return share;
|
|
}
|
|
|
|
#undef curl_share_setopt
|
|
CURLSHcode
|
|
curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
|
|
{
|
|
va_list param;
|
|
int type;
|
|
curl_lock_function lockfunc;
|
|
curl_unlock_function unlockfunc;
|
|
void *ptr;
|
|
CURLSHcode res = CURLSHE_OK;
|
|
|
|
if(!GOOD_SHARE_HANDLE(share))
|
|
return CURLSHE_INVALID;
|
|
|
|
if(share->dirty)
|
|
/* don't allow setting options while one or more handles are already
|
|
using this share */
|
|
return CURLSHE_IN_USE;
|
|
|
|
va_start(param, option);
|
|
|
|
switch(option) {
|
|
case CURLSHOPT_SHARE:
|
|
/* this is a type this share will share */
|
|
type = va_arg(param, int);
|
|
|
|
switch(type) {
|
|
case CURL_LOCK_DATA_DNS:
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_COOKIE:
|
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
|
if(!share->cookies) {
|
|
share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
|
|
if(!share->cookies)
|
|
res = CURLSHE_NOMEM;
|
|
}
|
|
#else /* CURL_DISABLE_HTTP */
|
|
res = CURLSHE_NOT_BUILT_IN;
|
|
#endif
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_SSL_SESSION:
|
|
#ifdef USE_SSL
|
|
if(!share->sslsession) {
|
|
share->max_ssl_sessions = 8;
|
|
share->sslsession = calloc(share->max_ssl_sessions,
|
|
sizeof(struct Curl_ssl_session));
|
|
share->sessionage = 0;
|
|
if(!share->sslsession)
|
|
res = CURLSHE_NOMEM;
|
|
}
|
|
#else
|
|
res = CURLSHE_NOT_BUILT_IN;
|
|
#endif
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_CONNECT:
|
|
if(Curl_conncache_init(&share->conn_cache, 103))
|
|
res = CURLSHE_NOMEM;
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_PSL:
|
|
#ifndef USE_LIBPSL
|
|
res = CURLSHE_NOT_BUILT_IN;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
res = CURLSHE_BAD_OPTION;
|
|
}
|
|
if(!res)
|
|
share->specifier |= (1<<type);
|
|
break;
|
|
|
|
case CURLSHOPT_UNSHARE:
|
|
/* this is a type this share will no longer share */
|
|
type = va_arg(param, int);
|
|
share->specifier &= ~(1<<type);
|
|
switch(type) {
|
|
case CURL_LOCK_DATA_DNS:
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_COOKIE:
|
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
|
if(share->cookies) {
|
|
Curl_cookie_cleanup(share->cookies);
|
|
share->cookies = NULL;
|
|
}
|
|
#else /* CURL_DISABLE_HTTP */
|
|
res = CURLSHE_NOT_BUILT_IN;
|
|
#endif
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_SSL_SESSION:
|
|
#ifdef USE_SSL
|
|
Curl_safefree(share->sslsession);
|
|
#else
|
|
res = CURLSHE_NOT_BUILT_IN;
|
|
#endif
|
|
break;
|
|
|
|
case CURL_LOCK_DATA_CONNECT:
|
|
break;
|
|
|
|
default:
|
|
res = CURLSHE_BAD_OPTION;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CURLSHOPT_LOCKFUNC:
|
|
lockfunc = va_arg(param, curl_lock_function);
|
|
share->lockfunc = lockfunc;
|
|
break;
|
|
|
|
case CURLSHOPT_UNLOCKFUNC:
|
|
unlockfunc = va_arg(param, curl_unlock_function);
|
|
share->unlockfunc = unlockfunc;
|
|
break;
|
|
|
|
case CURLSHOPT_USERDATA:
|
|
ptr = va_arg(param, void *);
|
|
share->clientdata = ptr;
|
|
break;
|
|
|
|
default:
|
|
res = CURLSHE_BAD_OPTION;
|
|
break;
|
|
}
|
|
|
|
va_end(param);
|
|
|
|
return res;
|
|
}
|
|
|
|
CURLSHcode
|
|
curl_share_cleanup(struct Curl_share *share)
|
|
{
|
|
if(!GOOD_SHARE_HANDLE(share))
|
|
return CURLSHE_INVALID;
|
|
|
|
if(share->lockfunc)
|
|
share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
|
|
share->clientdata);
|
|
|
|
if(share->dirty) {
|
|
if(share->unlockfunc)
|
|
share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
|
|
return CURLSHE_IN_USE;
|
|
}
|
|
|
|
Curl_conncache_close_all_connections(&share->conn_cache);
|
|
Curl_conncache_destroy(&share->conn_cache);
|
|
Curl_hash_destroy(&share->hostcache);
|
|
|
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
|
Curl_cookie_cleanup(share->cookies);
|
|
#endif
|
|
|
|
#ifdef USE_SSL
|
|
if(share->sslsession) {
|
|
size_t i;
|
|
for(i = 0; i < share->max_ssl_sessions; i++)
|
|
Curl_ssl_kill_session(&(share->sslsession[i]));
|
|
free(share->sslsession);
|
|
}
|
|
#endif
|
|
|
|
Curl_psl_destroy(&share->psl);
|
|
|
|
if(share->unlockfunc)
|
|
share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
|
|
share->magic = 0;
|
|
free(share);
|
|
|
|
return CURLSHE_OK;
|
|
}
|
|
|
|
|
|
CURLSHcode
|
|
Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
|
|
curl_lock_access accesstype)
|
|
{
|
|
struct Curl_share *share = data->share;
|
|
|
|
if(share == NULL)
|
|
return CURLSHE_INVALID;
|
|
|
|
if(share->specifier & (1<<type)) {
|
|
if(share->lockfunc) /* only call this if set! */
|
|
share->lockfunc(data, type, accesstype, share->clientdata);
|
|
}
|
|
/* else if we don't share this, pretend successful lock */
|
|
|
|
return CURLSHE_OK;
|
|
}
|
|
|
|
CURLSHcode
|
|
Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
|
|
{
|
|
struct Curl_share *share = data->share;
|
|
|
|
if(share == NULL)
|
|
return CURLSHE_INVALID;
|
|
|
|
if(share->specifier & (1<<type)) {
|
|
if(share->unlockfunc) /* only call this if set! */
|
|
share->unlockfunc (data, type, share->clientdata);
|
|
}
|
|
|
|
return CURLSHE_OK;
|
|
}
|