diff options
Diffstat (limited to 'lib/url.c')
-rw-r--r-- | lib/url.c | 708 |
1 files changed, 253 insertions, 455 deletions
@@ -126,6 +126,8 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "curl_rtmp.h" #include "gopher.h" #include "http_proxy.h" +#include "bundles.h" +#include "conncache.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -135,7 +137,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "memdebug.h" /* Local static prototypes */ -static long ConnectionKillOne(struct SessionHandle *data); +static bool ConnectionKillOne(struct SessionHandle *data); static void conn_free(struct connectdata *conn); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); static CURLcode do_init(struct connectdata *conn); @@ -262,10 +264,10 @@ static const struct Curl_handler Curl_handler_dummy = { static void close_connections(struct SessionHandle *data) { /* Loop through all open connections and kill them one by one */ - long i; + bool killed; do { - i = ConnectionKillOne(data); - } while(i != -1L); + killed = ConnectionKillOne(data); + } while(killed); } void Curl_freeset(struct SessionHandle * data) @@ -378,66 +380,6 @@ CURLcode Curl_close(struct SessionHandle *data) { struct Curl_multi *m = data->multi; -#ifdef DEBUGBUILD - /* only for debugging, scan through all connections and see if there's a - pipe reference still identifying this handle */ - - if(data->state.connc && data->state.connc->type == CONNCACHE_MULTI) { - struct conncache *c = data->state.connc; - long i; - struct curl_llist *pipeline; - struct curl_llist_element *curr; - struct connectdata *connptr; - - for(i=0; i< c->num; i++) { - connptr = c->connects[i]; - if(!connptr) - continue; - - pipeline = connptr->send_pipe; - if(pipeline) { - for(curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in send pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - pipeline = connptr->recv_pipe; - if(pipeline) { - for(curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in recv pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - pipeline = connptr->done_pipe; - if(pipeline) { - for(curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in done pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - pipeline = connptr->pend_pipe; - if(pipeline) { - for(curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in pend pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - } - } -#endif - Curl_expire(data, 0); /* shut off timers */ if(m) @@ -457,26 +399,16 @@ CURLcode Curl_close(struct SessionHandle *data) the multi handle, since that function uses the magic field! */ - if(data->state.connc) { - - if(data->state.connc->type == CONNCACHE_PRIVATE) { + if(data->state.conn_cache) { + if(data->state.conn_cache->type == CONNCACHE_PRIVATE) { /* close all connections still alive that are in the private connection cache, as we no longer have the pointer left to the shared one. */ close_connections(data); - - /* free the connection cache if allocated privately */ - Curl_rm_connc(data->state.connc); - data->state.connc = NULL; + Curl_conncache_destroy(data->state.conn_cache); + data->state.conn_cache = NULL; } } - if(data->state.shared_conn) { - /* marked to be used by a pending connection so we can't kill this handle - just yet */ - data->state.closed = TRUE; - return CURLE_OK; - } - if(data->dns.hostcachetype == HCACHE_PRIVATE) Curl_hostcache_destroy(data); @@ -533,124 +465,6 @@ CURLcode Curl_close(struct SessionHandle *data) return CURLE_OK; } -/* create a connection cache of a private or multi type */ -struct conncache *Curl_mk_connc(int type, - long amount) /* set -1 to use default */ -{ - /* It is subject for debate how many default connections to have for a multi - connection cache... */ - - struct conncache *c; - long default_amount; - long max_amount = (long)(((size_t)INT_MAX) / sizeof(struct connectdata *)); - - if(type == CONNCACHE_PRIVATE) { - default_amount = (amount < 1L) ? 5L : amount; - } - else { - default_amount = (amount < 1L) ? 10L : amount; - } - - if(default_amount > max_amount) - default_amount = max_amount; - - c = calloc(1, sizeof(struct conncache)); - if(!c) - return NULL; - - c->connects = calloc((size_t)default_amount, sizeof(struct connectdata *)); - if(!c->connects) { - free(c); - return NULL; - } - - c->num = default_amount; - - return c; -} - -/* Change number of entries of a connection cache */ -CURLcode Curl_ch_connc(struct SessionHandle *data, - struct conncache *c, - long newamount) -{ - long i; - struct connectdata **newptr; - long max_amount = (long)(((size_t)INT_MAX) / sizeof(struct connectdata *)); - - if(newamount < 1) - newamount = 1; /* we better have at least one entry */ - - if(!c) { - /* we get a NULL pointer passed in as connection cache, which means that - there is no cache created for this SessionHandle just yet, we create a - brand new with the requested size. - */ - data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, newamount); - if(!data->state.connc) - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; - } - - if(newamount < c->num) { - /* Since this number is *decreased* from the existing number, we must - close the possibly open connections that live on the indexes that - are being removed! - - NOTE: for conncache_multi cases we must make sure that we only - close handles not in use. - */ - for(i=newamount; i< c->num; i++) { - Curl_disconnect(c->connects[i], /* dead_connection */ FALSE); - c->connects[i] = NULL; - } - - /* If the most recent connection is no longer valid, mark it - invalid. */ - if(data->state.lastconnect <= newamount) - data->state.lastconnect = -1; - } - if(newamount > 0) { - if(newamount > max_amount) - newamount = max_amount; - newptr = realloc(c->connects, sizeof(struct connectdata *) * newamount); - if(!newptr) - /* we closed a few connections in vain, but so what? */ - return CURLE_OUT_OF_MEMORY; - - /* nullify the newly added pointers */ - for(i=c->num; i<newamount; i++) - newptr[i] = NULL; - - c->connects = newptr; - c->num = newamount; - } - /* we no longer support less than 1 as size for the connection cache, and - I'm not sure it ever worked to set it to zero */ - return CURLE_OK; -} - -/* Free a connection cache. This is called from Curl_close() and - curl_multi_cleanup(). */ -void Curl_rm_connc(struct conncache *c) -{ - if(!c) - return; - - if(c->connects) { - long i; - for(i = 0; i < c->num; ++i) { - conn_free(c->connects[i]); - c->connects[i] = NULL; - } - free(c->connects); - c->connects = NULL; - } - c->num = 0; - - free(c); -} - /* * Initialize the UserDefined fields within a SessionHandle. * This may be safely called on a new or existing SessionHandle. @@ -807,7 +621,7 @@ CURLcode Curl_open(struct SessionHandle **curl) Curl_convert_init(data); /* most recent connection is not yet defined */ - data->state.lastconnect = -1; + data->state.lastconnect = NULL; data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ @@ -880,7 +694,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set the absolute number of maximum simultaneous alive connection that * libcurl is allowed to have. */ - result = Curl_ch_connc(data, data->state.connc, va_arg(param, long)); + data->set.maxconnects = va_arg(param, long); break; case CURLOPT_FORBID_REUSE: /* @@ -2744,14 +2558,9 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) /* This is set if protocol-specific cleanups should be made */ conn->handler->disconnect(conn, dead_connection); - if(-1 != conn->connectindex) { /* unlink ourselves! */ - infof(data, "Closing connection #%ld\n", conn->connectindex); - if(data->state.connc) - /* only clear the table entry if we still know in which cache we - used to be in */ - data->state.connc->connects[conn->connectindex] = NULL; - } + infof(data, "Closing connection %d\n", conn->connection_id); + Curl_conncache_remove_conn(data->state.conn_cache, conn); #if defined(USE_LIBIDN) if(conn->host.encalloc) @@ -2938,225 +2747,229 @@ ConnectionExists(struct SessionHandle *data, struct connectdata *needle, struct connectdata **usethis) { - long i; struct connectdata *check; struct connectdata *chosen = 0; bool canPipeline = IsPipeliningPossible(data, needle); bool wantNTLM = (data->state.authhost.want==CURLAUTH_NTLM) || (data->state.authhost.want==CURLAUTH_NTLM_WB) ? TRUE : FALSE; + struct connectbundle *bundle; - for(i=0; i< data->state.connc->num; i++) { - bool match = FALSE; - bool credentialsMatch = FALSE; - size_t pipeLen = 0; - /* - * Note that if we use a HTTP proxy, we check connections to that - * proxy and not to the actual remote server. - */ - check = data->state.connc->connects[i]; - if(!check) - /* NULL pointer means not filled-in entry */ - continue; - - pipeLen = check->send_pipe->size + check->recv_pipe->size; + /* Look up the bundle with all the connections to this + particular host */ + bundle = Curl_conncache_find_bundle(data->state.conn_cache, + needle->host.name); + if(bundle) { + struct curl_llist_element *curr; - if(check->connectindex == -1) { - check->connectindex = i; /* Set this appropriately since it might have - been set to -1 when the easy was removed - from the multi */ - } + infof(data, "Found bundle for host %s: %p\n", needle->host.name, bundle); - if(!pipeLen && !check->inuse) { - /* The check for a dead socket makes sense only if there are no - handles in pipeline and the connection isn't already marked in - use */ - bool dead; - if(check->handler->protocol & CURLPROTO_RTSP) - /* RTSP is a special case due to RTP interleaving */ - dead = Curl_rtsp_connisdead(check); - else - dead = SocketIsDead(check->sock[FIRSTSOCKET]); + curr = bundle->conn_list->head; + while(curr) { + bool match = FALSE; + bool credentialsMatch = FALSE; + size_t pipeLen; - if(dead) { - check->data = data; - infof(data, "Connection #%ld seems to be dead!\n", i); - - /* disconnect resources */ - Curl_disconnect(check, /* dead_connection */ TRUE); - data->state.connc->connects[i]=NULL; /* nothing here */ + /* + * Note that if we use a HTTP proxy, we check connections to that + * proxy and not to the actual remote server. + */ + check = curr->ptr; + curr = curr->next; + + pipeLen = check->send_pipe->size + check->recv_pipe->size; + + if(!pipeLen && !check->inuse) { + /* The check for a dead socket makes sense only if there are no + handles in pipeline and the connection isn't already marked in + use */ + bool dead; + if(check->handler->protocol & CURLPROTO_RTSP) + /* RTSP is a special case due to RTP interleaving */ + dead = Curl_rtsp_connisdead(check); + else + dead = SocketIsDead(check->sock[FIRSTSOCKET]); - continue; - } - } + if(dead) { + check->data = data; + infof(data, "Connection %d seems to be dead!\n", + check->connection_id); - if(canPipeline) { - /* Make sure the pipe has only GET requests */ - struct SessionHandle* sh = gethandleathead(check->send_pipe); - struct SessionHandle* rh = gethandleathead(check->recv_pipe); - if(sh) { - if(!IsPipeliningPossible(sh, check)) - continue; - } - else if(rh) { - if(!IsPipeliningPossible(rh, check)) + /* disconnect resources */ + Curl_disconnect(check, /* dead_connection */ TRUE); continue; + } } + if(canPipeline) { + /* Make sure the pipe has only GET requests */ + struct SessionHandle* sh = gethandleathead(check->send_pipe); + struct SessionHandle* rh = gethandleathead(check->recv_pipe); + if(sh) { + if(!IsPipeliningPossible(sh, check)) + continue; + } + else if(rh) { + if(!IsPipeliningPossible(rh, check)) + continue; + } #ifdef DEBUGBUILD if(pipeLen > MAX_PIPELINE_LENGTH) { infof(data, "BAD! Connection #%ld has too big pipeline!\n", - check->connectindex); + check->connection_id); } #endif - } - else { - if(pipeLen > 0) { - /* can only happen within multi handles, and means that another easy - handle is using this connection */ - continue; } - - if(Curl_resolver_asynch()) { - /* ip_addr_str[0] is NUL only if the resolving of the name hasn't - completed yet and until then we don't re-use this connection */ - if(!check->ip_addr_str[0]) { - infof(data, - "Connection #%ld hasn't finished name resolve, can't reuse\n", - check->connectindex); + else { + if(pipeLen > 0) { + /* can only happen within multi handles, and means that another easy + handle is using this connection */ continue; } - } - if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) { - /* Don't pick a connection that hasn't connected yet or that is going - to get closed. */ - infof(data, "Connection #%ld isn't open enough, can't reuse\n", - check->connectindex); -#ifdef DEBUGBUILD - if(check->recv_pipe->size > 0) { - infof(data, "BAD! Unconnected #%ld has a non-empty recv pipeline!\n", - check->connectindex); + if(Curl_resolver_asynch()) { + /* ip_addr_str[0] is NUL only if the resolving of the name hasn't + completed yet and until then we don't re-use this connection */ + if(!check->ip_addr_str[0]) { + infof(data, + "Connection #%ld is still name resolving, can't reuse\n", + check->connection_id); + continue; + } } + + if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || + check->bits.close) { + /* Don't pick a connection that hasn't connected yet or that is going + to get closed. */ + infof(data, "Connection #%ld isn't open enough, can't reuse\n", + check->connection_id); +#ifdef DEBUGBUILD + if(check->recv_pipe->size > 0) { + infof(data, + "BAD! Unconnected #%ld has a non-empty recv pipeline!\n", + check->connection_id); + } #endif - continue; + continue; + } } - } - if((needle->handler->flags&PROTOPT_SSL) != - (check->handler->flags&PROTOPT_SSL)) - /* don't do mixed SSL and non-SSL connections */ - if(!(needle->handler->protocol & check->handler->protocol)) - /* except protocols that have been upgraded via TLS */ - continue; + if((needle->handler->flags&PROTOPT_SSL) != + (check->handler->flags&PROTOPT_SSL)) + /* don't do mixed SSL and non-SSL connections */ + if(!(needle->handler->protocol & check->handler->protocol)) + /* except protocols that have been upgraded via TLS */ + continue; - if(needle->handler->flags&PROTOPT_SSL) { - if((data->set.ssl.verifypeer != check->verifypeer) || - (data->set.ssl.verifyhost != check->verifyhost)) + if(needle->handler->flags&PROTOPT_SSL) { + if((data->set.ssl.verifypeer != check->verifypeer) || + (data->set.ssl.verifyhost != check->verifyhost)) + continue; + } + + if(needle->bits.proxy != check->bits.proxy) + /* don't do mixed proxy and non-proxy connections */ continue; - } - if(needle->bits.proxy != check->bits.proxy) - /* don't do mixed proxy and non-proxy connections */ - continue; - - if(!canPipeline && check->inuse) - /* this request can't be pipelined but the checked connection is already - in use so we skip it */ - continue; - - if(needle->localdev || needle->localport) { - /* If we are bound to a specific local end (IP+port), we must not re-use - a random other one, although if we didn't ask for a particular one we - can reuse one that was bound. - - This comparison is a bit rough and too strict. Since the input - parameters can be specified in numerous ways and still end up the - same it would take a lot of processing to make it really accurate. - Instead, this matching will assume that re-uses of bound connections - will most likely also re-use the exact same binding parameters and - missing out a few edge cases shouldn't hurt anyone very much. - */ - if((check->localport != needle->localport) || - (check->localportrange != needle->localportrange) || - !check->localdev || - !needle->localdev || - strcmp(check->localdev, needle->localdev)) + if(!canPipeline && check->inuse) + /* this request can't be pipelined but the checked connection is + already in use so we skip it */ continue; - } - if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || - (needle->bits.httpproxy && check->bits.httpproxy && - needle->bits.tunnel_proxy && check->bits.tunnel_proxy && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - (needle->port == check->port))) { - /* The requested connection does not use a HTTP proxy or it uses SSL or - it is a non-SSL protocol tunneled over the same http proxy name and - port number or it is a non-SSL protocol which is allowed to be - upgraded via TLS */ - - if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || - needle->handler->protocol & check->handler->protocol) && - Curl_raw_equal(needle->host.name, check->host.name) && - needle->remote_port == check->remote_port) { - if(needle->handler->flags & PROTOPT_SSL) { - /* This is a SSL connection so verify that we're using the same - SSL options as well */ - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) { - DEBUGF(infof(data, - "Connection #%ld has different SSL parameters, " - "can't reuse\n", - check->connectindex)); - continue; - } - else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { - DEBUGF(infof(data, - "Connection #%ld has not started SSL connect, " - "can't reuse\n", - check->connectindex)); - continue; + if(needle->localdev || needle->localport) { + /* If we are bound to a specific local end (IP+port), we must not + re-use a random other one, although if we didn't ask for a + particular one we can reuse one that was bound. + + This comparison is a bit rough and too strict. Since the input + parameters can be specified in numerous ways and still end up the + same it would take a lot of processing to make it really accurate. + Instead, this matching will assume that re-uses of bound connections + will most likely also re-use the exact same binding parameters and + missing out a few edge cases shouldn't hurt anyone very much. + */ + if((check->localport != needle->localport) || + (check->localportrange != needle->localportrange) || + !check->localdev || + !needle->localdev || + strcmp(check->localdev, needle->localdev)) + continue; + } + + if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || + (needle->bits.httpproxy && check->bits.httpproxy && + needle->bits.tunnel_proxy && check->bits.tunnel_proxy && + Curl_raw_equal(needle->proxy.name, check->proxy.name) && + (needle->port == check->port))) { + /* The requested connection does not use a HTTP proxy or it uses SSL or + it is a non-SSL protocol tunneled over the same http proxy name and + port number or it is a non-SSL protocol which is allowed to be + upgraded via TLS */ + + if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || + needle->handler->protocol & check->handler->protocol) && + Curl_raw_equal(needle->host.name, check->host.name) && + needle->remote_port == check->remote_port) { + if(needle->handler->flags & PROTOPT_SSL) { + /* This is a SSL connection so verify that we're using the same + SSL options as well */ + if(!Curl_ssl_config_matches(&needle->ssl_config, + &check->ssl_config)) { + DEBUGF(infof(data, + "Connection #%ld has different SSL parameters, " + "can't reuse\n", + check->connection_id)); + continue; + } + else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { + DEBUGF(infof(data, + "Connection #%ld has not started SSL connect, " + "can't reuse\n", + check->connection_id)); + continue; + } } - } - if((needle->handler->protocol & CURLPROTO_FTP) || - ((needle->handler->protocol & CURLPROTO_HTTP) && wantNTLM)) { - /* This is FTP or HTTP+NTLM, verify that we're using the same name - and password as well */ - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) { - /* one of them was different */ - continue; + if((needle->handler->protocol & CURLPROTO_FTP) || + ((needle->handler->protocol & CURLPROTO_HTTP) && wantNTLM)) { + /* This is FTP or HTTP+NTLM, verify that we're using the same name + and password as well */ + if(!strequal(needle->user, check->user) || + !strequal(needle->passwd, check->passwd)) { + /* one of them was different */ + continue; + } + credentialsMatch = TRUE; } - credentialsMatch = TRUE; + match = TRUE; } - match = TRUE; } - } - else { /* The requested needle connection is using a proxy, - is the checked one using the same host, port and type? */ - if(check->bits.proxy && - (needle->proxytype == check->proxytype) && - (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - needle->port == check->port) { - /* This is the same proxy connection, use it! */ - match = TRUE; + else { /* The requested needle connection is using a proxy, + is the checked one using the same host, port and type? */ + if(check->bits.proxy && + (needle->proxytype == check->proxytype) && + (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) && + Curl_raw_equal(needle->proxy.name, check->proxy.name) && + needle->port == check->port) { + /* This is the same proxy connection, use it! */ + match = TRUE; + } } - } - if(match) { - chosen = check; + if(match) { + chosen = check; - /* If we are not looking for an NTLM connection, we can choose this one - immediately. */ - if(!wantNTLM) - break; + /* If we are not looking for an NTLM connection, we can choose this one + immediately. */ + if(!wantNTLM) + break; - /* Otherwise, check if this is already authenticating with the right - credentials. If not, keep looking so that we can reuse NTLM - connections if possible. (Especially we must reuse the same - connection if partway through a handshake!) */ - if(credentialsMatch && chosen->ntlm.state != NTLMSTATE_NONE) - break; + /* Otherwise, check if this is already authenticating with the right + credentials. If not, keep looking so that we can reuse NTLM + connections if possible. (Especially we must reuse the same + connection if partway through a handshake!) */ + if(credentialsMatch && chosen->ntlm.state != NTLMSTATE_NONE) + break; + } } } @@ -3170,53 +2983,67 @@ ConnectionExists(struct SessionHandle *data, return FALSE; /* no matching connecting exists */ } - - /* * This function kills and removes an existing connection in the connection * cache. The connection that has been unused for the longest time. * - * Returns -1 if it can't find any unused connection to kill. + * Returns FALSE if it can't find any unused connection to kill. */ -static long +static bool ConnectionKillOne(struct SessionHandle *data) { - long i; - struct connectdata *conn; + struct conncache *bc = data->state.conn_cache; + struct curl_hash_iterator iter; + struct curl_llist_element *curr; + struct curl_hash_element *he; long highscore=-1; - long connindex=-1; long score; struct timeval now; + struct connectdata *conn_candidate = NULL; + struct connectbundle *bundle; now = Curl_tvnow(); - for(i=0; data->state.connc && (i< data->state.connc->num); i++) { - conn = data->state.connc->connects[i]; + Curl_hash_start_iterate(bc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectdata *conn; + + bundle = he->ptr; - if(!conn || conn->inuse) - continue; + curr = bundle->conn_list->head; + while(curr) { + conn = curr->ptr; - /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); + if(!conn->inuse) { + /* Set higher score for the age passed since the connection was used */ + score = Curl_tvdiff(now, conn->now); - if(score > highscore) { - highscore = score; - connindex = i; + if(score > highscore) { + highscore = score; + conn_candidate = conn; + } + } + curr = curr->next; } + + he = Curl_hash_next_element(&iter); } - if(connindex >= 0) { + + if(conn_candidate) { /* Set the connection's owner correctly */ - conn = data->state.connc->connects[connindex]; - conn->data = data; + conn_candidate->data = data; + + bundle = conn_candidate->bundle; /* the winner gets the honour of being disconnected */ - (void)Curl_disconnect(conn, /* dead_connection */ FALSE); + (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); - /* clean the array entry */ - data->state.connc->connects[connindex] = NULL; + return TRUE; } - return connindex; /* return the available index or -1 */ + return FALSE; } /* this connection can now be marked 'idle' */ @@ -3234,41 +3061,16 @@ ConnectionDone(struct connectdata *conn) * The given connection should be unique. That must've been checked prior to * this call. */ -static void ConnectionStore(struct SessionHandle *data, - struct connectdata *conn) +static CURLcode ConnectionStore(struct SessionHandle *data, + struct connectdata *conn) { - long i; - for(i=0; i< data->state.connc->num; i++) { - if(!data->state.connc->connects[i]) - break; - } - if(i == data->state.connc->num) { - /* there was no room available, kill one */ - i = ConnectionKillOne(data); - if(-1 != i) - infof(data, "Connection (#%ld) was killed to make room (holds %ld)\n", - i, data->state.connc->num); - else - infof(data, "This connection did not fit in the connection cache\n"); - } + static int connection_id_counter = 0; - conn->connectindex = i; /* Make the child know where the pointer to this - particular data is stored. But note that this -1 - if this is not within the cache and this is - probably not checked for everywhere (yet). */ - conn->inuse = TRUE; - if(-1 != i) { - /* Only do this if a true index was returned, if -1 was returned there - is no room in the cache for an unknown reason and we cannot store - this there. - - TODO: make sure we really can work with more handles than positions in - the cache, or possibly we should (allow to automatically) resize the - connection cache when we add more easy handles to a multi handle! - */ - data->state.connc->connects[i] = conn; /* fill in this */ - conn->data = data; - } + /* Assign a number to the connection for easier tracking in the log + output */ + conn->connection_id = connection_id_counter++; + + return Curl_conncache_add_conn(data->state.conn_cache, conn); } /* after a TCP connection to the proxy has been verified, this function does @@ -3318,7 +3120,7 @@ static CURLcode ConnectPlease(struct SessionHandle *data, infof(data, "About to connect() to %s%s port %ld (#%ld)\n", conn->bits.proxy?"proxy ":"", - hostname, conn->port, conn->connectindex); + hostname, conn->port, conn->connection_id); #else (void)data; #endif @@ -3359,7 +3161,7 @@ void Curl_verboseconnect(struct connectdata *conn) if(conn->data->set.verbose) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname, - conn->ip_addr_str, conn->port, conn->connectindex); + conn->ip_addr_str, conn->port, conn->connection_id); } #endif @@ -3618,7 +3420,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->connectindex = -1; /* no index */ + conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ /* Default protocol-independent behavior doesn't support persistent @@ -4898,7 +4700,7 @@ static CURLcode create_conn(struct SessionHandle *data, urllen=LEAST_PATH_ALLOC; /* - * We malloc() the buffers below urllen+2 to make room for to possibilities: + * We malloc() the buffers below urllen+2 to make room for 2 possibilities: * 1 - an extra terminating zero * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used) */ @@ -4960,8 +4762,8 @@ static CURLcode create_conn(struct SessionHandle *data, /* according to rfc3986, allow the query (?foo=bar) also on protocols that can't handle it. - cut the string-part after '?' - */ + cut the string-part after '?' + */ /* terminate the string */ path_q_sep[0] = 0; @@ -4975,7 +4777,7 @@ static CURLcode create_conn(struct SessionHandle *data, if(conn->bits.proxy_user_passwd) { result = parse_proxy_auth(data, conn); if(result != CURLE_OK) - return result; + return result; } /************************************************************* @@ -5178,7 +4980,7 @@ static CURLcode create_conn(struct SessionHandle *data, fix_hostname(data, conn, &conn->host); infof(data, "Re-using existing connection! (#%ld) with host %s\n", - conn->connectindex, + conn->connection_id, conn->proxy.name?conn->proxy.dispname:conn->host.dispname); } else { @@ -5443,12 +5245,8 @@ CURLcode Curl_done(struct connectdata **connp, 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, but currently we have no such detail knowledge. - - connectindex == -1 here means that the connection has no spot in the - connection cache and thus we must disconnect it here. */ - if(data->set.reuse_forbid || conn->bits.close || premature || - (-1 == conn->connectindex)) { + if(data->set.reuse_forbid || conn->bits.close || premature) { CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ /* If we had an error already, make sure we return that one. But @@ -5460,10 +5258,10 @@ CURLcode Curl_done(struct connectdata **connp, ConnectionDone(conn); /* the connection is no longer in use */ /* remember the most recently used connection */ - data->state.lastconnect = conn->connectindex; + data->state.lastconnect = conn; infof(data, "Connection #%ld to host %s left intact\n", - conn->connectindex, + conn->connection_id, conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); } |