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
This commit is contained in:
Daniel Stenberg
2013-01-17 12:59:23 +01:00
parent 9fd88abb70
commit c43127414d
54 changed files with 490 additions and 884 deletions

View File

@@ -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
@@ -1185,129 +1185,6 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
return (long)(state->max_time - current);
}
/**********************************************************
*
* tftp_easy_statemach
*
* Handle easy request until completion
*
**********************************************************/
static CURLcode tftp_easy_statemach(struct connectdata *conn)
{
int rc;
int check_time = 0;
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
curl_socket_t fd_read;
long timeout_ms;
struct SingleRequest *k = &data->req;
struct timeval transaction_start = Curl_tvnow();
k->start = transaction_start;
k->now = transaction_start;
/* Run the TFTP State Machine */
for(; (state->state != TFTP_STATE_FIN) && (result == CURLE_OK); ) {
timeout_ms = state->retry_time * 1000;
if(data->set.upload) {
if(data->set.max_send_speed &&
(data->progress.ulspeed > data->set.max_send_speed)) {
fd_read = CURL_SOCKET_BAD;
timeout_ms = Curl_sleep_time(data->set.max_send_speed,
data->progress.ulspeed, state->blksize);
}
else {
fd_read = state->sockfd;
}
}
else {
if(data->set.max_recv_speed &&
(data->progress.dlspeed > data->set.max_recv_speed)) {
fd_read = CURL_SOCKET_BAD;
timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
data->progress.dlspeed, state->blksize);
}
else
fd_read = state->sockfd;
}
if(data->set.timeout) {
timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
if(timeout_ms > state->retry_time * 1000)
timeout_ms = state->retry_time * 1000;
else if(timeout_ms < 0)
timeout_ms = 0;
}
/* Wait until ready to read or timeout occurs */
rc = Curl_socket_ready(fd_read, CURL_SOCKET_BAD, timeout_ms);
k->now = Curl_tvnow();
/* Force a progress callback if it's been too long */
if(Curl_tvdiff(k->now, k->start) >= data->set.timeout) {
if(Curl_pgrsUpdate(conn)) {
tftp_state_machine(state, TFTP_EVENT_ERROR);
return CURLE_ABORTED_BY_CALLBACK;
}
k->start = k->now;
}
if(rc == -1) {
/* bail out */
int error = SOCKERRNO;
failf(data, "%s", Curl_strerror(conn, error));
state->event = TFTP_EVENT_ERROR;
}
else {
if(rc==0) {
/* A timeout occurred, but our timeout is variable, so maybe
just continue? */
long rtms = state->retry_time * 1000;
if(Curl_tvdiff(k->now, transaction_start) > rtms) {
state->event = TFTP_EVENT_TIMEOUT;
/* Force a look at transfer timeouts */
check_time = 1;
}
else {
continue; /* skip state machine */
}
}
else {
result = tftp_receive_packet(conn);
if(result == CURLE_OK)
transaction_start = Curl_tvnow();
if(k->bytecountp)
*k->bytecountp = k->bytecount; /* read count */
if(k->writebytecountp)
*k->writebytecountp = k->writebytecount; /* write count */
}
}
if(check_time) {
tftp_state_timeout(conn, NULL);
check_time = 0;
}
if(result)
return(result);
result = tftp_state_machine(state, state->event);
}
/* Tell curl we're done */
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
return(result);
}
/**********************************************************
*
* tftp_multi_statemach
@@ -1404,12 +1281,7 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
return(result);
if(conn->data->state.used_interface == Curl_if_multi)
tftp_multi_statemach(conn, dophase_done);
else {
result = tftp_easy_statemach(conn);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
tftp_multi_statemach(conn, dophase_done);
if(*dophase_done)
DEBUGF(infof(conn->data, "DO phase is complete\n"));