diff options
author | Andy Cedilnik <andy.cedilnik@kitware.com> | 2004-10-05 13:34:20 (GMT) |
---|---|---|
committer | Andy Cedilnik <andy.cedilnik@kitware.com> | 2004-10-05 13:34:20 (GMT) |
commit | 609801fe67c95f9959468df8316a8f4a26943842 (patch) | |
tree | be2cf804edae61b76806c95bf0965985e4f45aed /Source/CTest/Curl/multi.c | |
parent | 50da0328472ad0f318f64a20876c474ad968fef3 (diff) | |
download | CMake-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.c | 426 |
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 - */ |