diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index 6b0c1ea96..7f48ccbaa 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -134,7 +134,7 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y) endif ifeq ($(CONFIG_USER_TEST_FTPCLIENT),y) - SRC_FILES += + SRC_FILES += test_ftpclient/test_ftpclient.c endif ifeq ($(CONFIG_USER_TEST_LORA_P2P),y) diff --git a/APP_Framework/Applications/app_test/test_ftpclient/01-FilesInFTPServer.png b/APP_Framework/Applications/app_test/test_ftpclient/01-FilesInFTPServer.png new file mode 100644 index 000000000..2edb6072b Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/01-FilesInFTPServer.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/02-OpenFTPServer.png b/APP_Framework/Applications/app_test/test_ftpclient/02-OpenFTPServer.png new file mode 100644 index 000000000..59e2aa6c0 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/02-OpenFTPServer.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/03-beforeDownload.png b/APP_Framework/Applications/app_test/test_ftpclient/03-beforeDownload.png new file mode 100644 index 000000000..99e65e6fe Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/03-beforeDownload.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/04-downloading1.png b/APP_Framework/Applications/app_test/test_ftpclient/04-downloading1.png new file mode 100644 index 000000000..61969ef6e Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/04-downloading1.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/05-downloading2.png b/APP_Framework/Applications/app_test/test_ftpclient/05-downloading2.png new file mode 100644 index 000000000..03b801817 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/05-downloading2.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/06-downloading3.png b/APP_Framework/Applications/app_test/test_ftpclient/06-downloading3.png new file mode 100644 index 000000000..3f30d1d91 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/06-downloading3.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/07-downloading4.png b/APP_Framework/Applications/app_test/test_ftpclient/07-downloading4.png new file mode 100644 index 000000000..d38fe47d3 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/07-downloading4.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/08-downloading5.png b/APP_Framework/Applications/app_test/test_ftpclient/08-downloading5.png new file mode 100644 index 000000000..cf32871f6 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/08-downloading5.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/09-downloading6.png b/APP_Framework/Applications/app_test/test_ftpclient/09-downloading6.png new file mode 100644 index 000000000..e56fb70a4 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/09-downloading6.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/10-downloadedFileList.png b/APP_Framework/Applications/app_test/test_ftpclient/10-downloadedFileList.png new file mode 100644 index 000000000..623331766 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/10-downloadedFileList.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/README.md b/APP_Framework/Applications/app_test/test_ftpclient/README.md new file mode 100644 index 000000000..0d6c971d9 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_ftpclient/README.md @@ -0,0 +1,70 @@ +# 基于矽璓已实现的Lwip,在ARM上实现FTP协议的Client功能并测试验证 ## + +## 1. 简介 +基于XiUOS中的Lwip协议和提供的接口,实现了FTP客户端的基本功能,包括登录(验证用户账号和密码)、文件目录显示(ls)、文件目录进入(cd)、文件下载等。 + +按照题目要求,FTP服务器端搭建在我们队员的个人电脑上,系统版本为Windows10专业版,利用Windows自带的Internet Information Services (IIS) 6.0 管理器对自定义FTP站点进行了创建及管理。 +此外,我们还借助FileZilla Server Interface在实现过程中辅助监测连接与传输情况,但最后提交代码所实现的数据上传下载实现过程不涉及FileZilla使用。 + +## 2. 函数功能设计说明 +`FillServerAddr`:Bind the server IP address
+`CreateControlConnection`:Create a control connection
+`CreateDataConnection`:Create a data connection
+`GetReplyMsg`:Get a reply message
+`SendControlCommand`:Send control command
+`LoginServer`:Logging In to the FTP Server
+`PasvInitiateFileDownload`:Before downloading the file, send the PASV command to enter passive mode, and the FTP server will open a new port for receiving the file data.
+`FileDownload`:Download the file from the server
+`ListCurrentDirectory`:Implement the ls command to display the files and directories in the current directory
+`ChangeDirectory`:Run the cd command to go to the target directory
+`Quit`:Log out of the server
+`TestFTPClient`:The function we used to test FTP client, realized .
+ + +## 3. 测试程序说明 +在ARM终端上实现了FTP Client的功能, + + +## 4. 运行结果(##需结合运行测试截图按步骤说明##) +① 编译及开启本地FTP服务器准备
+![image](pre1-EnableLwIP.JPG)
+menuconfig中使能LwIP网络协议栈 + +![image](pre2-ConfigOpen.JPG)
+打开menuconfig之后,将test ftp client开启(y),保存后退出 + +![image](pre3-CompileSuccess.JPG)
+使用 +“make BOARD=edu-arm32 distclean
+make BOARD=edu-arm32 menuconfig
+make BOARD=edu-arm32”命令,编译XiZi-edu-arm32.bin成功,编译得到的“XiZi-edu-arm32.bin”文件我们已附在文件夹中,供评委检验。
+ +![image](pre4-OpenFTPService.png)
+打开控制面板,选择“程序”,点击“启用或关闭Windows功能”。选择"Internet Information Services"下的FTP服务器中的FTP服务复选框,同时勾选web管理工具下的IIS管理控制台。
+ +![image](pre5-SetFTP1.png)
+win+R输入inetmgr打开IIS管理器,设置站点名称、IP地址、存储物理路径、SSL设置(方便起见可设置无SSL)、身份验证(设置匿名或授权访问均可,可自行生成所需SSL证书)等。 + +![image](pre6-SetFTP2.png)
+之后关闭电脑防火墙以防数据被误拦截,在身份验证时输入账号密码登录FTP服务器,通过身份验证,本地FTP服务器准备即告完成。 + +② 测试ARM终端数据下载 +![image](01-FilesInFTPServer.png)
+首先展示本地FTP服务器存放的测试文件,每个文件均为自动化脚本生成,大小为严格的4KB。
+ +![image](02-OpenFTPServer.png)
+启动本地FTP服务器,确保连接。
+ +![image](03-beforeDownload.png)
+首先通过ls命令,展示ARM终端现有的文件情况,可以看到目前仅有2个之前生成的测试用文件,我们可以将其忽略。
+ +![image](04-downloading1.png)
+![image](05-downloading2.png)
+![image](06-downloading3.png)
+![image](07-downloading4.png)
+![image](08-downloading5.png)
+![image](09-downloading6.png)
+输入执行TestFTPClient命令,ARM终端作为客户端开始访问服务器端下载指定的10个大小为4KB的.txt文件。对于每个文件的数据端口访问及接受数据、下载情况,打印出的提示信息中均有详细解释。
+ +![image](10-downloadedFileList.png)
+下载完成后,再次使用ls命令展示ARM终端作为客户端访问服务器端下载指定的10个大小为4KB的.txt文件,可以看到,相比最开始,终端上多了10个大小为4KB的文件,即一开始存放在本地服务器上的文件。
\ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_ftpclient/XiZi-edu-arm32.bin b/APP_Framework/Applications/app_test/test_ftpclient/XiZi-edu-arm32.bin new file mode 100644 index 000000000..5e0d4ab25 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/XiZi-edu-arm32.bin differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/pre1-enableLwIP.JPG b/APP_Framework/Applications/app_test/test_ftpclient/pre1-enableLwIP.JPG new file mode 100644 index 000000000..bcd163d19 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/pre1-enableLwIP.JPG differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/pre2-ConfigOpen.JPG b/APP_Framework/Applications/app_test/test_ftpclient/pre2-ConfigOpen.JPG new file mode 100644 index 000000000..8369d0b2a Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/pre2-ConfigOpen.JPG differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/pre3-CompileSuccess.JPG b/APP_Framework/Applications/app_test/test_ftpclient/pre3-CompileSuccess.JPG new file mode 100644 index 000000000..7c8f4fea3 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/pre3-CompileSuccess.JPG differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/pre4-OpenFTPService.png b/APP_Framework/Applications/app_test/test_ftpclient/pre4-OpenFTPService.png new file mode 100644 index 000000000..03a6645aa Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/pre4-OpenFTPService.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/pre5-SetFTP1.png b/APP_Framework/Applications/app_test/test_ftpclient/pre5-SetFTP1.png new file mode 100644 index 000000000..c231670d5 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/pre5-SetFTP1.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/pre6-SetFTP2.png b/APP_Framework/Applications/app_test/test_ftpclient/pre6-SetFTP2.png new file mode 100644 index 000000000..dd008821c Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/pre6-SetFTP2.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c new file mode 100644 index 000000000..078f274bd --- /dev/null +++ b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c @@ -0,0 +1,313 @@ +/* +* Copyright (c) 2023 AIIT Ubiquitous Team +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL +v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +/** + * @file: test_ftpclient.c + * @brief: Based on the protocol Lwip in XiUOS and the interface provided, this + file realized the basic functions of the FTP client, including login (verifying + user account and password), file directory display (ls), file directory entry (cd), + file download, etc. + * @version: 1.0 + * @author: Oscar + * @date: 2023/8/25 + */ + +#include +#include "test_ftpclient.h" + +struct sockaddr_in ftp_server_ctrl_addr; // Saves information about the control connection +struct sockaddr_in ftp_server_data_addr; // Saves data connection information +int sockfd_ctrl; // The socket that controls the connection +int sockfd_data; // The socket for the data connection +char server_ip_str[20]; // ip address of the FTP server +int server_port; // Port number of the FTP server +char msg_buffer[MAX_BUF_LEN]; // Message sent to the FTP server +char data_buffer[MAX_BUF_LEN]; // Send or receive data from the FTP server + +/** + * @description: Bind the server IP address + * @param ip - ip address + * @param port - server port + * @param str_server_addr - struct for save ip information + * @return void + */ +void FillServerAddr(const char* ip, unsigned short int port,struct sockaddr_in* str_server_addr) +{ + memset(str_server_addr, 0,sizeof(struct sockaddr_in)); + str_server_addr->sin_family = AF_INET; + str_server_addr->sin_port = htons(port); + str_server_addr->sin_addr.s_addr = inet_addr(ip); +} + +/** + * @description: Create a control connection + * @return 0 means success, -1 means fail + */ +int CreateControlConnection() +{ + sockfd_ctrl = socket(AF_INET, SOCK_STREAM, 0); // create socket descriptor + if(sockfd_ctrl == -1){ + printf("[Error] Create socket failed!\n"); + return -1; + } + printf("[Info] create socket success.\nbegin to connect.\n"); + + if(connect(sockfd_ctrl,(struct sockaddr *)&ftp_server_ctrl_addr,sizeof(struct sockaddr)) == 0){ // connect to the server + printf("Successfully connect to server:ip:%s,port:%d\n", + inet_ntoa(ftp_server_ctrl_addr.sin_addr) ,ntohs(ftp_server_ctrl_addr.sin_port)); + }else{ + printf("[Error] control connect failed!\n"); + return -1; + } + return 0; +} + +/** + * @description: Create a data connection + * @return 0 means success, -1 means fail + */ +int CreateDataConnection() +{ + sockfd_data = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd_data == -1){ + printf("[Error] Create socket failed!"); + return -1; + } + if (connect(sockfd_data, (struct sockaddr*)&ftp_server_data_addr, sizeof(struct sockaddr_in)) == 0){ + printf("[Info] Successfully connect to server:ip:%s,port:%d\n", inet_ntoa(ftp_server_data_addr.sin_addr), ntohs(ftp_server_data_addr.sin_port)); + }else{ + printf("[Error] data connect failed!\n"); + return -1; + } + return 0; +} + +/** + * @description: Get a reply message + * @return void + */ +int GetReplyMsg() +{ + int receive_byte_count, reply; + memset(msg_buffer, 0, MAX_BUF_LEN); + receive_byte_count = lwip_read(sockfd_ctrl, msg_buffer, MAX_BUF_LEN); + reply = atoi(msg_buffer); + printf("[Info] receive bytes: %d, Server reply: %s\n", receive_byte_count, msg_buffer); + return reply; +} + +/** + * @description: Send control command + * @param send_msg - message need send + * @return void + */ +void SendControlCommand(const char* send_msg) +{ + send(sockfd_ctrl, send_msg, strlen(send_msg), 0); + printf("[Info] Send tcp msg: %s\n", send_msg); +} + +/** + * @description: Logging In to the FTP Server + * @param username - server login username + * @param password - server login password + * @return 0 means success, -1 means fail + */ +int LoginServer(char *username, char *password) +{ + if (NULL == username || NULL == password) { + printf("[Error] username or password can not be NULL\n"); + return -1; + } + + sprintf(msg_buffer, "USER %s\r\n", username); + SendControlCommand(msg_buffer); + GetReplyMsg(); + sprintf(msg_buffer, "PASS %s\r\n", password); + SendControlCommand(msg_buffer); + if (230 == GetReplyMsg()) + return 0; + else + return -1; +} + +/** + * @description: Before downloading the file, send the PASV command to enter passive mode, and the FTP server will open a new port for receiving the file data. + * @return the new port for data connection + */ +int PasvInitiateFileDownload() +{ + int passive_port = -1; + SendControlCommand("PASV\r\n"); + GetReplyMsg(); + char *ip_and_port_str = strrchr(msg_buffer, '('); + int ip_first, ip_second, ip_third, ip_fourth, high_port, low_port; + sscanf(ip_and_port_str, "(%d,%d,%d,%d,%d,%d)", &ip_first, &ip_second, &ip_third, &ip_fourth, &high_port, &low_port); + passive_port = high_port * 256 + low_port; + return passive_port; +} + +/** + * @description: Download the file from the server + * @param filename - name of download file + * @return void + */ +void FileDownload(char *filename) +{ + if (NULL == filename) { + printf("[Error] file name can not be NULL"); + return; + } + + SendControlCommand("TYPE I\r\n"); + GetReplyMsg(); + sprintf(msg_buffer,"SIZE %s\r\n",filename); + SendControlCommand(msg_buffer); + GetReplyMsg(); + int file_size = atoi(msg_buffer + 4); + printf("[Info] %s filesize: %d\n", filename, file_size); + + // passive + int passive_port = PasvInitiateFileDownload(); + if (passive_port > 0) + FillServerAddr(server_ip_str, passive_port, &ftp_server_data_addr); + sprintf(msg_buffer,"RETR %s\r\n",filename); + SendControlCommand(msg_buffer); + if (CreateDataConnection() < 0){ + printf("[Error] unable to connect data port\n"); + return; + } + GetReplyMsg(); + + // create file and write message to file + int file_fd = PrivOpen(filename,O_RDWR | O_CREAT); + if (file_fd < 0){ + printf("[Error] error to open file!\n"); + } + printf("[Info] begin to download %s\n",filename); + int download_bytes_count = 0, current_download_bytes_count = 0; + memset(data_buffer,0,sizeof(data_buffer)); + while ((current_download_bytes_count = lwip_read(sockfd_data,data_buffer,MAX_BUF_LEN)) > 0){ + PrivWrite(file_fd,data_buffer, current_download_bytes_count); + download_bytes_count += current_download_bytes_count; + printf("== %d/%d bytes received\n", download_bytes_count, file_size); + } + printf("[Info] total %d bytes received. download %s succeed.\n", download_bytes_count, filename); + lwip_close(sockfd_data); + PrivClose(file_fd); +} + +/** + * @description: Implement the ls command to display the files and directories in the current directory + * @return void + */ +void ListCurrentDirectory() +{ + int passive_port = PasvInitiateFileDownload(); + if (passive_port > 0) + FillServerAddr(server_ip_str, passive_port, &ftp_server_data_addr); + SendControlCommand("LIST\r\n"); + if (CreateDataConnection() < 0){ + printf("[Error] unable to connect data port\n"); + return; + } + printf("[Info] Recving data! please wait....\n"); + int receive_bytes_count = lwip_read(sockfd_data, data_buffer, MAX_BUF_LEN); + printf("%s\n", data_buffer); + lwip_close(sockfd_data); +} + +/** + * @description: Run the cd command to go to the target directory + * @param pathname - target directory + * @return void + */ +void ChangeDirectory(char *pathname) +{ + if (NULL == pathname) { + printf("[Error] path name can not be NULL\n"); + return; + } + + sprintf(msg_buffer,"CWD %s\r\n",pathname); + SendControlCommand(msg_buffer); + GetReplyMsg(); +} + +/** + * @description: Log out of the server + * @return void + */ +void Quit() +{ + SendControlCommand("QUIT\r\n"); + GetReplyMsg(); + lwip_close(sockfd_ctrl); +} + +/** + * @description: Test FTP client. + */ +void TestFTPClient(int argc, char* argv[]) +{ + printf("-------------------Config Network-------------------\n"); + // Set an ip address for the development board + char board_ipaddr[] = { 192, 168, 1, 103 }; // ip address of the development board to be set + char board_netmask[] = { 255, 255, 255, 0 }; // Subnet mask of the development board + char board_gwaddr[] = { 192, 168, 1, 0 }; // Development board gateway + lwip_config_tcp(0, board_ipaddr, board_netmask, board_gwaddr); + + // connect + printf("-------------------Connect-------------------\n"); + char connect_ip_addr[] = "192.168.1.100";// ftp server ipaddr + int connect_port = 21; // ftp server port + sprintf(server_ip_str,connect_ip_addr); + server_port = connect_port; + FillServerAddr(server_ip_str, server_port, &ftp_server_ctrl_addr); + CreateControlConnection(); + GetReplyMsg(); + + // login, set username and password here + printf("-------------------Login-------------------\n"); + char username[] = "linha"; + char password[] = "guoji123"; + if (LoginServer(username, password) == 0){ + printf("success login.\n"); + } + else{ + printf("login fail.\n"); + return; + } + + // TestFTPClient + printf("-------------------TestFTPClient-------------------\n"); + + printf("-------------------List Directory-------------------\n"); + ListCurrentDirectory(); // ls + + printf("-------------------Change Directory-------------------\n"); + char change_to_directory[] = "file"; + ChangeDirectory(change_to_directory); // cd file + + printf("-------------------List 10 files need to download-------------------\n"); + ListCurrentDirectory(); // ls + + printf("-------------------Download 10 files-------------------\n"); + char test_files[][10] = {"foo.txt", "baz.txt", "bar.txt", "tab.txt", "tap.txt", "out.txt", "hot.txt", "egg.txt", "cat.txt", "num.txt"}; + for (int i = 0; i < 10; i++) { + FileDownload(test_files[i]); // download + } + + printf("-------------------Quit-------------------\n"); + Quit(); // quit +} +PRIV_SHELL_CMD_FUNCTION(TestFTPClient, a simple test FTPClient sample, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.h b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.h new file mode 100644 index 000000000..d171d018f --- /dev/null +++ b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.h @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2023 AIIT Ubiquitous Team +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL +v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +/** + * @file: test_ftpclient.h + * @brief: Based on the protocol Lwip in XiUOS and the interface provided, this + file realized the basic functions of the FTP client, including login (verifying + user account and password), file directory display (ls), file directory entry (cd), + file download, etc. + * @version: 1.0 + * @author: Oscar + * @date: 2023/8/25 + */ + +#include +#include +#include "lwip/sockets.h" + +#define MAX_BUF_LEN 4096 // Maximum cache bytes 4k + +// Bind the server IP address +void FillServerAddr(const char* ip, unsigned short int port, struct sockaddr_in* pServer_addr); + +// Create a control connection +int CreateControlConnection(); + +// Create a data connection +int CreateDataConnection(); + +// Get a reply message +int GetReplyMsg(void); + +// Send control command +void SendControlCommand(const char* send_msg); + +// Logging In to the FTP Server +int LoginServer(char* username, char* password); + +// Before downloading the file, send the PASV command to enter passive mode, and the +// FTP server will open a new port for receiving the file data. +int PasvInitiateFileDownload(); + +// Download the file from the server +void FileDownload(char* filename); + +// Implement the ls command to display the files and directories in the current +// directory +void ListCurrentDirectory(); + +// Run the cd command to go to the target directory +void ChangeDirectory(char* pathname); + +// Log out of the server +void Quit(void); \ No newline at end of file