LwIP Application Development Notes Four: LwIP no TFTP server operating system

  We have already achieved a simple application UDP loopback client and server loop, then we achieve a simple UDP-based file transfer protocol TFTP.

1 , the TFTP protocol Introduction

  TFTP is a TCP / IP protocol suite, is used for trivial file transfer protocol between the client and server, providing uncomplicated little overhead file transfer service. Port number is 69

  TFTP is a simple file transfer protocol. The goal is to establish but only supports file upload and download transfer protocol similar to FTP on top of UDP, so it does not contain content directory operations and user permissions, and FTP protocols.

  TFTP packets first two bytes and operation code, a total of 5 opcode, as follows:

 

  Read and write requests function code data packet format is the same, so described as TFTP packets turn four forms. For a read request or a write request, the file name field described in the server's file on the client to read or write a byte 0 and ends, the mode field is a string of ASCII code, to the same end of the 0 bytes. Read request and write request packet format:

 

  Followed by the packet includes two bytes from the block number and 0-512 bytes of data. Packet relatively simple format of the packet:

 

  Also confirmed for the package. Acknowledgment packet also has a 2-byte block number. Data format:

 

  TFTP last packet is an error packet type, its operation code 5 for the case that the server can not process a read request or write request. In the process of reading and writing in the file transfer leads will transmit such packets, then stops transmission. Packet format error message:

 

   TFTP like working process stop and wait protocol, after waiting for a file block after sending a confirm each other, should confirm the specified block number recognized. After sending the data not received within a predetermined time necessary to confirm the retransmission data PDU, the PDU transmission confirmation if one party does not receive the next block of file within the specified time, confirmation also retransmit PDU. This ensures the transmission of documents will not be lost because of one datagram and failed.

2 , the TFTP protocol stack design

  Earlier we simply introduced the TFTP protocol, let's look at how to implement its program. It has five operating code, we have to do is to implement these five response opcode.

2.1 , to achieve a read request

  The so-called read request is to get the client requests a file from a server, the server needs to be done naturally in response to client requests. But we did not file, so no matter what documents it requests, we have to return it the same size and content of the test file.

. 1  / * the TFTP read request processing * / 
2  int TftpReadProcess ( struct udp_pcb * UPCB, const ip_addr_t * to, int to_port, char * FileName)
 . 3  {
 . 4    tftp_connection_args * args = NULL;
 . 5   
. 6    / * This function is in the callback function calls, so the interrupt is disabled, so we can use conventional the malloc * / 
. 7    args = mem_malloc ( the sizeof (tftp_connection_args));
 . 8   
. 9    IF (! args)
 10    {
 . 11      / * memory allocation fails * / 
12     SendTftpErrorMessage (UPCB, to, to_port, TFTP_ERR_NOTDEFINED);
 13 is   
14      CleanTftpConnection (UPCB, args);
 15   
16      return  0 ;
 . 17    }
 18 is   
. 19    / * I initiate a connection structure   * / 
20 is    args-> OP = TFTP_RRQ;
 21 is    args-> = REMOTE_PORT to_port;
 22 is    args-> block = 1 ; / * block numbers starting at 1 * / 
23 is    args-> tot_bytes = 10 * 1024 * 1024 ;
 24   
25    / * registered callback function * / 
26   udp_recv (UPCB, RrqReceiveCallback, args);
 27   
28    / * to establish the connection by transmitting a first block, subsequent blocks sent after receiving the ACK * / 
29     SendNextBlock (UPCB, args, to, to_port);
 30   
31 is    return  . 1 ;
 32 }

2.2 , write requests to achieve

  Write requests to the server that the client wants to transfer files, here we are only achieve functional TFTP server, no need to save the file to receive a real place, so just do not receive the file to be written to the memory process, simple that is to say only in memory but not written to Flash and so on.

. 1  / * the TFTP write request processing * / 
2  int TftpWriteProcess ( struct udp_pcb * UPCB, const ip_addr_t * to, int to_port, char * FileName)
 . 3  {
 . 4    tftp_connection_args * args = NULL;
 . 5   
. 6    / * This function is in the callback function calls, therefore interrupts are disabled, so we can use the regular malloc * / 
7    args = mem_malloc ( sizeof (tftp_connection_args));
 8   
9    IF (! args)
 10    {
 11      SendTftpErrorMessage (UPCB, to, to_port, TFTP_ERR_NOTDEFINED);
12 is   
13 is      CleanTftpConnection (UPCB, args);
 14   
15      return  0 ;
 16    }
 . 17   
18 is    args-> OP = TFTP_WRQ;
 . 19    args-> REMOTE_PORT = to_port;
 20 is    args-> Block = 0 ;       // block number is 0 in response WRQ 
21 is    args-> tot_bytes = 0 ;
 22 is   
23 is    / * control block registered callback function * / 
24    udp_recv (UPCB, WrqReceiveCallback, args);
 25   
26 is    / * initiates a write transaction by sending a first ACK * / 
27    SendTftpAckPacket (UPCB , to, to_port, args->block);
28  
29   return 0;
30 }

2.3 , data packet operation

  Whether it is a read request or a write request, the ultimate purpose is to transfer data packets so naturally we need to construct and transfer. Corresponding packet is an operation code, we design procedure is as follows:

1  / * configuration and transmits the data packet * / 
2  static  int SendTftpDataPacket ( struct udp_pcb UPCB *, const ip_addr_t * to, int to_port, int Block, char * buf, int buflen,)
 . 3  {
 . 4    / * The first 2 bytes set function code * / 
. 5    SetTftpOpCode (buf, TFTP_DATA);
 . 6   
. 7    / * the subsequent 2-byte block number set * / 
. 8    SetTftpBlockNumber (buf, block);
 . 9   
10    / * in a subsequent set of n bytes data * / 
. 11   
12 is    / *Transmission packet * / 
13 is    return SendTftpMessage (UPCB, to, to_port, buf, buflen, + . 4 );
 14 }

2.4 , the operation confirmation packet

  After the transmission of data packets received not received, the sender does not know how to do it? After this time the recipient received, an acknowledgment packet will be given. Corresponding operation code is confirmed, then we need to realize confirmation packet constructed and transmitted.

1  / * construct and send acknowledgment packet * / 
2  int SendTftpAckPacket ( struct udp_pcb * UPCB, const ip_addr_t * to, int to_port, int Block)
 . 3  {
 . 4    / * create a TFTP ACK packet * / 
. 5    char Packet [TFTP_ACK_PKT_LEN];
 . 6   
7    / * the starting two bytes are set to function code * / 
. 8    SetTftpOpCode (Packet, TFTP_ACK);
 . 9   
10    / * develop ACK block number * / 
. 11    SetTftpBlockNumber (Packet, block);
 12 is   
13 is    return SendTftpMessage(upcb, to, to_port, packet, TFTP_ACK_PKT_LEN);
14 }

2.5 , the operation error packets

  In the process of packet transmission, there is no possible errors it? Of course yes, which requires so-called error packet opcode. In the case where the server can not process a read request or write request. In the process of reading and writing in the file transfer leads will transmit such packets, then stops transmission. We also need to develop the construction and function of packet transmission errors.

1  / * structure to the client sends an error message * / 
2  static  int SendTftpErrorMessage ( struct udp_pcb UPCB *, const ip_addr_t * to, int to_port, tftp_errorcode ERR)
 . 3  {
 . 4    char buf [ 512 ];
 . 5    int error_len;
 . 6   
. 7    = error_len ConstructTftpErrorMessage (buf, ERR);
 . 8   
. 9    return SendTftpMessage (UPCB, to, to_port, buf, error_len);
 10 }

3 , the TFTP server implementation

  We have achieved UDP server, but also to achieve a simple TFTP protocol stack, the next task is to realize the TFTP server based on UDP. We've already mentioned, complex server application just back performance function is different, so there is no difference in the development process.

  首先我们来实现初始化部分。创建新的UDP控制块。绑定到制定的服务器端口,我们要实现TFTP服务器,而TFTP协议的端口号为69,所以我们将其绑定到该端口。最后注册TFTP服务器的回调函数。

 1 /* 初始化TFTP服务器 */
 2 void Tftp_Server_Initialization(void)
 3 {
 4   err_t err;
 5   struct udp_pcb *tftp_server_pcb = NULL;
 6  
 7   /* 生成新的 UDP PCB控制块 */
 8   tftp_server_pcb = udp_new();
 9  
10   /* 判断UDP控制块是否正确生成 */
11   if (NULL == tftp_server_pcb)
12   { 
13     return;
14   }
15  
16   /* 绑定PCB控制块到指定端口 */
17   err = udp_bind(tftp_server_pcb, IP_ADDR_ANY, UDP_TFTP_SERVER_PORT);
18  
19   if (err != ERR_OK)
20   {
21     udp_remove(tftp_server_pcb);
22     return;
23   }
24  
25   /* 注册TFTP服务器处理函数 */
26   udp_recv(tftp_server_pcb, TftpServerCallback, NULL);
27 }

  在初始化中注册了回调函数,所以我们还要实现TFTP服务器的回调函数。这部分出于结构清晰的考虑,我们分成两个函数来写。

 1 /* TFTP服务器回调函数 */
 2 static void TftpServerCallback(void *arg, struct udp_pcb *upcb, struct pbuf *p,const ip_addr_t *addr, u16_t port)
 3 {
 4   /* 处理新的连接请求 */
 5   ProcessTftpRequest(p, addr, port);
 6  
 7   pbuf_free(p);
 8 }
 9 /* 从每一个来自addr:port的新请求创建一个新的端口来服务响应,并启动响应过程 */
10 static void ProcessTftpRequest(struct pbuf *pkt_buf, const ip_addr_t *addr, u16_t port)
11 {
12   tftp_opcode op = ExtractTftpOpcode(pkt_buf->payload);
13   char FileName[50] = {0};
14   struct udp_pcb *upcb = NULL;
15   err_t err;
16  
17   /* 生成新的UDP PCB控制块 */
18   upcb = udp_new();
19   if (!upcb)
20   {
21     return;
22   }
23  
24   /* 连接 */
25   err = udp_connect(upcb, addr, port);
26   if (err != ERR_OK)
27   { 
28     return;
29   }
30  
31   ExtractTftpFilename(FileName, pkt_buf->payload);
32  
33   switch (op)
34   {
35   case TFTP_RRQ:
36     {
37  
38       TftpReadProcess(upcb, addr, port, FileName);
39       break;
40     }
41   case TFTP_WRQ:
42     {
43       /* 启动TFTP写模式 */
44       TftpWriteProcess(upcb, addr, port, FileName);
45       break;
46     }
47   default:
48     {
49       /* 异常,发送错误消息 */
50       SendTftpErrorMessage(upcb, addr, port, TFTP_ERR_ACCESS_VIOLATION);
51  
52       udp_remove(upcb);
53  
54       break;
55     }
56   }
57 }

  在回调函数中,我们实现了对TFTP读请求和写请求的响应,但这足以验证我们想要实现的TFTP服务器的功能。

4、结论

  本篇我们基于LwIP的UDP实现了一个简单的FTP服务器。这个FTP服务器只是实现FTP协议的功能,具体的应用可根据需要添加。我们使用了TFTP客户端工具对这一服务器进行了基本测试,最终结果符合我们的预期。

欢迎关注:

Guess you like

Origin www.cnblogs.com/foxclever/p/11875378.html