diff options
| -rw-r--r-- | lib/tftp.c | 44 | 
1 files changed, 30 insertions, 14 deletions
| diff --git a/lib/tftp.c b/lib/tftp.c index 780cceea5..078dcfd8c 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -86,6 +86,9 @@  /* The last #include file should be: */  #include "memdebug.h" +/* RFC2348 allows the block size to be negotiated, but we don't support that */ +#define TFTP_BLOCKSIZE 512 +  typedef enum {    TFTP_MODE_NETASCII=0,    TFTP_MODE_OCTET @@ -122,7 +125,7 @@ typedef enum {  } tftp_error_t;  typedef struct tftp_packet { -  unsigned char data[516]; +  unsigned char data[2 + 2 + TFTP_BLOCKSIZE];  } tftp_packet_t;  typedef struct tftp_state_data { @@ -274,7 +277,7 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event)        /* If we are uploading, send an WRQ */        setpacketevent(&state->spacket, TFTP_EVENT_WRQ);        filename = curl_easy_unescape(data, filename, 0, NULL); -      state->conn->upload_fromhere = (char *)&state->spacket.data[2]; +      state->conn->upload_fromhere = (char *)&state->spacket.data[4];        if(data->set.infilesize != -1)          Curl_pgrsSetUploadSize(data, data->set.infilesize);      } @@ -283,7 +286,7 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event)        setpacketevent(&state->spacket, TFTP_EVENT_RRQ);      }      snprintf((char *)&state->spacket.data[2], -             512, +             TFTP_BLOCKSIZE,               "%s%c%s%c", filename, '\0',  mode, '\0');      sbytes = 4 + (int)strlen(filename) + (int)strlen(mode);      sbytes = sendto(state->sockfd, (void *)&state->spacket, @@ -291,7 +294,7 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event)                      state->conn->ip_addr->ai_addr,                      state->conn->ip_addr->ai_addrlen);      if(sbytes < 0) { -      failf(data, "%s\n", strerror(errno)); +      failf(data, "%s\n", Curl_strerror(state->conn, errno));      }      break; @@ -359,10 +362,10 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event)                      (struct sockaddr *)&state->remote_addr,                      state->remote_addrlen);      if(sbytes < 0) { -      failf(data, "%s\n", strerror(errno)); +      failf(data, "%s\n", Curl_strerror(state->conn, errno));      } -    /* Check if completed (That is, a less than full packet is recieved) */ +    /* Check if completed (That is, a less than full packet is received) */      if (state->rbytes < (int)sizeof(state->spacket)){        state->state = TFTP_STATE_FIN;      } @@ -387,7 +390,7 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event)                        state->remote_addrlen);        /* Check all sbytes were sent */        if(sbytes<0) { -        failf(data, "%s\n", strerror(errno)); +        failf(data, "%s\n", Curl_strerror(state->conn, errno));        }      }      break; @@ -401,7 +404,7 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event)      break;    }    Curl_pgrsSetDownloadCounter(data, -                              (curl_off_t) state->block*512); +                              (curl_off_t) state->block*TFTP_BLOCKSIZE);  }  /********************************************************** @@ -433,6 +436,16 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event)          failf(data, "%s\n",                "tftp_tx: giving up waiting for block %d ack",                state->block); +      } else { +	/* Re-send the data packet */ +	sbytes = sendto(state->sockfd, (void *)&state->spacket, +			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\n", Curl_strerror(state->conn, errno)); +	}        }        return;      } @@ -442,18 +455,18 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event)      state->retries = 0;      setpacketevent(&state->spacket, TFTP_EVENT_DATA);      setpacketblock(&state->spacket, state->block); -    if(state->block > 1 && state->sbytes < 512) { +    if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) {        state->state = TFTP_STATE_FIN;        return;      } -    Curl_fillreadbuffer(state->conn, 512, &state->sbytes); +    Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes);      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\n", strerror(errno)); +      failf(data, "%s\n", Curl_strerror(state->conn, errno));      }      break; @@ -474,7 +487,7 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event)                        state->remote_addrlen);        /* Check all sbytes were sent */        if(sbytes<0) { -        failf(data, "%s\n", strerror(errno)); +        failf(data, "%s\n", Curl_strerror(state->conn, errno));        }      }      break; @@ -489,7 +502,7 @@ 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*512); +  Curl_pgrsSetUploadCounter(data, (curl_off_t) state->block*TFTP_BLOCKSIZE);  }  /********************************************************** @@ -675,9 +688,12 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done)  	switch(event) {  	case TFTP_EVENT_DATA: -	  if (state->rbytes > 4) +	  /* Don't pass to the client empty or retransmitted packets */ +	  if (state->rbytes > 4 &&  +	      ((state->block+1) == getrpacketblock(&state->rpacket))) {  	    Curl_client_write(data, CLIENTWRITE_BODY,  			  (char *)&state->rpacket.data[4], state->rbytes-4); +	  }  	  break;  	case TFTP_EVENT_ERROR:  	  state->error = (tftp_error_t)getrpacketblock(&state->rpacket); | 
