Hardwired TCP/IP Chapter 18: W55MH32 FTP Server Example
Hardwired TCP/IP Chapter 18: W55MH32 FTP Server Example

Hardwired TCP/IP Chapter 18: W55MH32 FTP_Server Example
In this article, we will provide a detailed explanation on how to implement the FTP protocol on the W55MH32 chip. Through practical examples, we will also explain various functions such as using the W55MH32 as an FTP server, the PC as an FTP client for file transfer, directory operations, etc.
Other network protocols used in this example, such as DHCP, please refer to the relevant sections. Regarding the initialization process of the W55MH32, please refer to the "Network Installation" chapter. We will not elaborate on this here.
1 Introduction to the FTP Protocol
FTP (File Transfer Protocol) is a standard network protocol used for transferring files between clients and servers. The FTP client protocol is implemented based on the FTP protocol and is used to guide the client on how to communicate with the FTP server, enabling functions such as file upload, download, and directory operations. Since FTP was originally designed for plaintext transmission and is not secure enough, adding an SSL/TLS encryption layer to FTP can provide encrypted control connections and data connections. The following is an introduction to the main content and working mechanism of the FTP client protocol.
2 Characteristics of the FTP Protocol
- Based on TCP transmission: FTP uses two TCP connections: the control connection (port 21) and the data connection (port 20 or the dynamically assigned port in PASV mode), ensuring reliable data transmission.
- Separate control from data:
- The control connection is used for sending commands and receiving responses.
- The data connection is used for transmitting file contents or directory information.
3 Support multiple transmission modes:
- Active Mode: The server initiatively connects to the data port of the client.
- Passive Mode: The client initiatively connects to the data port provided by the server, addressing the limitations imposed by NAT firewalls.
4 Support multiple file operations:
- File upload (STOR), download (RETR), deletion (DELE).
- Directory operations (MKD, RMD, CWD, PWD).
- Obtaining file list (LIST, NLST).
5 Clear-text transmission (traditional FTP): Usernames, passwords and data are transmitted in plain text, which is insecure. Security improvements: FTPS (FTP Secure, based on SSL/TLS) and SFTP (Secure File Transfer Protocol, based on SSH).
6 Flexible user authentication mechanism:
- Support anonymous login (anonymous users can use email as the password).
- Support authentication of username and password.
3 Application scenarios of the FTP protocol
Next, let's take a look at what operations and applications can be accomplished using the FTP protocol on the W55MH32?
Firmware upgrade: Embedded devices can upgrade their systems by downloading new firmware or software update packages via FTP. This is suitable for devices that require regular updates, such as routers and industrial control equipment.
Data collection and transmission: Embedded devices (such as sensor nodes or data recorders) upload the collected data to remote servers for storage and analysis. For example, environmental monitoring equipment uploads temperature and humidity data to the server.
Remote configuration and log management: Devices can download configuration files or upload log information for administrators to analyze and troubleshoot. This is suitable for industrial automation equipment and embedded monitoring systems.
Embedded Web server file management: Many embedded devices have a simple Web server built-in for file storage or content distribution. These files can be managed through FTP.
4 The basic workflow of the FTP protocol
1. Establish a control connection
- Client initialization: The client starts the FTP client program and specifies the address and port number (port number is 21) of the FTP server to connect to.
- TCP connection establishment: The client initiates a connection request to the 21 port of the server via the TCP protocol. The server listens to this port, receives the request, and establishes a TCP connection with the client. This connection is called the control connection and is mainly used for transmitting FTP commands and server response information.
- Authentication: After the connection is established, the server prompts the client to enter the username and password for authentication. The client sends the corresponding username and password information to the server. After the server verifies the information, it allows the client to proceed with subsequent operations. There are also anonymous FTP servers that allow users to use "anonymous" as the username and an email address as the password for login, providing public file access services.
2. Selection of Transmission Mode
The client and the server negotiate the data transmission mode during the control connection. There are mainly two modes:
- Active mode (PORT mode): The client informs the server through the control connection of its own data port (a randomly opened port by the client), and the server initiatively connects to the client's data port using port 20 to transmit data.
- Passive mode (PASV mode): The client sends the PASV command to the server, and the server informs the client of a temporary data port it has opened (usually a port above 1024), then the client uses a random port of its own to connect to the server's this temporary data port to transmit data.
3. Data transmission
According to the user's operational requirements, perform file or directory-related operations through data connection:
- Upload file: The client sends the STOR (storage) command to the server, and then transmits the local file data through the data connection to the server. After receiving the data, the server stores it in the specified directory.
- Download file: The client sends the RETR (retrieve) command to the server, requesting to download the file on the server. The server sends the file data through the data connection to the client, and the client receives the data and saves it to the local designated location.
- Directory operations: The client can also send commands such as LIST (list directory contents), CWD (change working directory), MKD (create directory), RMD (delete directory), etc. The server executes the corresponding operations and returns the operation results through the control connection. When executing these commands, if it is necessary to transfer directory lists and other data, it will also be transmitted through the data connection.
4. Close the connection
- Data connection closed: After completing file transfer or other operations, the data connection will be closed. If there are other operations that need to be performed, the client and the server can re-establish the data connection as needed.
- Control connection closed: When the client completes all operations, it will send the QUIT command to the server. After receiving the command, the server will close the control connection. At this point, the FTP session between the client and the server ends.
5 Explanation of Active Mode and Passive Mode
Active Mode:
- The client opens a port and starts listening.
- The client informs the server of its own IP and port through the control connection.
- The server actively connects to the port specified by the client and transmits data.
Passive Mode:
- The client initiates the connection request in a passive mode.
- The server opens a random port and informs the client through the control connection.
- The client then initiatively connects to the port specified by the server and transmits data.
Comparison of advantages and disadvantages:
- The active mode is more suitable for environments where there are no firewall restrictions on the server-side network.
- The passive mode is more appropriate for situations where the client is behind a NAT or firewall.
6 FTP Message Analysis
FTP messages are divided into command and response messages. Command messages are used to send operation requests, while response messages are used to return results.
The format of command messages is "<command> <parameters>\r\n", and the field explanations are as follows:
<Command>: FTP commands (such as USER, PASS).
<Parameter>: Additional information for the command (such as username, file name).
For example, "USER username\r\n". Common commands include login (USER, PASS), file operations (RETR, STOR), directory operations (LIST, CWD), etc. Each FTP message consists of the command or response code, status code, and additional data. The status code is used to indicate the operation result.
Here are the common FTP commands:
- USER: Provide the username for identity verification.
- PASS: Provide the password for identity verification.
- CWD: Change the current working directory.
- PWD: Display the current working directory.
- LIST: List the files and subdirectories in the directory.
- RETR: Download files from the server.
- STOR: Upload files to the server.
- DELE: Delete the specified file.
- MKD: Create a new directory.
- RMD: Delete the directory.
- QUIT: Terminate the session and exit.
- TYPE: Set the file transfer type (ASCII or Binary).
- PORT: Specify the port for the data connection.
- PASV: Enable passive mode, where the server specifies the port for the client to connect to.
The response message format is "<status code> <description>\r\n", and the field explanations are as follows:
- <Status Code>: The three-digit number represents the status.
- <Description Text>: The textual description of the status.
For example, "230 User logged in, proceed.\r\n". Here are some common response codes for FTP:
- 1xx (Informative Response): This mainly provides some initial information and usually indicates that the server is processing the request but has not completed the operation yet.
- 2xx (Successful Response): This indicates that the command has been successfully executed. This is one of the response types that clients most desire, as it means that the operation of the request (such as login, file transfer, etc.) has been completed successfully.
- 3xx (Informational Response): This indicates that the server requires some additional information to complete the operation. This usually occurs during processes such as authentication or file location.
- 4xx (Temporary Error Response): This indicates that there is a problem with the client's request, but the error is temporary and can be resolved by some adjustments (such as re-sending the request, etc.).
- 5xx (Permanent Error Response): This indicates that there is an error with the client's request, and this error is relatively serious and difficult to correct through simple adjustments.
Next, let's take a look at an example of the FTP message for obtaining a directory:
- The client establishes a TCP connection to the server's port 21.
- The server responds: 220 Welcome to FTP Server\r\n
- The client sends: USER wiznet\r\n
- The server responds: 331 User wiznet OK. Password required\r\n
- The client sends: PASS wiznet\r\n
- The server responds: 230 User logged in\r\n
- The client sends: PORT 192,168,1,5,20,100\r\n (Active mode. 192,168,1,5 is the client's address, 20,100 is the client's expected port number, 20*256+100 = 5260)
- The server responds: 200 PORT command successful\r\n
- The client sends: LIST\r\n (DIR command, to obtain the file information of the current directory)
- The server replies: 150 Opening ASCII mode data connection for file list\r\n
- The server initiates a TCP connection to the client's expected port number and transmits the directory information. After the transmission is completed, it closes the TCP connection.
- The client sends: QUIT\r\n (To exit the FTP session)
- The server responds: 221 Goodbye\r\n
7 The implementation process
Next, let's take a look at how to implement the Server mode of the FTP protocol on the W55MH32. Note: The test instances require that the PC and W55MH32 be on the same network segment.
Step 1: Obtain network configuration information and initiate FTP.
1. wizchip_getnetinfo(&net_info);
2. ftpd_init(net_info.ip);
The content of the ftpd_init() function is as follows:
1. void ftpd_init(uint8_t *src_ip)
2. {
3. ftp.state = FTPS_NOT_LOGIN;
4. ftp.current_cmd = NO_CMD;
5. ftp.dsock_mode = ACTIVE_MODE;
6.
7. ftp.ID_Enable = STATUS_USED;
8. ftp.PW_Enable = STATUS_USED;
9.
10. if (ftp.ID_Enable == STATUS_USED)
11. {
12. strcpy(ftp.username, ftp_ID);
13. printf(" FTP ID[%d]:%s \r\n", strlen(ftp.username), ftp.username);
14. }
15. if (ftp.PW_Enable == STATUS_USED)
16. {
17. strcpy(ftp.userpassword, ftp_PW);
18. printf(" FTP PW[%d]:%s \r\n", strlen(ftp.userpassword), ftp.userpassword);
19. }
20.
21. local_ip.cVal[0] = src_ip[0];
22. local_ip.cVal[1] = src_ip[1];
23. local_ip.cVal[2] = src_ip[2];
24. local_ip.cVal[3] = src_ip[3];
25. local_port = 35000;
26.
27. strcpy(ftp.workingdir, "/");
28.
29. socket(CTRL_SOCK, Sn_MR_TCP, IPPORT_FTP, 0x0);
30. socket(CTRL_SOCK1, Sn_MR_TCP, IPPORT_FTP, 0x0);
31. }
The main function of the ftpd_init() function is to initialize various parameters of the FTP server, including server status, user authentication information, network address and port, as well as creating a TCP socket to prepare for the subsequent operation of the FTP service.
Step 2: Achieve continuous interaction between the server and the client
The ftpd_run() function is continuously called in the main loop, and its function is to make the FTP server run continuously, constantly processing various requests from the client, achieving continuous interaction between the server and the client, and providing stable FTP services.
1. while (1)
2. {
3. ftpd_run(ethernet_buf);
4. }
The content of the ftpd_run() function is as follows:
1. uint8_t ftpd_run(uint8_t *dbuf)
2. {
3. uint16_t size = 0;
4. long ret = 0;
5. uint32_t blocklen, recv_byte;
6. uint32_t remain_filesize;
7. int32_t remain_datasize;
8. #if defined(F_FILESYSTEM)
9. FILINFO fno;
10. #endif
11.
12. // FTP Control 1
13. #if 1
14. switch (getSn_SR(CTRL_SOCK))
15. {
16. case SOCK_ESTABLISHED:
17. if (!connect_state_control)
18. {
19. #if defined(_FTP_DEBUG_)
20. printf("%d:FTP Connected\r\n", CTRL_SOCK);
21. #endif
22. // fsprintf(CTRL_SOCK, banner, HOSTNAME, VERSION);
23. strcpy(ftp.workingdir, "/");
24. sprintf((char *)dbuf, "220 %s FTP version %s ready.\r\n", HOSTNAME, VERSION);
25. ret = send(CTRL_SOCK, (uint8_t *)dbuf, strlen((const char *)dbuf));
26.
27. #if defined(_FTP_DEBUG_)
28. printf("%d:send() [%s]\r\n", CTRL_SOCK, dbuf);
29. #endif
30. if (ret < 0)
31. {
32. #if defined(_FTP_DEBUG_)
33. printf("%d:send() error:%ld\r\n", CTRL_SOCK, ret);
34. #endif
35. close(CTRL_SOCK);
36. return ret;
37. }
38. connect_state_control = 1;
39. }
40. #if connect_timeout_en
41. else
42. {
43. if (con_remain_cnt1 > remain_time)
44. {
45. if ((ret = disconnect(CTRL_SOCK)) != SOCK_OK)
46. return ret;
47. #if defined(_FTP_DEBUG_)
48. printf("%d:Timeout Closed\r\n", CTRL_SOCK);
49. #endif
50. }
51. #if defined(_FTP_DEBUG_)
52. else if (((con_remain_cnt1 % 10000) == 0) && (con_remain_cnt1 != 0))
53. {
54. // printf("%d:Timeout Count:%ld\r\n", CTRL_SOCK, con_remain_cnt1);
55. }
56. #endif
57. con_remain_cnt1++;
58. }
59. #endif
60.
61. #if defined(_FTP_DEBUG_)
62. // printf("ftp socket %d\r\n", CTRL_SOCK);
63. #endif
64.
65. if ((size = getSn_RX_RSR(CTRL_SOCK)) > 0) // Don't need to check SOCKERR_BUSY because it doesn't not occur.
66. {
67. #if defined(_FTP_DEBUG_)
68. printf("%d:size: %d\r\n", CTRL_SOCK, size);
69. #endif
70.
71. memset(dbuf, 0, _MAX_SS);
72.
73. if (size > _MAX_SS)
74. size = _MAX_SS - 1;
75.
76. ret = recv(CTRL_SOCK, dbuf, size);
77. dbuf[ret] = '\0';
78. if (ret != size)
79. {
80. if (ret == SOCK_BUSY)
81. return 0;
82. if (ret < 0)
83. {
84. #if defined(_FTP_DEBUG_)
85. printf("%d:recv() error:%ld\r\n", CTRL_SOCK, ret);
86. #endif
87. close(CTRL_SOCK);
88. return ret;
89. }
90. }
91. #if defined(_FTP_DEBUG_)
92. printf("%d:Rcvd Command: %s", CTRL_SOCK, dbuf);
93. #endif
94. proc_ftpd(CTRL_SOCK, (char *)dbuf);
95. con_remain_cnt1 = 0;
96. }
97. break;
98.
99. case SOCK_CLOSE_WAIT:
100. #if defined(_FTP_DEBUG_)
101. printf("%d:CloseWait\r\n", CTRL_SOCK);
102. #endif
103. if ((ret = disconnect(CTRL_SOCK)) != SOCK_OK)
104. return ret;
105. #if defined(_FTP_DEBUG_)
106. printf("%d:Closed\r\n", CTRL_SOCK);
107. #endif
108. break;
109.
110. case SOCK_CLOSED:
111. #if defined(_FTP_DEBUG_)
112. printf("%d:FTPStart\r\n", CTRL_SOCK);
113. #endif
114. if ((ret = socket(CTRL_SOCK, Sn_MR_TCP, IPPORT_FTP, 0x0)) != CTRL_SOCK)
115. {
116. #if defined(_FTP_DEBUG_)
117. printf("%d:socket() error:%ld\r\n", CTRL_SOCK, ret);
118. #endif
119. close(CTRL_SOCK);
120. return ret;
121. }
122. break;
123.
124. case SOCK_INIT:
125. #if defined(_FTP_DEBUG_)
126. printf("%d:Opened\r\n", CTRL_SOCK);
127. #endif
128. strcpy(ftp.workingdir, "/");
129. if ((ret = listen(CTRL_SOCK)) != SOCK_OK)
130. {
131. #if defined(_FTP_DEBUG_)
132. printf("%d:Listen error\r\n", CTRL_SOCK);
133. #endif
134. return ret;
135. }
136. connect_state_control = 0;
137. con_remain_cnt1 = 0;
138.
139. #if defined(_FTP_DEBUG_)
140. printf("%d:Listen ok\r\n", CTRL_SOCK);
141. #endif
142. break;
143.
144. default:
145. break;
146. }
After entering the ftpd_run() function, the program will execute a state machine in TCP Server mode (refer to the TCP Server section for details). When the socket is in the SOCK_ESTABLISHED state, if it is the first time entering this state, a welcome message will be sent to the client. Subsequently, it will listen for client instructions. When a client instruction is received, it will enter the proc_ftpd() function for processing.
The proc_ftpd() function handles FTP service commands and performs corresponding operations based on different commands and parameters, including user authentication, file operations, data transmission, status handling, and error responses.
Note: When the value of the macro definition connect_timeout_en is set to 1, the connection timeout function will be enabled. If no operation is performed after the duration defined by the macro definition remain_time has elapsed, the system will automatically disconnect the connection. Here, connect_timeout_en is a macro that controls the enabling or disabling of the connection timeout function, with a value of 1 indicating that the function is enabled and 0 indicating that it is disabled; while remain_time is a macro that defines the maximum allowable period of no operation before triggering the automatic disconnection operation.
The proc_ftpd() function is as follows:
1. char proc_ftpd(uint8_t sn, char *buf)
2. {
3. char **cmdp, *cp, *arg, *tmpstr;
4. char sendbuf[200];
5. int slen;
6. long ret;
7.
8. // Translate first word to lower case
9. for (cp = buf; *cp != ' ' && *cp != '\0'; cp++)
10. *cp = tolower(*cp);
11.
12. // Find command in table; if not present, return syntax error
13. for (cmdp = commands; *cmdp != NULL; cmdp++)
14. if (strncmp(*cmdp, buf, strlen(*cmdp)) == 0)
15. break;
16.
17. if (*cmdp == NULL)
18. {
19. // fsprintf(CTRL_SOCK, badcmd, buf);
20. slen = sprintf(sendbuf, "500 Unknown command '%s'\r\n", buf);
21. send(sn, (uint8_t *)sendbuf, slen);
22. return 0;
23. }
24. // Allow only USER, PASS and QUIT before logging in
25. if (ftp.state == FTPS_NOT_LOGIN)
26. {
27. switch (cmdp - commands)
28. {
29. case USER_CMD:
30. case PASS_CMD:
31. case QUIT_CMD:
32. break;
33. default:
34. // fsprintf(CTRL_SOCK, notlog);
35. slen = sprintf(sendbuf, "530 Please log in with USER and PASS\r\n");
36. send(sn, (uint8_t *)sendbuf, slen);
37. return 0;
38. }
39. }
40.
41. arg = &buf[strlen(*cmdp)];
42. while (*arg == ' ')
43. arg++;
44.
45. /* Execute specific command */
46. switch (cmdp - commands)
47. {
48. case USER_CMD:
49. #if defined(_FTP_DEBUG_)
50. printf("USER_CMD : %s", arg);
51. #endif
52. slen = strlen(arg);
53. arg[slen - 1] = 0x00;
54. arg[slen - 2] = 0x00;
55. if (ftp.ID_Enable == STATUS_USED)
56. {
57. if (strcmp(ftp.username, arg) != 0)
58. {
59. slen = sprintf(sendbuf, "430 Invalid username\r\n");
60. ret = send(sn, (uint8_t *)sendbuf, slen);
61. if (ret < 0)
62. {
63. #if defined(_FTP_DEBUG_)
64. printf("%d:send() error:%ld\r\n", sn, ret);
65. #endif
66. close(sn);
67. return ret;
68. }
69. break;
70. }
71. }
72. else
73. {
74. strcpy(ftp.username, arg);
75. }
76. // fsprintf(CTRL_SOCK, givepass);
77. slen = sprintf(sendbuf, "331 Enter PASS command\r\n");
78. ret = send(sn, (uint8_t *)sendbuf, slen);
79. if (ret < 0)
80. {
81. #if defined(_FTP_DEBUG_)
82. printf("%d:send() error:%ld\r\n", sn, ret);
83. #endif
84. close(sn);
85. return ret;
86. }
87. break;
88.
89. case PASS_CMD:
90. #if defined(_FTP_DEBUG_)
91. printf("PASS_CMD : %s", arg);
92. #endif
93. slen = strlen(arg);
94. arg[slen - 1] = 0x00;
95. arg[slen - 2] = 0x00;
96. if (ftp.PW_Enable == STATUS_USED)
97. {
98. if (strcmp(ftp.userpassword, arg) != 0)
99. {
100. slen = sprintf(sendbuf, "430 Invalid password\r\n");
101. ret = send(sn, (uint8_t *)sendbuf, slen);
102. if (ret < 0)
103. {
104. #if defined(_FTP_DEBUG_)
105. printf("%d:send() error:%ld\r\n", sn, ret);
106. #endif
107. close(sn);
108. return ret;
109. }
110. break;
111. }
112. }
113. ftplogin(sn, arg);
114. break;
115.
116. case TYPE_CMD:
117. slen = strlen(arg);
118. arg[slen - 1] = 0x00;
119. arg[slen - 2] = 0x00;
120. switch (arg[0])
121. {
122. case 'A':
123. case 'a': // Ascii
124. ftp.type = ASCII_TYPE;
125. // fsprintf(CTRL_SOCK, typeok, arg);
126. slen = sprintf(sendbuf, "200 Type set to %s\r\n", arg);
127. send(sn, (uint8_t *)sendbuf, slen);
128. break;
129.
130. case 'B':
131. case 'b': // Binary
132. case 'I':
133. case 'i': // Image
134. ftp.type = IMAGE_TYPE;
135. // fsprintf(CTRL_SOCK, typeok, arg);
136. slen = sprintf(sendbuf, "200 Type set to %s\r\n", arg);
137. send(sn, (uint8_t *)sendbuf, slen);
138. break;
140. default: /* Invalid */
141. // fsprintf(CTRL_SOCK, badtype, arg);
142. slen = sprintf(sendbuf, "501 Unknown type \"%s\"\r\n", arg);
143. send(sn, (uint8_t *)sendbuf, slen);
144. break;
145. }
146. break;
147.
148. case FEAT_CMD:
149. slen = sprintf(sendbuf, "211-Features:\r\n MDTM\r\n REST STREAM\r\n SIZE\r\n MLST size*;type*;create*;modify*;\r\n MLSD\r\n UTF8\r\n CLNT\r\n MFMT\r\n211 END\r\n");
150. send(sn, (uint8_t *)sendbuf, slen);
151. break;
152.
153. case QUIT_CMD:
154. #if defined(_FTP_DEBUG_)
155. printf("QUIT_CMD\r\n");
156. #endif
157. // fsprintf(CTRL_SOCK, bye);
158. slen = sprintf(sendbuf, "221 Goodbye!\r\n");
159. send(sn, (uint8_t *)sendbuf, slen);
160. disconnect(sn);
161. break;
162.
163. case RETR_CMD:
164. slen = strlen(arg);
165. arg[slen - 1] = 0x00;
166. arg[slen - 2] = 0x00;
167. #if defined(_FTP_DEBUG_)
168. printf("RETR_CMD\r\n");
169. #endif
170. if (strlen(ftp.workingdir) == 1)
171. sprintf(ftp.filename, "/%s", arg);
172. else
173. sprintf(ftp.filename, "%s/%s", ftp.workingdir, arg);
174. slen = sprintf(sendbuf, "150 Opening data channel for file downloand from server of \"%s\"\r\n", ftp.filename);
175. send(sn, (uint8_t *)sendbuf, slen);
176. ftp.current_cmd = RETR_CMD;
177. break;
178.
179. case APPE_CMD:
180. case STOR_CMD:
181. slen = strlen(arg);
182. arg[slen - 1] = 0x00;
183. arg[slen - 2] = 0x00;
184. #if defined(_FTP_DEBUG_)
185. printf("STOR_CMD\r\n");
186. #endif
187. if (strlen(ftp.workingdir) == 1)
188. sprintf(ftp.filename, "/%s", arg);
189. else
190. sprintf(ftp.filename, "%s/%s", ftp.workingdir, arg);
191. slen = sprintf(sendbuf, "150 Opening data channel for file upload to server of \"%s\"\r\n", ftp.filename);
192. send(sn, (uint8_t *)sendbuf, slen);
193. ftp.current_cmd = STOR_CMD;
194. if (ftp.dsock_mode == ACTIVE_MODE)
195. {
196. if ((ret = connect(DATA_SOCK, remote_ip.cVal, remote_port)) != SOCK_OK)
197. {
198. #if defined(_FTP_DEBUG_)
199. printf("%d:Connect error\r\n", DATA_SOCK);
200. #endif
201. return ret;
202. }
203. }
204. connect_state_data = 0;
205. break;
206.
207. case PORT_CMD:
208. #if defined(_FTP_DEBUG_)
209. printf("PORT_CMD\r\n");
210. #endif
211. if (pport(arg) == -1)
212. {
213. // fsprintf(CTRL_SOCK, badport);
214. slen = sprintf(sendbuf, "501 Bad port syntax\r\n");
215. send(sn, (uint8_t *)sendbuf, slen);
216. }
217. else
218. {
219. // fsprintf(CTRL_SOCK, portok);
220. ftp.dsock_mode = ACTIVE_MODE;
221. ftp.dsock_state = DATASOCK_READY;
222. slen = sprintf(sendbuf, "200 PORT command successful.\r\n");
223. send(sn, (uint8_t *)sendbuf, slen);
224. }
225. break;
226.
227. case MLSD_CMD:
228. #if defined(_FTP_DEBUG_)
229. printf("MLSD_CMD\r\n");
230. #endif
231. slen = sprintf(sendbuf, "150 Opening data channel for directory listing of \"%s\"\r\n", ftp.workingdir);
232. send(sn, (uint8_t *)sendbuf, slen);
233. ftp.current_cmd = MLSD_CMD;
234. break;
235.
236. case LIST_CMD:
237. #if defined(_FTP_DEBUG_)
238. printf("LIST_CMD\r\n");
239. #endif
240. slen = sprintf(sendbuf, "150 Opening data channel for directory listing of \"%s\"\r\n", ftp.workingdir);
241. send(sn, (uint8_t *)sendbuf, slen);
242. ftp.current_cmd = LIST_CMD;
243. break;
244.
245. case NLST_CMD:
246. #if defined(_FTP_DEBUG_)
247. printf("NLST_CMD\r\n");
248. #endif
249. break;
250.
251. case SYST_CMD:
252. slen = sprintf(sendbuf, "215 UNIX emulated by WIZnet\r\n");
253. send(sn, (uint8_t *)sendbuf, slen);
254. break;
255.
256. case PWD_CMD:
257. case XPWD_CMD:
258. slen = sprintf(sendbuf, "257 \"%s\" is current directory.\r\n", ftp.workingdir);
259. send(sn, (uint8_t *)sendbuf, slen);
260. break;
261.
262. case PASV_CMD:
263. slen = sprintf(sendbuf, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", local_ip.cVal[0], local_ip.cVal[1], local_ip.cVal[2], local_ip.cVal[3], local_port >> 8, local_port & 0x00ff);
264. send(sn, (uint8_t *)sendbuf, slen);
265.
266. if (getSn_SR(DATA_SOCK) == SOCK_ESTABLISHED)
267. {
268. #if defined(_FTP_DEBUG_)
269. printf("data disconnect: %d\r\n", DATA_SOCK);
270. #endif
271. disconnect(DATA_SOCK);
272. }
273. ftp.dsock_mode = PASSIVE_MODE;
274. ftp.dsock_state = DATASOCK_READY;
275. cur_sn = sn;
276. #if defined(_FTP_DEBUG_)
277. printf("PASV port: %d\r\n", local_port);
278. #endif
279. break;
280.
281. case SIZE_CMD:
282. slen = strlen(arg);
283. arg[slen - 1] = 0x00;
284. arg[slen - 2] = 0x00;
285. if (slen > 3)
286. {
287. tmpstr = strrchr(arg, '/');
288. *tmpstr = 0;
289. #if defined(F_FILESYSTEM)
290. slen = get_filesize(arg, tmpstr + 1);
291. #else
292. slen = _MAX_SS;
293. #endif
294. if (slen > 0)
295. slen = sprintf(sendbuf, "213 %d\r\n", slen);
296. else
297. slen = sprintf(sendbuf, "550 File not Found\r\n");
298. }
299. else
300. {
301. slen = sprintf(sendbuf, "550 File not Found\r\n");
302. }
303. send(sn, (uint8_t *)sendbuf, slen);
304. break;
305.
306. case CWD_CMD:
307. slen = strlen(arg);
308. arg[slen - 1] = 0x00;
309. arg[slen - 2] = 0x00;
310. if (slen > 3)
311. {
312. arg[slen - 3] = 0x00;
313. tmpstr = strrchr(arg, '/');
314. *tmpstr = 0;
315. #if defined(F_FILESYSTEM)
316. slen = get_filesize(arg, tmpstr + 1);
317. #else
318. slen = 0;
319. #endif
320. *tmpstr = '/';
321. if (slen == 0)
322. {
323. slen = sprintf(sendbuf, "213 %d\r\n", slen);
324. strcpy(ftp.workingdir, arg);
325. slen = sprintf(sendbuf, "250 CWD successful. \"%s\" is current directory.\r\n", ftp.workingdir);
326. }
327. else
328. {
329. slen = sprintf(sendbuf, "550 CWD failed. \"%s\"\r\n", arg);
330. }
331. }
332. else
333. {
334. strcpy(ftp.workingdir, arg);
335. slen = sprintf(sendbuf, "250 CWD successful. \"%s\" is current directory.\r\n", ftp.workingdir);
336. }
337. send(sn, (uint8_t *)sendbuf, slen);
338. break;
339.
340. case MKD_CMD:
341. case XMKD_CMD:
342. slen = strlen(arg);
343. arg[slen - 1] = 0x00;
344. arg[slen - 2] = 0x00;
345. #if defined(F_FILESYSTEM)
346. if (f_mkdir(arg) != 0)
347. {
348. slen = sprintf(sendbuf, "550 Can't create directory. \"%s\"\r\n", arg);
349. }
350. else
351. {
352. slen = sprintf(sendbuf, "257 MKD command successful. \"%s\"\r\n", arg);
353. // strcpy(ftp.workingdir, arg);
354. }
355. #else
356. slen = sprintf(sendbuf, "550 Can't create directory. Permission denied\r\n");
357. #endif
358. send(sn, (uint8_t *)sendbuf, slen);
359. break;
360.
361. case DELE_CMD:
362. slen = strlen(arg);
363. arg[slen - 1] = 0x00;
364. arg[slen - 2] = 0x00;
365. #if defined(F_FILESYSTEM)
366. if (f_unlink(arg) != 0)
367. {
368. slen = sprintf(sendbuf, "550 Could not delete. \"%s\"\r\n", arg);
369. }
370. else
371. {
372. slen = sprintf(sendbuf, "250 Deleted. \"%s\"\r\n", arg);
373. }
374. #else
375. slen = sprintf(sendbuf, "550 Could not delete. Permission denied\r\n");
376. #endif
377. send(sn, (uint8_t *)sendbuf, slen);
378. break;
379.
380. case XCWD_CMD:
381. case ACCT_CMD:
382. case XRMD_CMD:
383. case RMD_CMD:
384. case STRU_CMD:
385. case MODE_CMD:
386. case XMD5_CMD:
387. // fsprintf(CTRL_SOCK, unimp);
388. slen = sprintf(sendbuf, "502 Command does not implemented yet.\r\n");
389. send(sn, (uint8_t *)sendbuf, slen);
390. break;
391.
392. default: // Invalid
393. // fsprintf(CTRL_SOCK, badcmd, arg);
394. slen = sprintf(sendbuf, "500 Unknown command \'%s\'\r\n", arg);
395. send(sn, (uint8_t *)sendbuf, slen);
396. break;
397. }
398.
399. return 1;
400. }
After entering the proc_ftpd() function, the program will execute a state machine. Firstly, it converts the received command to lowercase and searches it in the command table. If not found, it sends an error message. Before login, only the USER, PASS, and QUIT commands are allowed, and any other commands will result in an error. For different commands, such as USER_CMD, it handles username verification and subsequent operations, PASS_CMD performs password verification and login, TYPE_CMD handles transmission type settings, FEAT_CMD sends feature information, QUIT_CMD disconnects the connection, and RETR_CMD and other file operation commands, as well as PORT_CMD and PASV_CMD, which are related to data connection modes, perform corresponding operations and error handling based on different situations, and send the corresponding status information.
8 Run results
After the burning routine is executed, the PHY link detection is first carried out, followed by the printing of the network information settings. Open the FileZilla software (download link: Client - FileZilla Chinese Website), and fill in the host ID, username, password, and port number (usually 21) on the FileZilla software to connect to the FTP server. If the connection is successful, the following interface will be displayed:
Then, drag the local site files to the remote site (server), and the files were successfully transferred to the server.
9 Summary
This article explains how to implement the FTP server mode on the W55MH32 chip. Through practical examples, it demonstrates the process of using W55MH32 as an FTP server and performing file transfer, directory operations, and other functions with the PC end. It covers key steps such as obtaining network configuration information and FTP initialization, as well as achieving continuous interaction between the server and the client. The article details the concept, characteristics, application scenarios, basic workflow, active and passive modes, and message parsing of the FTP protocol, helping readers understand its practical application value in file transfer.
The next article will focus on the FTP client mode, analyzing its core principles and applications in file transfer, and explaining how to implement the FTP client function on W55MH32. Stay tuned!
WIZnet is a non-chipfoundry semiconductor company founded in 1998. Its products include the Internet processor iMCU™, which adopts TOE (TCP/IP Offloading Engine) technology and is based on a unique patented fully hardwired TCP/IP. iMCU™ is designed for embedded Internet devices in various applications.
WIZnet has over 70 distributors worldwide, with offices in Hong Kong, South Korea, and the United States, providing technical support and product marketing.
The region managed by the Hong Kong office includes: Australia, India, Turkey, and Asia (excluding South Korea and Japan).