aboutsummaryrefslogtreecommitdiff
path: root/lib/easy.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/easy.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/easy.c')
-rw-r--r--lib/easy.c161
1 files changed, 44 insertions, 117 deletions
diff --git a/lib/easy.c b/lib/easy.c
index 700fb327b..2f4b48b80 100644
--- a/lib/easy.c
+++ b/lib/easy.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
@@ -385,40 +385,46 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
return ret;
}
-#ifdef CURL_MULTIEASY
-/***************************************************************************
- * This function is still only for testing purposes. It makes a great way
- * to run the full test suite on the multi interface instead of the easy one.
- ***************************************************************************
- *
- * The *new* curl_easy_perform() is the external interface that performs a
- * transfer previously setup.
+/*
+ * curl_easy_perform() is the external interface that performs a blocking
+ * transfer as previously setup.
*
- * Wrapper-function that: creates a multi handle, adds the easy handle to it,
+ * CONCEPT: This function creates a multi handle, adds the easy handle to it,
* runs curl_multi_perform() until the transfer is done, then detaches the
* easy handle, destroys the multi handle and returns the easy handle's return
- * code. This will make everything internally use and assume multi interface.
+ * code.
+ *
+ * REALITY: it can't just create and destroy the multi handle that easily. It
+ * needs to keep it around since if this easy handle is used again by this
+ * function, the same multi handle must be re-used so that the same pools and
+ * caches can be used.
*/
CURLcode curl_easy_perform(CURL *easy)
{
CURLM *multi;
CURLMcode mcode;
CURLcode code = CURLE_OK;
- int still_running;
- struct timeval timeout;
- int rc;
CURLMsg *msg;
- fd_set fdread;
- fd_set fdwrite;
- fd_set fdexcep;
- int maxfd;
+ bool done = FALSE;
+ int rc;
+ struct SessionHandle *data = easy;
if(!easy)
return CURLE_BAD_FUNCTION_ARGUMENT;
- multi = curl_multi_init();
- if(!multi)
- return CURLE_OUT_OF_MEMORY;
+ if(data->multi) {
+ failf(data, "easy handled already used in multi handle");
+ return CURLE_FAILED_INIT;
+ }
+
+ if(data->multi_easy)
+ multi = data->multi_easy;
+ else {
+ multi = curl_multi_init();
+ if(!multi)
+ return CURLE_OUT_OF_MEMORY;
+ data->multi_easy = multi;
+ }
mcode = curl_multi_add_handle(multi, easy);
if(mcode) {
@@ -429,108 +435,33 @@ CURLcode curl_easy_perform(CURL *easy)
return CURLE_FAILED_INIT;
}
- /* we start some action by calling perform right away */
-
- do {
- while(CURLM_CALL_MULTI_PERFORM ==
- curl_multi_perform(multi, &still_running));
-
- if(!still_running)
- break;
-
- FD_ZERO(&fdread);
- FD_ZERO(&fdwrite);
- FD_ZERO(&fdexcep);
-
- /* timeout once per second */
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-
- /* Old deprecated style: get file descriptors from the transfers */
- curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
- rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
-
- /* The way is to extract the sockets and wait for them without using
- select. This whole alternative version should probably rather use the
- curl_multi_socket() approach. */
-
- if(rc == -1)
- /* select error */
- break;
-
- /* timeout or data to send/receive => loop! */
- } while(still_running);
-
- msg = curl_multi_info_read(multi, &rc);
- if(msg)
- code = msg->data.result;
-
- mcode = curl_multi_remove_handle(multi, easy);
- /* what to do if it fails? */
-
- mcode = curl_multi_cleanup(multi);
- /* what to do if it fails? */
-
- return code;
-}
-#else
-/*
- * curl_easy_perform() is the external interface that performs a transfer
- * previously setup.
- */
-CURLcode curl_easy_perform(CURL *curl)
-{
- struct SessionHandle *data = (struct SessionHandle *)curl;
-
- if(!data)
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ /* assign this after curl_multi_add_handle() since that function checks for
+ it and rejects this handle otherwise */
+ data->multi = multi;
- if(! (data->share && data->share->hostcache)) {
- /* this handle is not using a shared dns cache */
+ while(!done && !mcode) {
+ int still_running;
- if(data->set.global_dns_cache &&
- (data->dns.hostcachetype != HCACHE_GLOBAL)) {
- /* global dns cache was requested but still isn't */
- struct curl_hash *ptr;
+ mcode = curl_multi_wait(multi, NULL, 0, 1000, NULL);
- if(data->dns.hostcachetype == HCACHE_PRIVATE) {
- /* if the current cache is private, kill it first */
- Curl_hash_destroy(data->dns.hostcache);
- data->dns.hostcachetype = HCACHE_NONE;
- data->dns.hostcache = NULL;
- }
+ if(mcode == CURLM_OK)
+ mcode = curl_multi_perform(multi, &still_running);
- ptr = Curl_global_host_cache_init();
- if(ptr) {
- /* only do this if the global cache init works */
- data->dns.hostcache = ptr;
- data->dns.hostcachetype = HCACHE_GLOBAL;
+ /* only read 'still_running' if curl_multi_perform() return OK */
+ if((mcode == CURLM_OK) && !still_running) {
+ msg = curl_multi_info_read(multi, &rc);
+ if(msg) {
+ code = msg->data.result;
+ done = TRUE;
}
}
-
- if(!data->dns.hostcache) {
- data->dns.hostcachetype = HCACHE_PRIVATE;
- data->dns.hostcache = Curl_mk_dnscache();
-
- if(!data->dns.hostcache)
- /* While we possibly could survive and do good without a host cache,
- the fact that creating it failed indicates that things are truly
- screwed up and we should bail out! */
- return CURLE_OUT_OF_MEMORY;
- }
-
}
- if(!data->state.conn_cache) {
- /* Oops, no connection cache, create one */
- data->state.conn_cache = Curl_conncache_init(CONNCACHE_PRIVATE);
- if(!data->state.conn_cache)
- return CURLE_OUT_OF_MEMORY;
- }
+ mcode = curl_multi_remove_handle(multi, easy);
- return Curl_perform(data);
+ /* The multi handle is kept alive, owned by the easy handle */
+ return code;
}
-#endif
/*
* curl_easy_cleanup() is the external interface to cleaning/freeing the given
@@ -553,10 +484,6 @@ void Curl_easy_addmulti(struct SessionHandle *data,
void *multi)
{
data->multi = multi;
- if(multi == NULL)
- /* the association is cleared, mark the easy handle as not used by an
- interface */
- data->state.used_interface = Curl_if_none;
}
void Curl_easy_initHandleData(struct SessionHandle *data)