diff options
-rw-r--r-- | lib/tftp.c | 68 |
1 files changed, 42 insertions, 26 deletions
diff --git a/lib/tftp.c b/lib/tftp.c index 8dacca6f0..568d12cbb 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -151,8 +151,8 @@ typedef struct tftp_state_data { /* Forward declarations */ -static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; -static void 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) ; void tftp_set_timeouts(tftp_state_data_t *state) ; /********************************************************** @@ -249,12 +249,16 @@ static unsigned short getrpacketblock(tftp_packet_t *packet) return (packet->data[2] << 8) | packet->data[3]; } -static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) +static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) { int sbytes; const char *mode = "octet"; - char *filename = state->conn->path; + + /* As RFC3617 describes the separator slash is not actually part of the file + name so we skip the always-present first letter of the path string. */ + char *filename = &state->conn->path[1]; struct SessionHandle *data = state->conn->data; + CURLcode res; /* Set ascii mode if -B flag was used */ if(data->set.ftp_ascii) @@ -269,7 +273,7 @@ static void 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; + return res; } if(data->set.upload) { @@ -301,15 +305,13 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) infof(data, "%s\n", "Connected for transmit"); state->state = TFTP_STATE_TX; tftp_set_timeouts(state); - tftp_tx(state, event); - break; + return tftp_tx(state, event); case TFTP_EVENT_DATA: /* connected for receive */ infof(data, "%s\n", "Connected for receive"); state->state = TFTP_STATE_RX; tftp_set_timeouts(state); - tftp_rx(state, event); - break; + return tftp_rx(state, event); case TFTP_EVENT_ERROR: state->state = TFTP_STATE_FIN; @@ -319,6 +321,7 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) failf(state->conn->data, "tftp_send_first: internal error\n"); break; } + return res; } /********************************************************** @@ -328,7 +331,7 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) * Event handler for the RX state * **********************************************************/ -static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) +static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) { int sbytes; int rblock; @@ -348,7 +351,7 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) if (state->retries>state->retry_max) { failf(data, "tftp_rx: giving up waiting for block %d\n", state->block+1); - return; + return CURLE_TFTP_ILLEGAL; } } /* This is the expected block. Reset counters and ACK it. */ @@ -381,7 +384,8 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) if(state->retries > state->retry_max) { state->error = TFTP_ERR_TIMEOUT; state->state = TFTP_STATE_FIN; - } else { + } + else { /* Resend the previous ACK */ sbytes = sendto(state->sockfd, (void *)&state->spacket, 4, SEND_4TH_ARG, @@ -404,6 +408,7 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) } Curl_pgrsSetDownloadCounter(data, (curl_off_t) state->block*TFTP_BLOCKSIZE); + return CURLE_OK; } /********************************************************** @@ -413,11 +418,12 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) * Event handler for the TX state * **********************************************************/ -static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) +static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) { struct SessionHandle *data = state->conn->data; int sbytes; int rblock; + CURLcode res = CURLE_OK; switch(event) { @@ -432,10 +438,11 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) state->retries++; /* Bail out if over the maximum */ if(state->retries>state->retry_max) { - failf(data, "%s\n", - "tftp_tx: giving up waiting for block %d ack", + failf(data, "tftp_tx: giving up waiting for block %d ack", state->block); - } else { + res = CURLE_SEND_ERROR; + } + else { /* Re-send the data packet */ sbytes = sendto(state->sockfd, (void *)&state->spacket, 4+state->sbytes, SEND_4TH_ARG, @@ -444,9 +451,10 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno())); + res = CURLE_SEND_ERROR; } } - return; + return res; } /* This is the expected packet. Reset the counters and send the next block */ @@ -456,9 +464,11 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) setpacketblock(&state->spacket, state->block); if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) { state->state = TFTP_STATE_FIN; - return; + return CURLE_OK; } - Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes); + res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes); + if(res) + return res; sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4+state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, @@ -502,6 +512,8 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) /* Update the progress meter */ Curl_pgrsSetUploadCounter(data, (curl_off_t) state->block*TFTP_BLOCKSIZE); + + return res; } /********************************************************** @@ -514,19 +526,20 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { + CURLcode res = CURLE_OK; struct SessionHandle *data = state->conn->data; switch(state->state) { case TFTP_STATE_START: DEBUGF(infof(data, "TFTP_STATE_START\n")); - tftp_send_first(state, event); + res = tftp_send_first(state, event); break; case TFTP_STATE_RX: DEBUGF(infof(data, "TFTP_STATE_RX\n")); - tftp_rx(state, event); + res = tftp_rx(state, event); break; case TFTP_STATE_TX: DEBUGF(infof(data, "TFTP_STATE_TX\n")); - tftp_tx(state, event); + res = tftp_tx(state, event); break; case TFTP_STATE_FIN: infof(data, "%s\n", "TFTP finished"); @@ -534,9 +547,10 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, default: DEBUGF(infof(data, "STATE: %d\n", state->state)); failf(data, "%s\n", "Internal state machine error"); + res = CURLE_TFTP_ILLEGAL; break; } - return CURLE_OK; + return res; } @@ -711,8 +725,8 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done) } /* Update the progress meter */ - Curl_pgrsUpdate(conn); - + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; } } @@ -731,7 +745,9 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done) } /* Tell curl we're done */ - Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + code = Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL); + if(code) + return code; /* If we have encountered an error */ if(state->error) { |