diff options
-rw-r--r-- | lib/transfer.c | 372 | ||||
-rw-r--r-- | lib/transfer.h | 4 | ||||
-rw-r--r-- | lib/wildcard.h | 6 |
3 files changed, 5 insertions, 377 deletions
diff --git a/lib/transfer.c b/lib/transfer.c index 5e861f9fe..330b37a2b 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1245,156 +1245,6 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, return (long)rv; } - -/* - * Transfer() - * - * This function is what performs the actual transfer. It is capable of doing - * both ways simultaneously. The transfer must already have been setup by a - * call to Curl_setup_transfer(). - * - * Note that headers are created in a preallocated buffer of a default size. - * That buffer can be enlarged on demand, but it is never shrunken again. - * - */ - -static CURLcode -Transfer(struct connectdata *conn) -{ - CURLcode result; - struct SessionHandle *data = conn->data; - struct SingleRequest *k = &data->req; - bool done=FALSE; - bool first=TRUE; - long timeout_ms; - int buffersize; - long totmp; - - if((conn->sockfd == CURL_SOCKET_BAD) && - (conn->writesockfd == CURL_SOCKET_BAD)) - /* nothing to read, nothing to write, we're already OK! */ - return CURLE_OK; - - /* we want header and/or body, if neither then don't do this! */ - if(!k->getheader && data->set.opt_no_body) - return CURLE_OK; - - while(!done) { - curl_socket_t fd_read = conn->sockfd; - curl_socket_t fd_write = conn->writesockfd; - int keepon = k->keepon; - timeout_ms = 1000; - - if(conn->waitfor) { - /* if waitfor is set, get the RECV and SEND bits from that but keep the - other bits */ - keepon &= ~ (KEEP_RECV|KEEP_SEND); - keepon |= conn->waitfor & (KEEP_RECV|KEEP_SEND); - } - - /* limit-rate logic: if speed exceeds threshold, then do not include fd in - select set. The current speed is recalculated in each Curl_readwrite() - call */ - if((keepon & KEEP_SEND) && - (!data->set.max_send_speed || - (data->progress.ulspeed < data->set.max_send_speed) )) { - k->keepon &= ~KEEP_SEND_HOLD; - } - else { - if(data->set.upload && data->set.max_send_speed && - (data->progress.ulspeed > data->set.max_send_speed) ) { - /* calculate upload rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - totmp = Curl_sleep_time(data->set.max_send_speed, - data->progress.ulspeed, buffersize); - if(totmp < timeout_ms) - timeout_ms = totmp; - } - fd_write = CURL_SOCKET_BAD; - if(keepon & KEEP_SEND) - k->keepon |= KEEP_SEND_HOLD; /* hold it */ - } - - if((keepon & KEEP_RECV) && - (!data->set.max_recv_speed || - (data->progress.dlspeed < data->set.max_recv_speed)) ) { - k->keepon &= ~KEEP_RECV_HOLD; - } - else { - if((!data->set.upload) && data->set.max_recv_speed && - (data->progress.dlspeed > data->set.max_recv_speed)) { - /* Calculate download rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - totmp = Curl_sleep_time(data->set.max_recv_speed, - data->progress.dlspeed, buffersize); - if(totmp < timeout_ms) - timeout_ms = totmp; - } - fd_read = CURL_SOCKET_BAD; - if(keepon & KEEP_RECV) - k->keepon |= KEEP_RECV_HOLD; /* hold it */ - } - - /* pause logic. Don't check descriptors for paused connections */ - if(k->keepon & KEEP_RECV_PAUSE) - fd_read = CURL_SOCKET_BAD; - if(k->keepon & KEEP_SEND_PAUSE) - fd_write = CURL_SOCKET_BAD; - - /* The *_HOLD and *_PAUSE logic is necessary since even though there might - be no traffic during the select interval, we still call - Curl_readwrite() for the timeout case and if we limit transfer speed we - must make sure that this function doesn't transfer anything while in - HOLD status. - - The no timeout for the first round is for the protocols for which data - has already been slurped off the socket and thus waiting for action - won't work since it'll wait even though there is already data present - to work with. */ - if(first && - ((fd_read != CURL_SOCKET_BAD) || (fd_write != CURL_SOCKET_BAD))) - /* if this is the first lap and one of the file descriptors is fine - to work with, skip the timeout */ - timeout_ms = 0; - else { - totmp = Curl_timeleft(data, &k->now, FALSE); - if(totmp < 0) - return CURLE_OPERATION_TIMEDOUT; - else if(!totmp) - totmp = 1000; - - if(totmp < timeout_ms) - timeout_ms = totmp; - } - - switch (Curl_socket_ready(fd_read, fd_write, timeout_ms)) { - case -1: /* select() error, stop reading */ -#ifdef EINTR - /* The EINTR is not serious, and it seems you might get this more - often when using the lib in a multi-threaded environment! */ - if(SOCKERRNO == EINTR) - continue; -#endif - return CURLE_RECV_ERROR; /* indicate a network problem */ - case 0: /* timeout */ - default: /* readable descriptors */ - - result = Curl_readwrite(conn, &done); - /* "done" signals to us if the transfer(s) are ready */ - break; - } - if(result) - return result; - - first = FALSE; /* not the first lap anymore */ - } - - return CURLE_OK; -} - - /* * Curl_pretransfer() is called immediately before a transfer starts. */ @@ -1925,38 +1775,6 @@ CURLcode Curl_follow(struct SessionHandle *data, #endif /* CURL_DISABLE_HTTP */ } -static CURLcode -connect_host(struct SessionHandle *data, - struct connectdata **conn) -{ - CURLcode res = CURLE_OK; - - bool async; - bool protocol_done=TRUE; /* will be TRUE always since this is only used - within the easy interface */ - Curl_pgrsTime(data, TIMER_STARTSINGLE); - res = Curl_connect(data, conn, &async, &protocol_done); - - if((CURLE_OK == res) && async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - res = Curl_resolver_wait_resolv(*conn, NULL); - if(CURLE_OK == res) { - /* Resolved, continue with the connection */ - res = Curl_async_resolved(*conn, &protocol_done); - if(res) - *conn = NULL; - } - else { - /* if we can't resolve, we kill this "connection" now */ - (void)Curl_disconnect(*conn, /* dead_connection */ FALSE); - *conn = NULL; - } - } - - return res; -} - CURLcode Curl_reconnect_request(struct connectdata **connp) { @@ -2060,196 +1878,6 @@ CURLcode Curl_retry_request(struct connectdata *conn, return CURLE_OK; } -static CURLcode Curl_do_perform(struct SessionHandle *data) -{ - CURLcode res; - CURLcode res2; - struct connectdata *conn=NULL; - char *newurl = NULL; /* possibly a new URL to follow to! */ - followtype follow = FOLLOW_NONE; - - res = Curl_pretransfer(data); - if(res) - return res; - - /* - * It is important that there is NO 'return' from this function at any other - * place than falling down to the end of the function! This is because we - * have cleanup stuff that must be done before we get back, and that is only - * performed after this do-while loop. - */ - - for(;;) { - res = connect_host(data, &conn); /* primary connection */ - - if(res == CURLE_OK) { - bool do_done; - if(data->set.connect_only) { - /* keep connection open for application to use the socket */ - conn->bits.close = FALSE; - res = Curl_done(&conn, CURLE_OK, FALSE); - break; - } - res = Curl_do(&conn, &do_done); - - if(res == CURLE_OK) { - if(conn->data->set.wildcardmatch) { - if(conn->data->wildcard.state == CURLWC_DONE || - conn->data->wildcard.state == CURLWC_SKIP) { - /* keep connection open for application to use the socket */ - conn->bits.close = FALSE; - res = Curl_done(&conn, CURLE_OK, FALSE); - break; - } - } - res = Transfer(conn); /* now fetch that URL please */ - if((res == CURLE_OK) || (res == CURLE_RECV_ERROR)) { - bool retry = FALSE; - CURLcode rc = Curl_retry_request(conn, &newurl); - if(rc) - res = rc; - else - retry = (newurl?TRUE:FALSE); - - if(retry) { - /* we know (newurl != NULL) at this point */ - res = CURLE_OK; - follow = FOLLOW_RETRY; - } - else if(res == CURLE_OK) { - /* - * We must duplicate the new URL here as the connection data may - * be free()ed in the Curl_done() function. We prefer the newurl - * one since that's used for redirects or just further requests - * for retries or multi-stage HTTP auth methods etc. - */ - if(data->req.newurl) { - follow = FOLLOW_REDIR; - newurl = strdup(data->req.newurl); - if(!newurl) - res = CURLE_OUT_OF_MEMORY; - } - else if(data->req.location) { - follow = FOLLOW_FAKE; - newurl = strdup(data->req.location); - if(!newurl) - res = CURLE_OUT_OF_MEMORY; - } - } - - /* in the above cases where 'newurl' gets assigned, we have a fresh - * allocated memory pointed to */ - } - if(res != CURLE_OK) { - /* The transfer phase returned error, we mark the connection to get - * closed to prevent being re-used. This is because we can't - * possibly know if the connection is in a good shape or not now. */ - conn->bits.close = TRUE; - - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - /* if we failed anywhere, we must clean up the secondary socket if - it was used */ - Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } - } - - /* Always run Curl_done(), even if some of the previous calls - failed, but return the previous (original) error code */ - res2 = Curl_done(&conn, res, FALSE); - - if(CURLE_OK == res) - res = res2; - } - else if(conn) - /* Curl_do() failed, clean up left-overs in the done-call, but note - that at some cases the conn pointer is NULL when Curl_do() failed - and the connection cache is very small so only call Curl_done() if - conn is still "alive". */ - /* ignore return code since we already have an error to return */ - (void)Curl_done(&conn, res, FALSE); - - /* - * Important: 'conn' cannot be used here, since it may have been closed - * in 'Curl_done' or other functions. - */ - - if((res == CURLE_OK) && follow) { - res = Curl_follow(data, newurl, follow); - if(CURLE_OK == res) { - /* if things went fine, Curl_follow() freed or otherwise took - responsibility for the newurl pointer */ - newurl = NULL; - if(follow >= FOLLOW_RETRY) { - follow = FOLLOW_NONE; - continue; - } - /* else we break out of the loop below */ - } - } - } - break; /* it only reaches here when this shouldn't loop */ - - } /* loop if Location: */ - - if(newurl) - free(newurl); - - if(res && !data->state.errorbuf) { - /* - * As an extra precaution: if no error string has been set and there was - * an error, use the strerror() string or if things are so bad that not - * even that is good, set a bad string that mentions the error code. - */ - const char *str = curl_easy_strerror(res); - if(!str) - failf(data, "unspecified error %d", (int)res); - else - failf(data, "%s", str); - } - - /* run post-transfer unconditionally, but don't clobber the return code if - we already have an error code recorder */ - res2 = Curl_posttransfer(data); - if(!res && res2) - res = res2; - - return res; -} - -/* - * Curl_perform() is the internal high-level function that gets called by the - * external curl_easy_perform() function. It inits, performs and cleans up a - * single file transfer. - */ -CURLcode Curl_perform(struct SessionHandle *data) -{ - CURLcode res; - if(!data->set.wildcardmatch) - return Curl_do_perform(data); - - /* init main wildcard structures */ - res = Curl_wildcard_init(&data->wildcard); - if(res) - return res; - - res = Curl_do_perform(data); - if(res) { - Curl_wildcard_dtor(&data->wildcard); - return res; - } - - /* wildcard loop */ - while(!res && data->wildcard.state != CURLWC_DONE) - res = Curl_do_perform(data); - - Curl_wildcard_dtor(&data->wildcard); - - /* wildcard download finished or failed */ - data->wildcard.state = CURLWC_INIT; - return res; -} - /* * Curl_setup_transfer() is called to setup some basic properties for the * upcoming transfer. diff --git a/lib/transfer.h b/lib/transfer.h index b47422a63..ad4a3acd6 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, 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 @@ -21,7 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ -CURLcode Curl_perform(struct SessionHandle *data); + CURLcode Curl_pretransfer(struct SessionHandle *data); CURLcode Curl_second_connect(struct connectdata *conn); CURLcode Curl_posttransfer(struct SessionHandle *data); diff --git a/lib/wildcard.h b/lib/wildcard.h index 8f732d106..16c80ecbe 100644 --- a/lib/wildcard.h +++ b/lib/wildcard.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 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 @@ -33,8 +33,8 @@ typedef enum { CURLWC_CLEAN, /* deallocate resources and reset settings */ CURLWC_SKIP, /* skip over concrete file */ CURLWC_ERROR, /* error cases */ - CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop in - Curl_perform() will end */ + CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop + will end */ } curl_wildcard_states; typedef void (*curl_wildcard_tmp_dtor)(void *ptr); |