summaryrefslogtreecommitdiffstats
path: root/Source/CTest/Curl/multi.c
diff options
context:
space:
mode:
authorAndy Cedilnik <andy.cedilnik@kitware.com>2004-10-05 13:34:20 (GMT)
committerAndy Cedilnik <andy.cedilnik@kitware.com>2004-10-05 13:34:20 (GMT)
commit609801fe67c95f9959468df8316a8f4a26943842 (patch)
treebe2cf804edae61b76806c95bf0965985e4f45aed /Source/CTest/Curl/multi.c
parent50da0328472ad0f318f64a20876c474ad968fef3 (diff)
downloadCMake-609801fe67c95f9959468df8316a8f4a26943842.zip
CMake-609801fe67c95f9959468df8316a8f4a26943842.tar.gz
CMake-609801fe67c95f9959468df8316a8f4a26943842.tar.bz2
ENH: Update Curl to 7.12.1
Diffstat (limited to 'Source/CTest/Curl/multi.c')
-rw-r--r--Source/CTest/Curl/multi.c426
1 files changed, 252 insertions, 174 deletions
diff --git a/Source/CTest/Curl/multi.c b/Source/CTest/Curl/multi.c
index 630342b..12b987f 100644
--- a/Source/CTest/Curl/multi.c
+++ b/Source/CTest/Curl/multi.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, 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
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -24,20 +24,28 @@
#include "setup.h"
#include <stdlib.h>
#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include <curl/curl.h>
#include "urldata.h"
#include "transfer.h"
#include "url.h"
#include "connect.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+#include "progress.h"
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
struct Curl_message {
/* the 'CURLMsg' is the part that is visible to the external user */
@@ -47,7 +55,8 @@ struct Curl_message {
typedef enum {
CURLM_STATE_INIT,
- CURLM_STATE_CONNECT, /* connect has been sent off */
+ CURLM_STATE_CONNECT, /* resolve/connect has been sent off */
+ CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
CURLM_STATE_DO, /* send off the request (part 1) */
CURLM_STATE_DO_MORE, /* send off the request (part 2) */
@@ -62,7 +71,7 @@ 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 */
@@ -90,7 +99,7 @@ struct Curl_multi {
long type;
/* We have a linked list with easy handles */
- struct Curl_one_easy easy;
+ struct Curl_one_easy easy;
/* This is the amount of entries in the linked list above. */
int num_easy;
@@ -111,7 +120,15 @@ CURLM *curl_multi_init(void)
memset(multi, 0, sizeof(struct Curl_multi));
multi->type = CURL_MULTI_HANDLE;
}
-
+ else
+ return NULL;
+
+ multi->hostcache = Curl_mk_dnscache();
+ if(!multi->hostcache) {
+ /* failure, free mem and bail out */
+ free(multi);
+ multi = NULL;
+ }
return (CURLM *) multi;
}
@@ -124,7 +141,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
-
+
/* Verify that we got a somewhat good easy handle too */
if(!GOOD_EASY_HANDLE(easy_handle))
return CURLM_BAD_EASY_HANDLE;
@@ -133,18 +150,21 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
if(!easy)
return CURLM_OUT_OF_MEMORY;
-
+
/* clean it all first (just to be sure) */
memset(easy, 0, sizeof(struct Curl_one_easy));
/* set the easy handle */
easy->easy_handle = easy_handle;
easy->state = CURLM_STATE_INIT;
-
+
+ /* for multi interface connections, we share DNS cache automaticly */
+ easy->easy_handle->hostcache = multi->hostcache;
+
/* We add this new entry first in the list. We make our 'next' point to the
previous next and our 'prev' point back to the 'first' struct */
easy->next = multi->easy.next;
- easy->prev = &multi->easy;
+ easy->prev = &multi->easy;
/* make 'easy' the first node in the chain */
multi->easy.next = easy;
@@ -169,7 +189,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
-
+
/* Verify that we got a somewhat good easy handle too */
if(!GOOD_EASY_HANDLE(curl_handle))
return CURLM_BAD_EASY_HANDLE;
@@ -177,7 +197,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* scan through the list and remove the 'curl_handle' */
easy = multi->easy.next;
while(easy) {
- if((CURL*)(easy->easy_handle) == curl_handle)
+ if(easy->easy_handle == (struct SessionHandle *)curl_handle)
break;
easy=easy->next;
}
@@ -187,14 +207,14 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* clear out the usage of the shared DNS cache */
easy->easy_handle->hostcache = NULL;
-
+
/* make the previous node point to our next */
if(easy->prev)
easy->prev->next = easy->next;
/* make our next point to our previous node */
if(easy->next)
easy->next->prev = easy->prev;
-
+
/* NOTE NOTE NOTE
We do not touch the easy handle here! */
if (easy->msg)
@@ -230,30 +250,37 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
switch(easy->state) {
default:
break;
+ case CURLM_STATE_WAITRESOLVE:
+ /* waiting for a resolve to complete */
+ Curl_fdset(easy->easy_conn, read_fd_set, write_fd_set, &this_max_fd);
+ if(this_max_fd > *max_fd)
+ *max_fd = this_max_fd;
+ break;
+
case CURLM_STATE_WAITCONNECT:
case CURLM_STATE_DO_MORE:
{
/* when we're waiting for a connect, we wait for the socket to
become writable */
struct connectdata *conn = easy->easy_conn;
- int sockfd;
+ curl_socket_t sockfd;
if(CURLM_STATE_WAITCONNECT == easy->state) {
- sockfd = conn->firstsocket;
+ sockfd = conn->sock[FIRSTSOCKET];
FD_SET(sockfd, write_fd_set);
}
else {
/* When in DO_MORE state, we could be either waiting for us
to connect to a remote site, or we could wait for that site
to connect to us. It makes a difference in the way: if we
- connect to the site we wait for the socket to become writable, if
+ connect to the site we wait for the socket to become writable, if
the site connects to us we wait for it to become readable */
- sockfd = conn->secondarysocket;
+ sockfd = conn->sock[SECONDARYSOCKET];
FD_SET(sockfd, write_fd_set);
}
- if(sockfd > *max_fd)
- *max_fd = sockfd;
+ if((int)sockfd > *max_fd)
+ *max_fd = (int)sockfd;
}
break;
case CURLM_STATE_PERFORM:
@@ -284,6 +311,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
CURLMcode result=CURLM_OK;
struct Curl_message *msg = NULL;
bool connected;
+ bool async;
*running_handles = 0; /* bump this once for every living handle */
@@ -292,54 +320,106 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy=multi->easy.next;
while(easy) {
-
-#ifdef MALLOCDEBUG
+#if 0
fprintf(stderr, "HANDLE %p: State: %x\n",
(char *)easy, easy->state);
#endif
+ do {
+ if (CURLM_STATE_WAITCONNECT <= easy->state &&
+ easy->state <= CURLM_STATE_DO &&
+ easy->easy_handle->change.url_changed) {
+ char *gotourl;
+ Curl_posttransfer(easy->easy_handle);
- switch(easy->state) {
- case CURLM_STATE_INIT:
- /* init this transfer. */
- easy->result=Curl_pretransfer(easy->easy_handle);
-
- if(CURLE_OK == easy->result) {
- /* after init, go CONNECT */
- easy->state = CURLM_STATE_CONNECT;
- result = CURLM_CALL_MULTI_PERFORM;
-
- easy->easy_handle->state.used_interface = Curl_if_multi;
- }
- break;
- case CURLM_STATE_CONNECT:
- if (Curl_global_host_cache_use(easy->easy_handle)) {
- easy->easy_handle->hostcache = Curl_global_host_cache_get();
+ easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+ if(CURLE_OK == easy->result) {
+ gotourl = strdup(easy->easy_handle->change.url);
+ if(gotourl) {
+ easy->easy_handle->change.url_changed = FALSE;
+ easy->result = Curl_follow(easy->easy_handle, gotourl);
+ if(CURLE_OK == easy->result)
+ easy->state = CURLM_STATE_CONNECT;
+ else
+ free(gotourl);
+ }
+ else {
+ easy->result = CURLE_OUT_OF_MEMORY;
+ easy->state = CURLM_STATE_COMPLETED;
+ break;
+ }
+ }
}
- else {
- if (multi->hostcache == NULL)
- multi->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
- easy->easy_handle->hostcache = multi->hostcache;
- }
+ easy->easy_handle->change.url_changed = FALSE;
+
+ switch(easy->state) {
+ case CURLM_STATE_INIT:
+ /* init this transfer. */
+ easy->result=Curl_pretransfer(easy->easy_handle);
+
+ if(CURLE_OK == easy->result) {
+ /* after init, go CONNECT */
+ easy->state = CURLM_STATE_CONNECT;
+ result = CURLM_CALL_MULTI_PERFORM;
+
+ easy->easy_handle->state.used_interface = Curl_if_multi;
+ }
+ break;
+
+ case CURLM_STATE_CONNECT:
+ /* Connect. We get a connection identifier filled in. */
+ Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
+ easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
+ &async);
- /* Connect. We get a connection identifier filled in. */
- easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
+ if(CURLE_OK == easy->result) {
+ if(async)
+ /* We're now waiting for an asynchronous name lookup */
+ easy->state = CURLM_STATE_WAITRESOLVE;
+ else {
+ /* after the connect has been sent off, go WAITCONNECT */
+ easy->state = CURLM_STATE_WAITCONNECT;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ break;
+
+ case CURLM_STATE_WAITRESOLVE:
+ /* awaiting an asynch name resolve to complete */
+ {
+ struct Curl_dns_entry *dns = NULL;
+
+ /* check if we have the name resolved by now */
+ easy->result = Curl_is_resolved(easy->easy_conn, &dns);
- /* after the connect has been sent off, go WAITCONNECT */
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_WAITCONNECT;
- result = CURLM_CALL_MULTI_PERFORM;
+ if(dns) {
+ /* Perform the next step in the connection phase, and then move on
+ to the WAITCONNECT state */
+ easy->result = Curl_async_resolved(easy->easy_conn);
+
+ if(CURLE_OK != easy->result)
+ /* if Curl_async_resolved() returns failure, the connection struct
+ is already freed and gone */
+ easy->easy_conn = NULL; /* no more connection */
+
+ easy->state = CURLM_STATE_WAITCONNECT;
+ }
+
+ if(CURLE_OK != easy->result) {
+ /* failure detected */
+ Curl_disconnect(easy->easy_conn); /* disconnect properly */
+ easy->easy_conn = NULL; /* no more connection */
+ break;
+ }
}
break;
- case CURLM_STATE_WAITCONNECT:
- {
- bool connected;
- easy->result = Curl_is_connected(easy->easy_conn,
- easy->easy_conn->firstsocket,
+ case CURLM_STATE_WAITCONNECT:
+ /* awaiting a completion of an asynch connect */
+ easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
&connected);
if(connected)
- easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
+ easy->result = Curl_protocol_connect(easy->easy_conn);
if(CURLE_OK != easy->result) {
/* failure detected */
@@ -351,127 +431,131 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
if(connected) {
/* after the connect has completed, go DO */
easy->state = CURLM_STATE_DO;
- result = CURLM_CALL_MULTI_PERFORM;
+ result = CURLM_CALL_MULTI_PERFORM;
}
- }
- break;
+ break;
- case CURLM_STATE_DO:
- /* Do the fetch or put request */
- easy->result = Curl_do(&easy->easy_conn);
- if(CURLE_OK == easy->result) {
-
- /* after do, go PERFORM... or DO_MORE */
- if(easy->easy_conn->bits.do_more) {
- /* we're supposed to do more, but we need to sit down, relax
- and wait a little while first */
- easy->state = CURLM_STATE_DO_MORE;
- result = CURLM_OK;
- }
- else {
- /* we're done with the DO, now PERFORM */
- easy->result = Curl_readwrite_init(easy->easy_conn);
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_PERFORM;
- result = CURLM_CALL_MULTI_PERFORM;
+ case CURLM_STATE_DO:
+ /* Do the fetch or put request */
+ easy->result = Curl_do(&easy->easy_conn);
+ if(CURLE_OK == easy->result) {
+
+ /* after do, go PERFORM... or DO_MORE */
+ if(easy->easy_conn->bits.do_more) {
+ /* we're supposed to do more, but we need to sit down, relax
+ and wait a little while first */
+ easy->state = CURLM_STATE_DO_MORE;
+ result = CURLM_OK;
+ }
+ else {
+ /* we're done with the DO, now PERFORM */
+ easy->result = Curl_readwrite_init(easy->easy_conn);
+ if(CURLE_OK == easy->result) {
+ easy->state = CURLM_STATE_PERFORM;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
}
}
- }
- break;
+ break;
- case CURLM_STATE_DO_MORE:
- /*
- * First, check if we really are ready to do more.
- */
- easy->result = Curl_is_connected(easy->easy_conn,
- easy->easy_conn->secondarysocket,
- &connected);
- if(connected) {
+ case CURLM_STATE_DO_MORE:
/*
- * When we are connected, DO MORE and then go PERFORM
+ * First, check if we really are ready to do more.
*/
- easy->result = Curl_do_more(easy->easy_conn);
+ easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
+ &connected);
+ if(connected) {
+ /*
+ * When we are connected, DO MORE and then go PERFORM
+ */
+ easy->result = Curl_do_more(easy->easy_conn);
- if(CURLE_OK == easy->result)
- easy->result = Curl_readwrite_init(easy->easy_conn);
+ if(CURLE_OK == easy->result)
+ easy->result = Curl_readwrite_init(easy->easy_conn);
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_PERFORM;
- result = CURLM_CALL_MULTI_PERFORM;
+ if(CURLE_OK == easy->result) {
+ easy->state = CURLM_STATE_PERFORM;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
}
- }
- break;
+ break;
- case CURLM_STATE_PERFORM:
- /* read/write data if it is ready to do so */
- easy->result = Curl_readwrite(easy->easy_conn, &done);
-
- if(easy->result) {
- /* The transfer phase returned error, we mark the connection to get
- * closed to prevent being re-used. This is becasue we can't
- * possibly know if the connection is in a good shape or not now. */
- easy->easy_conn->bits.close = TRUE;
-
- if(-1 !=easy->easy_conn->secondarysocket) {
- /* if we failed anywhere, we must clean up the secondary socket if
- it was used */
- sclose(easy->easy_conn->secondarysocket);
- easy->easy_conn->secondarysocket=-1;
+ case CURLM_STATE_PERFORM:
+ /* read/write data if it is ready to do so */
+ easy->result = Curl_readwrite(easy->easy_conn, &done);
+
+ if(easy->result) {
+ /* The transfer phase returned error, we mark the connection to get
+ * closed to prevent being re-used. This is becasue we can't
+ * possibly know if the connection is in a good shape or not now. */
+ easy->easy_conn->bits.close = TRUE;
+
+ if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
+ /* if we failed anywhere, we must clean up the secondary socket if
+ it was used */
+ sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
+ easy->easy_conn->sock[SECONDARYSOCKET]=-1;
+ }
+ Curl_posttransfer(easy->easy_handle);
+ Curl_done(&easy->easy_conn, easy->result);
}
- Curl_posttransfer(easy->easy_handle);
- Curl_done(easy->easy_conn);
- }
-
- /* after the transfer is done, go DONE */
- else if(TRUE == done) {
-
- /* call this even if the readwrite function returned error */
- Curl_posttransfer(easy->easy_handle);
- /* When we follow redirects, must to go back to the CONNECT state */
- if(easy->easy_conn->newurl) {
- easy->result = Curl_follow(easy->easy_handle,
- strdup(easy->easy_conn->newurl));
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_CONNECT;
+ /* after the transfer is done, go DONE */
+ else if(TRUE == done) {
+
+ /* call this even if the readwrite function returned error */
+ Curl_posttransfer(easy->easy_handle);
+
+ /* When we follow redirects, must to go back to the CONNECT state */
+ if(easy->easy_conn->newurl) {
+ char *newurl = easy->easy_conn->newurl;
+ easy->easy_conn->newurl = NULL;
+ easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+ if(easy->result == CURLE_OK)
+ easy->result = Curl_follow(easy->easy_handle, newurl);
+ if(CURLE_OK == easy->result) {
+ easy->state = CURLM_STATE_CONNECT;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ else {
+ easy->state = CURLM_STATE_DONE;
result = CURLM_CALL_MULTI_PERFORM;
}
}
- else {
- easy->state = CURLM_STATE_DONE;
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
- break;
- case CURLM_STATE_DONE:
- /* post-transfer command */
- easy->result = Curl_done(easy->easy_conn);
+ break;
+ case CURLM_STATE_DONE:
+ /* post-transfer command */
+ easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
- /* after we have DONE what we're supposed to do, go COMPLETED, and
- it doesn't matter what the Curl_done() returned! */
- easy->state = CURLM_STATE_COMPLETED;
- break;
+ /* after we have DONE what we're supposed to do, go COMPLETED, and
+ it doesn't matter what the Curl_done() returned! */
+ easy->state = CURLM_STATE_COMPLETED;
+ break;
- case CURLM_STATE_COMPLETED:
- /* this is a completed transfer, it is likely to still be connected */
+ case CURLM_STATE_COMPLETED:
+ /* this is a completed transfer, it is likely to still be connected */
- /* This node should be delinked from the list now and we should post
- an information message that we are complete. */
- break;
- default:
- return CURLM_INTERNAL_ERROR;
- }
+ /* This node should be delinked from the list now and we should post
+ an information message that we are complete. */
+ break;
+ default:
+ return CURLM_INTERNAL_ERROR;
+ }
- if(CURLM_STATE_COMPLETED != easy->state) {
- if(CURLE_OK != easy->result)
- /*
- * If an error was returned, and we aren't in completed state now,
- * then we go to completed and consider this transfer aborted. */
- easy->state = CURLM_STATE_COMPLETED;
- else
- /* this one still lives! */
- (*running_handles)++;
- }
+ if(CURLM_STATE_COMPLETED != easy->state) {
+ if(CURLE_OK != easy->result) {
+ /*
+ * If an error was returned, and we aren't in completed state now,
+ * then we go to completed and consider this transfer aborted. */
+ easy->state = CURLM_STATE_COMPLETED;
+ }
+ else
+ /* this one still lives! */
+ (*running_handles)++;
+ }
+
+ } while (easy->easy_handle->change.url_changed);
if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
/* clear out the usage of the shared DNS cache */
@@ -535,9 +619,11 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
{
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ *msgs_in_queue = 0; /* default to none */
+
if(GOOD_MULTI_HANDLE(multi)) {
struct Curl_one_easy *easy;
-
+
if(!multi->num_msgs)
return NULL; /* no messages left to return */
@@ -560,11 +646,3 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
else
return NULL;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */