initial commit
This commit is contained in:
378
lib/amb1_sdk/common/network/tftp/tftp_client.c
Normal file
378
lib/amb1_sdk/common/network/tftp/tftp_client.c
Normal file
@@ -0,0 +1,378 @@
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <platform/platform_stdlib.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netdb.h>
|
||||
#include "tftp.h"
|
||||
|
||||
#include "wifi_conf.h"
|
||||
|
||||
int req_packet (int opcode, const char *filename,const char *mode, char buf[], int size)
|
||||
{
|
||||
int len;
|
||||
|
||||
len =sprintf (buf, "%c%c%s%c%s%c", 0x00, opcode, filename, 0x00, mode, 0x00);
|
||||
|
||||
if (len == 0){
|
||||
printf ("Error in creating the request packet\r\n"); /*could not print to the client buffer */
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void ip_port (struct sockaddr_in host)
|
||||
{
|
||||
printf ("The IP port pair for the host is: IP:%s Port:%d \n",inet_ntoa (host.sin_addr), ntohs (host.sin_port));
|
||||
}
|
||||
|
||||
|
||||
int tftp_client_send (const char *pFilename, struct sockaddr_in server,const char *pMode, int sock,tftp *tftp_handler)
|
||||
{
|
||||
/* local variables */
|
||||
int len, server_len, opcode, j, n, tid = 0;
|
||||
unsigned short int count = 0, rcount = 0;
|
||||
unsigned char packetbuf[64];
|
||||
char *bufindex;
|
||||
struct sockaddr_in data;
|
||||
|
||||
n = BLOCK_SIZE;
|
||||
|
||||
fd_set read_fds;
|
||||
struct timeval time_out;
|
||||
|
||||
while(1){
|
||||
|
||||
for (j = 0; j < tftp_handler->tftp_retry_num; j++){ /* this allows us to loop until we either break out by getting the correct ack OR time out because we've looped more than RETRIES times */
|
||||
|
||||
server_len = sizeof (data);
|
||||
time_out.tv_sec = tftp_handler->tftp_timeout; // Set select timeout of 3 seconds
|
||||
time_out.tv_usec = 0;
|
||||
FD_ZERO(&read_fds) ;
|
||||
FD_SET(sock, &read_fds); // Only set server fd
|
||||
if(select(sock + 1, &read_fds, NULL, NULL, &time_out) == 1){
|
||||
n = recvfrom (sock, tftp_handler->tftp_buf, BLOCK_SIZE, 0,(struct sockaddr *) &data,(socklen_t *) & server_len);
|
||||
if(n < 0){
|
||||
printf("could not read datagram\r\n");
|
||||
goto exit;
|
||||
}
|
||||
}else{
|
||||
if(count == 0){
|
||||
printf("Resend the wrq request");
|
||||
goto exit;
|
||||
}else{
|
||||
printf("timeout\r\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//printf("get count = %d num = %d\r\n",count,n);
|
||||
|
||||
if (!tid){
|
||||
tid = ntohs (data.sin_port); //get the tid of the server.
|
||||
server.sin_port = htons (tid); //set the tid for rest of the transfer
|
||||
}
|
||||
|
||||
if (server.sin_addr.s_addr != data.sin_addr.s_addr){ /* checks to ensure get from ip is same from ACK IP */
|
||||
printf("Error recieving file (data from invalid address)\n");
|
||||
j--;
|
||||
continue; /* we aren't going to let another connection spoil our first connection */
|
||||
}
|
||||
|
||||
if (tid != ntohs (server.sin_port)){ /* checks to ensure get from the correct TID */
|
||||
printf ("Error recieving file (data from invalid tid)\n");
|
||||
len = sprintf ((char *) packetbuf,"%c%c%c%cBad/Unknown TID%c",0x00, 0x05, 0x00, 0x05, 0x00);
|
||||
if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &server, sizeof (server)) != len){ /* send the data packet */
|
||||
printf("Mismatch in number of sent bytes while trying to send mode error packet\n");
|
||||
}
|
||||
j--;
|
||||
continue; /* we aren't going to let another connection spoil our first connection */
|
||||
}
|
||||
|
||||
/* this formatting code is just like the code in the main function */
|
||||
bufindex = (char *) tftp_handler->tftp_buf; //start our pointer going
|
||||
if (bufindex++[0] != 0x00){
|
||||
printf ("bad first nullbyte!\n");
|
||||
goto exit;
|
||||
}
|
||||
opcode = *bufindex++;
|
||||
rcount = *bufindex++ << 8;
|
||||
rcount &= 0xff00;
|
||||
rcount += (*bufindex++ & 0x00ff);
|
||||
|
||||
if (opcode != 0X04 ){ /* ack packet should have code 3 (data) and should be ack+1 the packet we just sent */
|
||||
printf("Client: Remote host failed to ACK proper data packet # %d (got OP: %d Block: %d)\n",count, opcode, rcount);
|
||||
//printf("Badly ordered/invalid data packet (Got OP: %d Block: %d) (Wanted Op: 3 Block: %d)\n",opcode, rcount, count);
|
||||
/* sending error message */
|
||||
if (opcode > 5)
|
||||
{
|
||||
len = sprintf ((char *) packetbuf,"%c%c%c%cIllegal operation%c",0x00, 0x05, 0x00, 0x04, 0x00);
|
||||
if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &server, sizeof (server)) != len){ /* send the data packet */
|
||||
printf("Mismatch in number of sent bytes while trying to send mode error packet\n");
|
||||
}
|
||||
}else{
|
||||
bufindex = (char *) tftp_handler->tftp_buf;
|
||||
bufindex += 3;
|
||||
printf("error opcode = %d message = %s\r\n",opcode,bufindex);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if(rcount != count){
|
||||
//printf("error:rcount = %d count = %d\r\n",rcount,count);
|
||||
len = sprintf ((char *) tftp_handler->tftp_buf, "%c%c%c%c", 0x00, 0x03, 0x00, 0x00); /* build data packet but write out the count as zero */
|
||||
//tftp_handler->send_handle(tftp_handler->tftp_buf+4,&len,count);
|
||||
tftp_handler->tftp_buf[2] = (count & 0xFF00) >> 8; //fill in the count (top number first)
|
||||
tftp_handler->tftp_buf[3] = (count & 0x00FF); //fill in the lower part of the count
|
||||
//len+=4;
|
||||
if (sendto(sock, tftp_handler->tftp_buf, len, 0, (struct sockaddr *) &server,sizeof (server)) != len){
|
||||
printf ("Mismatch in number of sent bytes\n");
|
||||
goto exit;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//send file to tftp server
|
||||
//printf("ok:rcount = %d count = %d\r\n",rcount,count);
|
||||
count++;
|
||||
|
||||
sprintf ((char *) tftp_handler->tftp_buf, "%c%c%c%c", 0x00, 0x03, 0x00, 0x00); /* build data packet but write out the count as zero */
|
||||
tftp_handler->send_handle(tftp_handler->tftp_buf+4,&len,count);
|
||||
tftp_handler->tftp_buf[2] = (count & 0xFF00) >> 8; //fill in the count (top number first)
|
||||
tftp_handler->tftp_buf[3] = (count & 0x00FF); //fill in the lower part of the count
|
||||
len+=4;
|
||||
//printf("len = %d\r\n",len);
|
||||
if (sendto(sock, tftp_handler->tftp_buf, len, 0, (struct sockaddr *) &server,sizeof (server)) != len){
|
||||
printf ("Mismatch in number of sent bytes\n");
|
||||
goto exit;
|
||||
}else if(len != BLOCK_SIZE){
|
||||
printf("Send file finish last chunk = %d\r\n",len-4);
|
||||
goto done;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == tftp_handler->tftp_retry_num){
|
||||
printf ("Data recieve Timeout. Aborting transfer\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
exit:
|
||||
return -1;
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tftp_client_get (const char *pFilename, struct sockaddr_in server,const char *pMode, int sock,tftp *tftp_handler)
|
||||
{
|
||||
/* local variables */
|
||||
int len, server_len, opcode, j, n, tid = 0;
|
||||
unsigned short int count = 0, rcount = 0;
|
||||
unsigned char packetbuf[64];
|
||||
//int errno;
|
||||
char *bufindex, ackbuf[12];
|
||||
struct sockaddr_in data;
|
||||
|
||||
n = BLOCK_SIZE;
|
||||
|
||||
fd_set read_fds;
|
||||
struct timeval time_out;
|
||||
|
||||
printf("tftp_client_get\r\n");
|
||||
|
||||
while(1){
|
||||
|
||||
if (n != BLOCK_SIZE){ /* remember if our datasize is less than a full packet this was the last packet to be received */
|
||||
|
||||
printf("Last chunk detected (file chunk size: %d). exiting while loop\n",n - 4);
|
||||
len = sprintf (ackbuf, "%c%c%c%c", 0x00, 0x04, 0x00, 0x00);
|
||||
ackbuf[2] = (count & 0xFF00) >> 8; //fill in the count (top number first)
|
||||
ackbuf[3] = (count & 0x00FF); //fill in the lower part of the count
|
||||
printf ("Sending ack # %04d (length: %d)\n", count, len);
|
||||
if (sendto(sock, ackbuf, len, 0, (struct sockaddr *) &server,sizeof (server)) != len){
|
||||
printf ("Mismatch in number of sent bytes\n");
|
||||
goto exit;
|
||||
}
|
||||
printf ("The Client has sent an ACK for packet\n");
|
||||
goto done; /* gotos are not optimal, but a good solution when exiting a multi-layer loop */
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
for (j = 0; j < tftp_handler->tftp_retry_num; j++){ /* this allows us to loop until we either break out by getting the correct ack OR time out because we've looped more than RETRIES times */
|
||||
server_len = sizeof (data);
|
||||
time_out.tv_sec = tftp_handler->tftp_timeout; // Set select timeout of 3 seconds
|
||||
time_out.tv_usec = 0;
|
||||
FD_ZERO(&read_fds) ;
|
||||
FD_SET(sock, &read_fds); // Only set server fd
|
||||
if(select(sock + 1, &read_fds, NULL, NULL, &time_out) == 1){
|
||||
n = recvfrom (sock, tftp_handler->tftp_buf, BLOCK_SIZE, 0,(struct sockaddr *) &data,(socklen_t *) & server_len);
|
||||
if(n < 0){
|
||||
printf("could not read datagram\r\n");
|
||||
goto exit;
|
||||
}
|
||||
}else{
|
||||
printf("timeout...%d\r\n",j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tid){
|
||||
tid = ntohs (data.sin_port); //get the tid of the server.
|
||||
server.sin_port = htons (tid); //set the tid for rest of the transfer
|
||||
}
|
||||
|
||||
if (server.sin_addr.s_addr != data.sin_addr.s_addr){ /* checks to ensure get from ip is same from ACK IP */
|
||||
printf("Error recieving file (data from invalid address)\n");
|
||||
j--;
|
||||
continue; /* we aren't going to let another connection spoil our first connection */
|
||||
}
|
||||
|
||||
if (tid != ntohs (server.sin_port)){ /* checks to ensure get from the correct TID */
|
||||
printf ("Error recieving file (data from invalid tid)\n");
|
||||
len = sprintf ((char *) packetbuf,"%c%c%c%cBad/Unknown TID%c",0x00, 0x05, 0x00, 0x05, 0x00);
|
||||
if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &server, sizeof (server)) != len){ /* send the data packet */
|
||||
printf("Mismatch in number of sent bytes while trying to send mode error packet\n");
|
||||
}
|
||||
j--;
|
||||
continue; /* we aren't going to let another connection spoil our first connection */
|
||||
}
|
||||
|
||||
/* this formatting code is just like the code in the main function */
|
||||
bufindex = (char *) tftp_handler->tftp_buf; //start our pointer going
|
||||
if (bufindex++[0] != 0x00)
|
||||
printf ("bad first nullbyte!\n");
|
||||
opcode = *bufindex++;
|
||||
rcount = *bufindex++ << 8;
|
||||
rcount &= 0xff00;
|
||||
rcount += (*bufindex++ & 0x00ff);
|
||||
|
||||
if (opcode != 3){ /* ack packet should have code 3 (data) and should be ack+1 the packet we just sent */
|
||||
|
||||
//printf("Badly ordered/invalid data packet (Got OP: %d Block: %d) (Wanted Op: 3 Block: %d)\n",opcode, rcount, count);
|
||||
/* sending error message */
|
||||
if (opcode > 5)
|
||||
{
|
||||
len = sprintf ((char *) packetbuf,"%c%c%c%cIllegal operation%c",0x00, 0x05, 0x00, 0x04, 0x00);
|
||||
if (sendto (sock, packetbuf, len, 0, (struct sockaddr *) &server, sizeof (server)) != len){ /* send the data packet */
|
||||
printf("Mismatch in number of sent bytes while trying to send mode error packet\n");
|
||||
}
|
||||
}else{
|
||||
bufindex = (char *) tftp_handler->tftp_buf;
|
||||
bufindex += 3;
|
||||
printf("error opcode = %d message = %s\r\n",opcode,bufindex);
|
||||
goto exit;
|
||||
}
|
||||
}else{
|
||||
len = sprintf (ackbuf, "%c%c%c%c", 0x00, 0x04, 0x00, 0x00);
|
||||
ackbuf[2] = (count & 0xFF00) >> 8; //fill in the count (top number first)
|
||||
ackbuf[3] = (count & 0x00FF); //fill in the lower part of the count
|
||||
}
|
||||
|
||||
if(rcount != count){
|
||||
//printf("rcount %d %d\r\n",rcount,count);
|
||||
len = sprintf (ackbuf, "%c%c%c%c", 0x00, 0x04, 0x00, 0x00);
|
||||
ackbuf[2] = ((count-1) & 0xFF00) >> 8; //fill in the count (top number first)
|
||||
ackbuf[3] = ((count-1) & 0x00FF); //fill in the lower part of the count
|
||||
if (sendto(sock, ackbuf, len, 0, (struct sockaddr *) &server,sizeof (server)) != len){
|
||||
printf ("Mismatch in number of sent bytes\n");
|
||||
goto exit;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sendto(sock, ackbuf, len, 0, (struct sockaddr *) &server,sizeof (server)) != len){
|
||||
printf ("Mismatch in number of sent bytes\n");
|
||||
goto exit;
|
||||
}else{
|
||||
tftp_handler->recv_handle( tftp_handler->tftp_buf+4,n-4,count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == tftp_handler->tftp_retry_num){
|
||||
printf ("Data recieve Timeout. Aborting transfer\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
exit:
|
||||
return -1;
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tftp_client_start(tftp *tftp_handler)
|
||||
{
|
||||
int sock, server_len, len; //,n;
|
||||
struct hostent *host; /*for host information */
|
||||
struct sockaddr_in server; //, client; /*the address structure for both the server and client */
|
||||
char request_buf[64]={0};
|
||||
|
||||
int retry_count = 0;
|
||||
|
||||
vTaskDelay(5000);
|
||||
|
||||
printf("start to tftp client\r\n");
|
||||
|
||||
if (!(host = gethostbyname (tftp_handler->tftp_host))){
|
||||
printf ("Client could not get host address information\r\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
/*Create the socket, a -1 will show us an error */
|
||||
if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
|
||||
printf ("Client: Socket could not be created");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
|
||||
/*set the address values for the server */
|
||||
memset (&server, 0, sizeof (server)); /*Clear the structure */
|
||||
server.sin_family = AF_INET; /*address family for TCP and UDP */
|
||||
memcpy (&server.sin_addr, host->h_addr, host->h_length); /*set address of server taken from gethostbyname function */
|
||||
//server.sin_addr.s_addr = htonl (INADDR_ANY); /*use any address */
|
||||
server.sin_port = htons (tftp_handler->tftp_port); /*pick a free port */
|
||||
|
||||
server_len = sizeof (server); /*get the length of the server address */
|
||||
ip_port(server);
|
||||
|
||||
len = req_packet(tftp_handler->tftp_op,tftp_handler->tftp_file_name,tftp_handler->tftp_mode,request_buf,0);
|
||||
|
||||
RETRY:
|
||||
if(retry_count == tftp_handler->tftp_retry_num){
|
||||
printf("Try the maxium %d times \r\n",tftp_handler->tftp_retry_num);
|
||||
goto EXIT;
|
||||
}
|
||||
if (sendto (sock, request_buf, len, 0, (struct sockaddr *) &server, server_len) !=len){
|
||||
printf("Client: sendto has returend an error %d\r\n",len);
|
||||
goto EXIT;
|
||||
}
|
||||
if(tftp_handler->tftp_op == RRQ){
|
||||
printf("recv file\r\n");
|
||||
if(tftp_client_get (tftp_handler->tftp_file_name, server, tftp_handler->tftp_mode, sock,tftp_handler) == 0){
|
||||
printf("tget finish\r\n");
|
||||
close(sock);
|
||||
}else{
|
||||
printf("tget error\r\n");
|
||||
retry_count++;
|
||||
goto RETRY;
|
||||
}
|
||||
}else if(tftp_handler->tftp_op == WRQ){
|
||||
printf("send file\r\n");
|
||||
if(tftp_client_send (tftp_handler->tftp_file_name, server, tftp_handler->tftp_mode, sock,tftp_handler) == 0){
|
||||
printf("tput finish\r\n");
|
||||
close(sock);
|
||||
goto DONE;
|
||||
}else{
|
||||
printf("tput error\r\n");
|
||||
retry_count++;
|
||||
goto RETRY;
|
||||
}
|
||||
}
|
||||
DONE:
|
||||
return 0;
|
||||
EXIT:
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user