mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
bundles connection caching: some out of memory handling fixes
This commit is contained in:
parent
b7a1eccce8
commit
eafccdb315
@ -6,6 +6,7 @@
|
|||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
|
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
|
||||||
|
* Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -48,6 +49,7 @@ CURLcode Curl_bundle_create(struct SessionHandle *data,
|
|||||||
struct connectbundle **cb_ptr)
|
struct connectbundle **cb_ptr)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
|
DEBUGASSERT(*cb_ptr == NULL);
|
||||||
*cb_ptr = malloc(sizeof(struct connectbundle));
|
*cb_ptr = malloc(sizeof(struct connectbundle));
|
||||||
if(!*cb_ptr)
|
if(!*cb_ptr)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
@ -56,15 +58,22 @@ CURLcode Curl_bundle_create(struct SessionHandle *data,
|
|||||||
(*cb_ptr)->server_supports_pipelining = FALSE;
|
(*cb_ptr)->server_supports_pipelining = FALSE;
|
||||||
|
|
||||||
(*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor);
|
(*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor);
|
||||||
if(!(*cb_ptr)->conn_list)
|
if(!(*cb_ptr)->conn_list) {
|
||||||
|
Curl_safefree(*cb_ptr);
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Curl_bundle_destroy(struct connectbundle *cb_ptr)
|
void Curl_bundle_destroy(struct connectbundle *cb_ptr)
|
||||||
{
|
{
|
||||||
if(cb_ptr->conn_list)
|
if(!cb_ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(cb_ptr->conn_list) {
|
||||||
Curl_llist_destroy(cb_ptr->conn_list, NULL);
|
Curl_llist_destroy(cb_ptr->conn_list, NULL);
|
||||||
|
cb_ptr->conn_list = NULL;
|
||||||
|
}
|
||||||
Curl_safefree(cb_ptr);
|
Curl_safefree(cb_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
|
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
|
||||||
|
* Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -70,9 +71,12 @@ struct conncache *Curl_conncache_init(conncachetype type)
|
|||||||
|
|
||||||
void Curl_conncache_destroy(struct conncache *connc)
|
void Curl_conncache_destroy(struct conncache *connc)
|
||||||
{
|
{
|
||||||
|
if(connc) {
|
||||||
Curl_hash_destroy(connc->hash);
|
Curl_hash_destroy(connc->hash);
|
||||||
|
connc->hash = NULL;
|
||||||
free(connc);
|
free(connc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc,
|
struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc,
|
||||||
char *hostname)
|
char *hostname)
|
||||||
@ -125,23 +129,30 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
|
|||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct connectbundle *bundle;
|
struct connectbundle *bundle;
|
||||||
|
struct connectbundle *new_bundle = NULL;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
bundle = Curl_conncache_find_bundle(data->state.conn_cache,
|
bundle = Curl_conncache_find_bundle(data->state.conn_cache,
|
||||||
conn->host.name);
|
conn->host.name);
|
||||||
if(!bundle) {
|
if(!bundle) {
|
||||||
result = Curl_bundle_create(data, &bundle);
|
result = Curl_bundle_create(data, &new_bundle);
|
||||||
if(result != CURLE_OK)
|
if(result != CURLE_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if(!conncache_add_bundle(data->state.conn_cache,
|
if(!conncache_add_bundle(data->state.conn_cache,
|
||||||
conn->host.name, bundle))
|
conn->host.name, new_bundle)) {
|
||||||
|
Curl_bundle_destroy(new_bundle);
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
bundle = new_bundle;
|
||||||
|
}
|
||||||
|
|
||||||
result = Curl_bundle_add_conn(bundle, conn);
|
result = Curl_bundle_add_conn(bundle, conn);
|
||||||
if(result != CURLE_OK)
|
if(result != CURLE_OK) {
|
||||||
|
if(new_bundle)
|
||||||
|
conncache_remove_bundle(data->state.conn_cache, new_bundle);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
connc->num_connections++;
|
connc->num_connections++;
|
||||||
|
|
||||||
|
29
lib/multi.c
29
lib/multi.c
@ -432,6 +432,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
struct Curl_one_easy *easy;
|
struct Curl_one_easy *easy;
|
||||||
struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
|
struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
|
||||||
struct SessionHandle *data = (struct SessionHandle *)easy_handle;
|
struct SessionHandle *data = (struct SessionHandle *)easy_handle;
|
||||||
|
struct SessionHandle *new_closure = NULL;
|
||||||
|
|
||||||
/* First, make some basic checks that the CURLM handle is a good handle */
|
/* First, make some basic checks that the CURLM handle is a good handle */
|
||||||
if(!GOOD_MULTI_HANDLE(multi))
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
@ -447,15 +448,6 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
/* possibly we should create a new unique error code for this condition */
|
/* possibly we should create a new unique error code for this condition */
|
||||||
return CURLM_BAD_EASY_HANDLE;
|
return CURLM_BAD_EASY_HANDLE;
|
||||||
|
|
||||||
/* This is a good time to allocate a fresh easy handle to use when closing
|
|
||||||
cached connections */
|
|
||||||
if(!multi->closure_handle) {
|
|
||||||
multi->closure_handle =
|
|
||||||
(struct SessionHandle *)curl_easy_init();
|
|
||||||
Curl_easy_addmulti(easy_handle, multi_handle);
|
|
||||||
multi->closure_handle->state.conn_cache = multi->conn_cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate and initialize timeout list for easy handle */
|
/* Allocate and initialize timeout list for easy handle */
|
||||||
timeoutlist = Curl_llist_alloc(multi_freetimeout);
|
timeoutlist = Curl_llist_alloc(multi_freetimeout);
|
||||||
if(!timeoutlist)
|
if(!timeoutlist)
|
||||||
@ -469,6 +461,17 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
return CURLM_OUT_OF_MEMORY;
|
return CURLM_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In case multi handle has no closure_handle yet, allocate
|
||||||
|
a new easy handle to use when closing cached connections */
|
||||||
|
if(!multi->closure_handle) {
|
||||||
|
new_closure = (struct SessionHandle *)curl_easy_init();
|
||||||
|
if(!new_closure) {
|
||||||
|
free(easy);
|
||||||
|
Curl_llist_destroy(timeoutlist, NULL);
|
||||||
|
return CURLM_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** No failure allowed in this function beyond this point. And
|
** No failure allowed in this function beyond this point. And
|
||||||
** no modification of easy nor multi handle allowed before this
|
** no modification of easy nor multi handle allowed before this
|
||||||
@ -476,6 +479,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
** won't be undone in this function no matter what.
|
** won't be undone in this function no matter what.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* In case a new closure handle has been initialized above, it
|
||||||
|
is associated now with the multi handle which lacked one. */
|
||||||
|
if(new_closure) {
|
||||||
|
multi->closure_handle = new_closure;
|
||||||
|
Curl_easy_addmulti(multi->closure_handle, multi_handle);
|
||||||
|
multi->closure_handle->state.conn_cache = multi->conn_cache;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make easy handle use timeout list initialized above */
|
/* Make easy handle use timeout list initialized above */
|
||||||
data->state.timeoutlist = timeoutlist;
|
data->state.timeoutlist = timeoutlist;
|
||||||
timeoutlist = NULL;
|
timeoutlist = NULL;
|
||||||
|
@ -2495,6 +2495,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|||||||
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
||||||
DEBUGASSERT(sshc->kh == NULL);
|
DEBUGASSERT(sshc->kh == NULL);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIBSSH2_AGENT_API
|
||||||
|
DEBUGASSERT(sshc->ssh_agent == NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
Curl_safefree(sshc->rsa_pub);
|
Curl_safefree(sshc->rsa_pub);
|
||||||
Curl_safefree(sshc->rsa);
|
Curl_safefree(sshc->rsa);
|
||||||
|
21
lib/url.c
21
lib/url.c
@ -372,10 +372,15 @@ CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src)
|
|||||||
|
|
||||||
CURLcode Curl_close(struct SessionHandle *data)
|
CURLcode Curl_close(struct SessionHandle *data)
|
||||||
{
|
{
|
||||||
struct Curl_multi *m = data->multi;
|
struct Curl_multi *m;
|
||||||
|
|
||||||
|
if(!data)
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
Curl_expire(data, 0); /* shut off timers */
|
Curl_expire(data, 0); /* shut off timers */
|
||||||
|
|
||||||
|
m = data->multi;
|
||||||
|
|
||||||
if(m)
|
if(m)
|
||||||
/* This handle is still part of a multi handle, take care of this first
|
/* This handle is still part of a multi handle, take care of this first
|
||||||
and detach this handle from there. */
|
and detach this handle from there. */
|
||||||
@ -3060,11 +3065,17 @@ static CURLcode ConnectionStore(struct SessionHandle *data,
|
|||||||
{
|
{
|
||||||
static int connection_id_counter = 0;
|
static int connection_id_counter = 0;
|
||||||
|
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
/* Assign a number to the connection for easier tracking in the log
|
/* Assign a number to the connection for easier tracking in the log
|
||||||
output */
|
output */
|
||||||
conn->connection_id = connection_id_counter++;
|
conn->connection_id = connection_id_counter++;
|
||||||
|
|
||||||
return Curl_conncache_add_conn(data->state.conn_cache, conn);
|
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
|
||||||
|
if(result != CURLE_OK)
|
||||||
|
conn->connection_id = -1;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* after a TCP connection to the proxy has been verified, this function does
|
/* after a TCP connection to the proxy has been verified, this function does
|
||||||
@ -5239,8 +5250,12 @@ CURLcode Curl_done(struct connectdata **connp,
|
|||||||
state it is for re-using, so we're forced to close it. In a perfect world
|
state it is for re-using, so we're forced to close it. In a perfect world
|
||||||
we can add code that keep track of if we really must close it here or not,
|
we can add code that keep track of if we really must close it here or not,
|
||||||
but currently we have no such detail knowledge.
|
but currently we have no such detail knowledge.
|
||||||
|
|
||||||
|
connection_id == -1 here means that the connection has not been added
|
||||||
|
to the connection cache (OOM) and thus we must disconnect it here.
|
||||||
*/
|
*/
|
||||||
if(data->set.reuse_forbid || conn->bits.close || premature) {
|
if(data->set.reuse_forbid || conn->bits.close || premature ||
|
||||||
|
(-1 == conn->connection_id)) {
|
||||||
CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
|
CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
|
||||||
|
|
||||||
/* If we had an error already, make sure we return that one. But
|
/* If we had an error already, make sure we return that one. But
|
||||||
|
Loading…
Reference in New Issue
Block a user