diff options
Diffstat (limited to 'lib/tftp.c')
-rw-r--r-- | lib/tftp.c | 443 |
1 files changed, 156 insertions, 287 deletions
@@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, 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 @@ -20,30 +20,16 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_TFTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#if defined(WIN32) -#include <time.h> -#include <io.h> -#else -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif + +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -58,8 +44,6 @@ #include <sys/param.h> #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -72,14 +56,12 @@ #include "multiif.h" #include "url.h" #include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -#include "curl_memory.h" +#include "speedcheck.h" +#include "curl_printf.h" #include "select.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* RFC2348 allows the block size to be negotiated */ @@ -163,10 +145,11 @@ typedef struct tftp_state_data { /* Forward declarations */ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; +static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event); +static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event); static CURLcode tftp_connect(struct connectdata *conn, bool *done); -static CURLcode tftp_disconnect(struct connectdata *conn); +static CURLcode tftp_disconnect(struct connectdata *conn, + bool dead_connection); static CURLcode tftp_do(struct connectdata *conn, bool *done); static CURLcode tftp_done(struct connectdata *conn, CURLcode, bool premature); @@ -193,10 +176,13 @@ const struct Curl_handler Curl_handler_tftp = { tftp_doing, /* doing */ tftp_getsock, /* proto_getsock */ tftp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_TFTP, /* defport */ - PROT_TFTP /* protocol */ + CURLPROTO_TFTP, /* protocol */ + PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; /********************************************************** @@ -213,12 +199,12 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) { time_t maxtime, timeout; long timeout_ms; - bool start = (bool)(state->state == TFTP_STATE_START); + bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; time(&state->start_time); /* Compute drop-dead time */ - timeout_ms = Curl_timeleft(state->conn, NULL, start); + timeout_ms = Curl_timeleft(state->conn->data, NULL, start); if(timeout_ms < 0) { /* time-out, bail out, go home */ @@ -232,7 +218,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; /* Set per-block timeout to total */ - timeout = maxtime ; + timeout = maxtime; /* Average restart after 5 seconds */ state->retry_max = (int)timeout/5; @@ -255,11 +241,11 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; - /* Set per-block timeout to 10% of total */ - timeout = maxtime/10 ; + /* Set per-block timeout to total */ + timeout = maxtime; - /* Average reposting an ACK after 15 seconds */ - state->retry_max = (int)timeout/15; + /* Average reposting an ACK after 5 seconds */ + state->retry_max = (int)timeout/5; } /* But bound the total number */ if(state->retry_max<3) @@ -329,14 +315,14 @@ static const char *tftp_option_get(const char *buf, size_t len, loc = Curl_strnlen( buf, len ); loc++; /* NULL term */ - if (loc >= len) + if(loc >= len) return NULL; *option = buf; loc += Curl_strnlen( buf+loc, len-loc ); loc++; /* NULL term */ - if (loc > len) + if(loc > len) return NULL; *value = &buf[strlen(*option) + 1]; @@ -352,7 +338,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, /* if OACK doesn't contain blksize option, the default (512) must be used */ state->blksize = TFTP_BLKSIZE_DEFAULT; - while (tmp < ptr + len) { + while(tmp < ptr + len) { const char *option, *value; tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value); @@ -382,7 +368,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, TFTP_BLKSIZE_MIN); return CURLE_TFTP_ILLEGAL; } - else if (blksize > state->requested_blksize) { + else if(blksize > state->requested_blksize) { /* could realloc pkt buffers here, but the spec doesn't call out * support for the server requesting a bigger blksize than the client * requests */ @@ -403,7 +389,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, /* tsize should be ignored on upload: Who cares about the size of the remote file? */ - if (!data->set.upload) { + if(!data->set.upload) { if(!tsize) { failf(data, "invalid tsize -:%s:- value in OACK packet", value); return CURLE_TFTP_ILLEGAL; @@ -419,41 +405,41 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, static size_t tftp_option_add(tftp_state_data_t *state, size_t csize, char *buf, const char *option) { - if( ( strlen(option) + csize + 1 ) > (size_t)state->blksize ) + if(( strlen(option) + csize + 1 ) > (size_t)state->blksize) return 0; strcpy(buf, option); - return( strlen(option) + 1 ); + return strlen(option) + 1; } static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res; + CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct SessionHandle *data = state->conn->data; infof(data, "%s\n", "Connected for transmit"); #endif state->state = TFTP_STATE_TX; - res = tftp_set_timeouts(state); - if(res != CURLE_OK) - return(res); + result = tftp_set_timeouts(state); + if(result) + return result; return tftp_tx(state, event); } static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res; + CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct SessionHandle *data = state->conn->data; infof(data, "%s\n", "Connected for receive"); #endif state->state = TFTP_STATE_RX; - res = tftp_set_timeouts(state); - if(res != CURLE_OK) - return(res); + result = tftp_set_timeouts(state); + if(result) + return result; return tftp_rx(state, event); } @@ -465,7 +451,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) char *filename; char buf[64]; struct SessionHandle *data = state->conn->data; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; /* Set ascii mode if -B flag was used */ if(data->set.prefer_ascii) @@ -480,7 +466,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(state->retries>state->retry_max) { state->error = TFTP_ERR_NORESPONSE; state->state = TFTP_STATE_FIN; - return res; + return result; } if(data->set.upload) { @@ -488,8 +474,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) setpacketevent(&state->spacket, TFTP_EVENT_WRQ); state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4; - if(data->set.infilesize != -1) - Curl_pgrsSetUploadSize(data, data->set.infilesize); + if(data->state.infilesize != -1) + Curl_pgrsSetUploadSize(data, data->state.infilesize); } else { /* If we are downloading, send an RRQ */ @@ -509,8 +495,9 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) sbytes = 4 + strlen(filename) + strlen(mode); /* add tsize option */ - if(data->set.upload && (data->set.infilesize != -1)) - snprintf( buf, sizeof(buf), "%" FORMAT_OFF_T, data->set.infilesize ); + if(data->set.upload && (data->state.infilesize != -1)) + snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); else strcpy(buf, "0"); /* the destination is large enough */ @@ -544,24 +531,24 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(senddata != (ssize_t)sbytes) { failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); } - Curl_safefree(filename); + free(filename); break; case TFTP_EVENT_OACK: if(data->set.upload) { - res = tftp_connect_for_tx(state, event); + result = tftp_connect_for_tx(state, event); } else { - res = tftp_connect_for_rx(state, event); + result = tftp_connect_for_rx(state, event); } break; case TFTP_EVENT_ACK: /* Connected for transmit */ - res = tftp_connect_for_tx(state, event); + result = tftp_connect_for_tx(state, event); break; case TFTP_EVENT_DATA: /* Connected for receive */ - res = tftp_connect_for_rx(state, event); + result = tftp_connect_for_rx(state, event); break; case TFTP_EVENT_ERROR: @@ -572,7 +559,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) failf(state->conn->data, "tftp_send_first: internal error"); break; } - return res; + + return result; } /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit @@ -597,21 +585,25 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) case TFTP_EVENT_DATA: /* Is this the block we expect? */ rblock = getrpacketblock(&state->rpacket); - if(NEXT_BLOCKNUM(state->block) != rblock) { - /* No, log it, up the retry count and fail if over the limit */ + if(NEXT_BLOCKNUM(state->block) == rblock) { + /* This is the expected block. Reset counters and ACK it. */ + state->retries = 0; + } + else if(state->block == rblock) { + /* This is the last recently received block again. Log it and ACK it + again. */ + infof(data, "Received last DATA packet block %d again.\n", rblock); + } + else { + /* totally unexpected, just log it */ infof(data, - "Received unexpected DATA packet block %d\n", rblock); - state->retries++; - if(state->retries > state->retry_max) { - failf(data, "tftp_rx: giving up waiting for block %d", - NEXT_BLOCKNUM(state->block)); - return CURLE_TFTP_ILLEGAL; - } + "Received unexpected DATA packet block %d, expecting block %d\n", + rblock, NEXT_BLOCKNUM(state->block)); break; } - /* This is the expected block. Reset counters and ACK it. */ + + /* ACK this block. */ state->block = (unsigned short)rblock; - state->retries = 0; setpacketevent(&state->spacket, TFTP_EVENT_ACK); setpacketblock(&state->spacket, state->block); sbytes = sendto(state->sockfd, (void *)state->spacket.data, @@ -624,7 +616,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) } /* Check if completed (That is, a less than full packet is received) */ - if(state->rbytes < (ssize_t)state->blksize+4){ + if(state->rbytes < (ssize_t)state->blksize+4) { state->state = TFTP_STATE_FIN; } else { @@ -708,14 +700,14 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) struct SessionHandle *data = state->conn->data; ssize_t sbytes; int rblock; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; switch(event) { case TFTP_EVENT_ACK: case TFTP_EVENT_OACK: - if (event == TFTP_EVENT_ACK) { + if(event == TFTP_EVENT_ACK) { /* Ack the packet */ rblock = getrpacketblock(&state->rpacket); @@ -734,21 +726,22 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) if(state->retries>state->retry_max) { failf(data, "tftp_tx: giving up waiting for block %d ack", state->block); - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } else { /* Re-send the data packet */ - sbytes = sendto(state->sockfd, (void *)&state->spacket, + sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4+state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } } - return res; + + return result; } /* This is the expected packet. Reset the counters and send the next block */ @@ -765,11 +758,13 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) state->state = TFTP_STATE_FIN; return CURLE_OK; } - res = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); - if(res) - return res; - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4+state->sbytes, SEND_4TH_ARG, + + result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); + if(result) + return result; + + sbytes = sendto(state->sockfd, (void *) state->spacket.data, + 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ @@ -825,7 +820,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) break; } - return res; + return result; } /********************************************************** @@ -837,48 +832,47 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) **********************************************************/ static CURLcode tftp_translate_code(tftp_error_t error) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; if(error != TFTP_ERR_NONE) { switch(error) { case TFTP_ERR_NOTFOUND: - code = CURLE_TFTP_NOTFOUND; + result = CURLE_TFTP_NOTFOUND; break; case TFTP_ERR_PERM: - code = CURLE_TFTP_PERM; + result = CURLE_TFTP_PERM; break; case TFTP_ERR_DISKFULL: - code = CURLE_REMOTE_DISK_FULL; + result = CURLE_REMOTE_DISK_FULL; break; case TFTP_ERR_UNDEF: case TFTP_ERR_ILLEGAL: - code = CURLE_TFTP_ILLEGAL; + result = CURLE_TFTP_ILLEGAL; break; case TFTP_ERR_UNKNOWNID: - code = CURLE_TFTP_UNKNOWNID; + result = CURLE_TFTP_UNKNOWNID; break; case TFTP_ERR_EXISTS: - code = CURLE_REMOTE_FILE_EXISTS; + result = CURLE_REMOTE_FILE_EXISTS; break; case TFTP_ERR_NOSUCHUSER: - code = CURLE_TFTP_NOSUCHUSER; + result = CURLE_TFTP_NOSUCHUSER; break; case TFTP_ERR_TIMEOUT: - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; break; case TFTP_ERR_NORESPONSE: - code = CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; break; default: - code= CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; break; } } - else { - code = CURLE_OK; - } + else + result = CURLE_OK; - return(code); + return result; } /********************************************************** @@ -891,20 +885,21 @@ static CURLcode tftp_translate_code(tftp_error_t error) static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = state->conn->data; + switch(state->state) { case TFTP_STATE_START: DEBUGF(infof(data, "TFTP_STATE_START\n")); - res = tftp_send_first(state, event); + result = tftp_send_first(state, event); break; case TFTP_STATE_RX: DEBUGF(infof(data, "TFTP_STATE_RX\n")); - res = tftp_rx(state, event); + result = tftp_rx(state, event); break; case TFTP_STATE_TX: DEBUGF(infof(data, "TFTP_STATE_TX\n")); - res = tftp_tx(state, event); + result = tftp_tx(state, event); break; case TFTP_STATE_FIN: infof(data, "%s\n", "TFTP finished"); @@ -912,10 +907,11 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, default: DEBUGF(infof(data, "STATE: %d\n", state->state)); failf(data, "%s", "Internal state machine error"); - res = CURLE_TFTP_ILLEGAL; + result = CURLE_TFTP_ILLEGAL; break; } - return res; + + return result; } /********************************************************** @@ -925,9 +921,10 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, * The disconnect callback * **********************************************************/ -static CURLcode tftp_disconnect(struct connectdata *conn) +static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) { tftp_state_data_t *state = conn->proto.tftpc; + (void) dead_connection; /* done, free dynamically allocated pkt buffers */ if(state) { @@ -948,16 +945,11 @@ static CURLcode tftp_disconnect(struct connectdata *conn) **********************************************************/ static CURLcode tftp_connect(struct connectdata *conn, bool *done) { - CURLcode code; tftp_state_data_t *state; int blksize, rc; blksize = TFTP_BLKSIZE_DEFAULT; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t)); if(!state) return CURLE_OUT_OF_MEMORY; @@ -983,9 +975,9 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) return CURLE_OUT_OF_MEMORY; } - conn->bits.close = TRUE; /* we don't keep TFTP connections up bascially - because there's none or very little gain for UDP - */ + /* we don't keep TFTP connections up bascially because there's none or very + * little gain for UDP */ + connclose(conn, "TFTP"); state->conn = conn; state->sockfd = state->conn->sock[FIRSTSOCKET]; @@ -1026,8 +1018,8 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) Curl_pgrsStartNow(conn->data); *done = TRUE; - code = CURLE_OK; - return(code); + + return CURLE_OK; } /********************************************************** @@ -1040,18 +1032,20 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) static CURLcode tftp_done(struct connectdata *conn, CURLcode status, bool premature) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; (void)status; /* unused */ (void)premature; /* not used */ - Curl_pgrsDone(conn); + if(Curl_pgrsDone(conn)) + return CURLE_ABORTED_BY_CALLBACK; /* If we have encountered an error */ - code = tftp_translate_code(state->error); + if(state) + result = tftp_translate_code(state->error); - return code; + return result; } /********************************************************** @@ -1168,7 +1162,7 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) time_t current; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - if (event) + if(event) *event = TFTP_EVENT_NONE; time(¤t); @@ -1179,8 +1173,8 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) state->state = TFTP_STATE_FIN; return 0; } - else if (current > state->rx_time+state->retry_time) { - if (event) + else if(current > state->rx_time+state->retry_time) { + if(event) *event = TFTP_EVENT_TIMEOUT; time(&state->rx_time); /* update even though we received nothing */ } @@ -1191,130 +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, (int)(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 occured, 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 @@ -1337,11 +1207,11 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) failf(data, "TFTP response timeout"); return CURLE_OPERATION_TIMEDOUT; } - else if (event != TFTP_EVENT_NONE) { + else if(event != TFTP_EVENT_NONE) { result = tftp_state_machine(state, event); - if(result != CURLE_OK) - return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + if(result) + return result; + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1358,12 +1228,12 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else if(rc != 0) { result = tftp_receive_packet(conn); - if(result != CURLE_OK) - return(result); + if(result) + return result; result = tftp_state_machine(state, state->event); - if(result != CURLE_OK) - return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + if(result) + return result; + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1389,6 +1259,15 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done) if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } + else if(!result) { + /* The multi code doesn't have this logic for the DOING state so we + provide it for TFTP since it may do the entire transfer in this + state. */ + if(Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(conn->data, Curl_tvnow()); + } return result; } @@ -1408,15 +1287,10 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) result = tftp_state_machine(state, TFTP_EVENT_INIT); - if(state->state == TFTP_STATE_FIN || result != CURLE_OK) - return(result); + if((state->state == TFTP_STATE_FIN) || result) + 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")); @@ -1437,35 +1311,30 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) static CURLcode tftp_do(struct connectdata *conn, bool *done) { - tftp_state_data_t *state; - CURLcode code; + tftp_state_data_t *state; + CURLcode result; *done = FALSE; - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct TFTP' to play with. For new connections, - the struct TFTP is allocated and setup in the tftp_connect() function. - */ - Curl_reset_reqproto(conn); - if(!conn->proto.tftpc) { - code = tftp_connect(conn, done); - if(code) - return code; + result = tftp_connect(conn, done); + if(result) + return result; } + state = (tftp_state_data_t *)conn->proto.tftpc; + if(!state) + return CURLE_BAD_CALLING_ORDER; - code = tftp_perform(conn, done); + result = tftp_perform(conn, done); /* If tftp_perform() returned an error, use that for return code. If it was OK, see if tftp_translate_code() has an error. */ - if (code == CURLE_OK) + if(!result) /* If we have encountered an internal tftp error, translate it. */ - code = tftp_translate_code(state->error); + result = tftp_translate_code(state->error); - return code; + return result; } static CURLcode tftp_setup_connection(struct connectdata * conn) |