aboutsummaryrefslogtreecommitdiff
path: root/lib/multi.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2013-01-17 12:59:23 +0100
committerDaniel Stenberg <daniel@haxx.se>2013-01-17 19:40:35 +0100
commitc43127414d89ccb9ef6517081f68986d991bcfb3 (patch)
treef6a639061f5e199089a923b052904aa24901243c /lib/multi.c
parent9fd88abb7032346e88636165e688232e36f5c336 (diff)
always-multi: always use non-blocking internals
Remove internal separated behavior of the easy vs multi intercace. curl_easy_perform() is now using the multi interface itself. Several minor multi interface quirks and bugs have been fixed in the process. Much help with debugging this has been provided by: Yang Tse
Diffstat (limited to 'lib/multi.c')
-rw-r--r--lib/multi.c183
1 files changed, 31 insertions, 152 deletions
diff --git a/lib/multi.c b/lib/multi.c
index de1fc7d6e..fa0afb9f8 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, 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
@@ -39,6 +39,7 @@
#include "speedcheck.h"
#include "conncache.h"
#include "bundles.h"
+#include "multihandle.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -56,62 +57,6 @@
#define CURL_SOCKET_HASH_TABLE_SIZE 911
#endif
-struct Curl_message {
- /* the 'CURLMsg' is the part that is visible to the external user */
- struct CURLMsg extmsg;
-};
-
-/* NOTE: if you add a state here, add the name to the statename[] array as
- well!
-*/
-typedef enum {
- CURLM_STATE_INIT, /* 0 - start in this state */
- CURLM_STATE_CONNECT, /* 1 - resolve/connect has been sent off */
- CURLM_STATE_WAITRESOLVE, /* 2 - awaiting the resolve to finalize */
- CURLM_STATE_WAITCONNECT, /* 3 - awaiting the connect to finalize */
- CURLM_STATE_WAITPROXYCONNECT, /* 4 - awaiting proxy CONNECT to finalize */
- CURLM_STATE_PROTOCONNECT, /* 5 - completing the protocol-specific connect
- phase */
- CURLM_STATE_WAITDO, /* 6 - wait for our turn to send the request */
- CURLM_STATE_DO, /* 7 - start send off the request (part 1) */
- CURLM_STATE_DOING, /* 8 - sending off the request (part 1) */
- CURLM_STATE_DO_MORE, /* 9 - send off the request (part 2) */
- CURLM_STATE_DO_DONE, /* 10 - done sending off request */
- CURLM_STATE_WAITPERFORM, /* 11 - wait for our turn to read the response */
- CURLM_STATE_PERFORM, /* 12 - transfer data */
- CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */
- CURLM_STATE_DONE, /* 14 - post data transfer operation */
- CURLM_STATE_COMPLETED, /* 15 - operation complete */
- CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */
- CURLM_STATE_LAST /* 17 - not a true state, never use this */
-} CURLMstate;
-
-/* we support N sockets per easy handle. Set the corresponding bit to what
- action we should wait for */
-#define MAX_SOCKSPEREASYHANDLE 5
-#define GETSOCK_READABLE (0x00ff)
-#define GETSOCK_WRITABLE (0xff00)
-
-struct Curl_one_easy {
- /* first, two fields for the linked list of these */
- struct Curl_one_easy *next;
- struct Curl_one_easy *prev;
-
- struct SessionHandle *easy_handle; /* the easy handle for this unit */
- struct connectdata *easy_conn; /* the "unit's" connection */
-
- CURLMstate state; /* the handle's state */
- CURLcode result; /* previous result */
-
- struct Curl_message msg; /* A single posted message. */
-
- /* Array with the plain socket numbers this handle takes care of, in no
- particular order. Note that all sockets are added to the sockhash, where
- the state etc are also kept. This array is mostly used to detect when a
- socket is to be removed from the hash. See singlesocket(). */
- curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
- int numsocks;
-};
#define CURL_MULTI_HANDLE 0x000bab1e
@@ -120,57 +65,6 @@ struct Curl_one_easy {
#define GOOD_EASY_HANDLE(x) \
((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
-/* This is the struct known as CURLM on the outside */
-struct Curl_multi {
- /* First a simple identifier to easier detect if a user mix up
- this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
- long type;
-
- /* We have a doubly-linked circular list with easy handles */
- struct Curl_one_easy easy;
-
- int num_easy; /* amount of entries in the linked list above. */
- int num_alive; /* amount of easy handles that are added but have not yet
- reached COMPLETE state */
-
- struct curl_llist *msglist; /* a list of messages from completed transfers */
-
- /* callback function and user data pointer for the *socket() API */
- curl_socket_callback socket_cb;
- void *socket_userp;
-
- /* Hostname cache */
- struct curl_hash *hostcache;
-
- /* timetree points to the splay-tree of time nodes to figure out expire
- times of all currently set timers */
- struct Curl_tree *timetree;
-
- /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
- the pluralis form, there can be more than one easy handle waiting on the
- same actual socket) */
- struct curl_hash *sockhash;
-
- /* Whether pipelining is enabled for this multi handle */
- bool pipelining_enabled;
-
- /* Shared connection cache (bundles)*/
- struct conncache *conn_cache;
-
- /* This handle will be used for closing the cached connections in
- curl_multi_cleanup() */
- struct SessionHandle *closure_handle;
-
- long maxconnects; /* if >0, a fixed limit of the maximum number of entries
- we're allowed to grow the connection cache to */
-
- /* timer callback and user data pointer for the *socket() API */
- curl_multi_timer_callback timer_cb;
- void *timer_userp;
- struct timeval timer_lastcall; /* the fixed time for the timeout for the
- previous callback */
-};
-
static void singlesocket(struct Curl_multi *multi,
struct Curl_one_easy *easy);
static int update_timer(struct Curl_multi *multi);
@@ -213,7 +107,11 @@ static const char * const statename[]={
static void multi_freetimeout(void *a, void *b);
/* always use this function to change state, to make debugging easier */
-static void multistate(struct Curl_one_easy *easy, CURLMstate state)
+static void mstate(struct Curl_one_easy *easy, CURLMstate state
+#ifdef DEBUGBUILD
+ , int lineno
+#endif
+)
{
#ifdef DEBUGBUILD
long connection_id = -5000;
@@ -233,9 +131,9 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
connection_id = easy->easy_conn->connection_id;
infof(easy->easy_handle,
- "STATE: %s => %s handle %p; (connection #%ld) \n",
+ "STATE: %s => %s handle %p; line %d (connection #%ld) \n",
statename[oldstate], statename[easy->state],
- (char *)easy, connection_id);
+ (char *)easy, lineno, connection_id);
}
#endif
if(state == CURLM_STATE_COMPLETED)
@@ -243,6 +141,12 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
easy->easy_handle->multi->num_alive--;
}
+#ifndef DEBUGBUILD
+#define multistate(x,y) mstate(x,y)
+#else
+#define multistate(x,y) mstate(x,y, __LINE__)
+#endif
+
/*
* We add one of these structs to the sockhash for a particular socket
*/
@@ -396,7 +300,7 @@ CURLM *curl_multi_init(void)
if(!multi->sockhash)
goto error;
- multi->conn_cache = Curl_conncache_init(CONNCACHE_MULTI);
+ multi->conn_cache = Curl_conncache_init();
if(!multi->conn_cache)
goto error;
@@ -516,29 +420,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
easy->easy_handle->multi_pos = easy;
/* for multi interface connections, we share DNS cache automatically if the
- easy handle's one is currently private. */
- if(easy->easy_handle->dns.hostcache &&
- (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
- Curl_hash_destroy(easy->easy_handle->dns.hostcache);
- easy->easy_handle->dns.hostcache = NULL;
- easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
- }
-
+ easy handle's one is currently not set. */
if(!easy->easy_handle->dns.hostcache ||
(easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
easy->easy_handle->dns.hostcache = multi->hostcache;
easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
}
- /* On a multi stack the connection cache, owned by the multi handle,
- is shared between all easy handles within the multi handle.
- Therefore we free the private connection cache if there is one */
- if(easy->easy_handle->state.conn_cache &&
- easy->easy_handle->state.conn_cache->type == CONNCACHE_PRIVATE) {
- Curl_conncache_destroy(easy->easy_handle->state.conn_cache);
- }
-
- /* Point now to this multi's connection cache */
+ /* Point to the multi's connection cache */
easy->easy_handle->state.conn_cache = multi->conn_cache;
/* This adds the new entry at the 'end' of the doubly-linked circular
@@ -666,18 +555,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
}
if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
- if(multi->num_easy == 1) {
- if(easy_owns_conn) {
- Curl_resolver_cancel(easy->easy_conn);
- if(easy->easy_conn->dns_entry) {
- Curl_resolv_unlock(easy->easy_handle, easy->easy_conn->dns_entry);
- easy->easy_conn->dns_entry = NULL;
- }
- }
- Curl_hostcache_destroy(easy->easy_handle);
- multi->hostcache = NULL;
- }
- /* clear out the usage of the shared DNS cache */
+ /* stop using the multi handle's DNS cache */
easy->easy_handle->dns.hostcache = NULL;
easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
}
@@ -700,12 +578,9 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn);
}
- if(easy->easy_handle->state.conn_cache->type == CONNCACHE_MULTI) {
- /* if this was using the shared connection cache we clear the pointer
- to that since we're not part of that handle anymore */
- easy->easy_handle->state.conn_cache = NULL;
- easy->easy_handle->state.lastconnect = NULL;
- }
+ /* as this was using a shared connection cache we clear the pointer
+ to that since we're not part of that multi handle anymore */
+ easy->easy_handle->state.conn_cache = NULL;
/* change state without using multistate(), only to make singlesocket() do
what we want */
@@ -1025,7 +900,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool connected;
bool async;
bool protocol_connect = FALSE;
- bool dophase_done;
+ bool dophase_done = FALSE;
bool done = FALSE;
CURLMcode result = CURLM_OK;
struct SingleRequest *k;
@@ -1120,8 +995,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* after init, go CONNECT */
multistate(easy, CURLM_STATE_CONNECT);
result = CURLM_CALL_MULTI_PERFORM;
-
- data->state.used_interface = Curl_if_multi;
}
break;
@@ -1577,9 +1450,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!ret)
retry = (newurl)?TRUE:FALSE;
- if(retry)
- /* if we are to retry, set the result to OK */
+ if(retry) {
+ /* if we are to retry, set the result to OK and consider the
+ request as done */
easy->result = CURLE_OK;
+ done = TRUE;
+ }
}
if(easy->result) {
@@ -1897,6 +1773,9 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
/* Close all the connections in the connection cache */
close_all_connections(multi);
+ multi->closure_handle->dns.hostcache = multi->hostcache;
+ Curl_hostcache_clean(multi->closure_handle);
+
Curl_close(multi->closure_handle);
multi->closure_handle = NULL;