aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/conncache.c3
-rw-r--r--lib/conncache.h3
-rw-r--r--lib/url.c90
3 files changed, 71 insertions, 25 deletions
diff --git a/lib/conncache.c b/lib/conncache.c
index 290638ea0..5bbcf3c86 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -202,6 +202,7 @@ void Curl_conncache_foreach(struct conncache *connc,
struct connectdata *conn;
bundle = he->ptr;
+ he = Curl_hash_next_element(&iter);
curr = bundle->conn_list->head;
while(curr) {
@@ -213,8 +214,6 @@ void Curl_conncache_foreach(struct conncache *connc,
if(1 == func(conn, param))
return;
}
-
- he = Curl_hash_next_element(&iter);
}
}
diff --git a/lib/conncache.h b/lib/conncache.h
index 866554b63..d793f2482 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012, 2013, Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,6 +26,7 @@ struct conncache {
struct curl_hash *hash;
size_t num_connections;
long next_connection_id;
+ struct timeval last_cleanup;
};
struct conncache *Curl_conncache_init(int size);
diff --git a/lib/url.c b/lib/url.c
index 57d243822..cf9325308 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2913,6 +2913,69 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
}
/*
+ * This function checks if given connection is dead and disconnects if so.
+ * (That also removes it from the connection cache.)
+ *
+ * Returns TRUE if the connection actually was dead and disconnected.
+ */
+static bool disconnect_if_dead(struct connectdata *conn,
+ struct SessionHandle *data)
+{
+ size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
+ if(!pipeLen && !conn->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(conn->handler->protocol & CURLPROTO_RTSP)
+ /* RTSP is a special case due to RTP interleaving */
+ dead = Curl_rtsp_connisdead(conn);
+ else
+ dead = SocketIsDead(conn->sock[FIRSTSOCKET]);
+
+ if(dead) {
+ conn->data = data;
+ infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
+
+ /* disconnect resources */
+ Curl_disconnect(conn, /* dead_connection */TRUE);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Wrapper to use disconnect_if_dead() function in Curl_conncache_foreach()
+ *
+ * Returns always 0.
+ */
+static int call_disconnect_if_dead(struct connectdata *conn,
+ void *param)
+{
+ struct SessionHandle* data = (struct SessionHandle*)param;
+ disconnect_if_dead(conn, data);
+ return 0; /* continue iteration */
+}
+
+/*
+ * This function scans the connection cache for half-open/dead connections,
+ * closes and removes them.
+ * The cleanup is done at most once per second.
+ */
+static void prune_dead_connections(struct SessionHandle *data)
+{
+ struct timeval now = Curl_tvnow();
+ long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
+
+ if(elapsed >= 1000L) {
+ Curl_conncache_foreach(data->state.conn_cache, data,
+ call_disconnect_if_dead);
+ data->state.conn_cache->last_cleanup = now;
+ }
+}
+
+/*
* Given one filled in connection struct (named needle), this function should
* detect if there already is one that has all the significant details
* exactly the same and thus should be used instead.
@@ -2976,29 +3039,10 @@ ConnectionExists(struct SessionHandle *data,
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]);
-
- if(dead) {
- check->data = data;
- infof(data, "Connection %ld seems to be dead!\n",
- check->connection_id);
+ if(disconnect_if_dead(check, data))
+ continue;
- /* disconnect resources */
- Curl_disconnect(check, /* dead_connection */ TRUE);
- continue;
- }
- }
+ pipeLen = check->send_pipe->size + check->recv_pipe->size;
if(canPipeline) {
/* Make sure the pipe has only GET requests */
@@ -5460,6 +5504,8 @@ static CURLcode create_conn(struct SessionHandle *data,
goto out;
}
+ prune_dead_connections(data);
+
/*************************************************************
* Check the current list of connections to see if we can
* re-use an already existing one or if we have to create a