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..593b7dd6d --- /dev/null +++ b/APP_Framework/Applications/app_test/test_ftpclient/README.md @@ -0,0 +1,132 @@ +# ##modbus-tcp## + +## 1. 简介 + +基于XiZi内核一直FTP Client库,实现基于FTP协议的Client文件下载功能。 + +## 2. 数据结构设计说明 + +### 2.1 数据结构定义 +```c +typedef struct ZftpClientStruct +{ + char user_name[ZFTP_USER_NAME_LEN]; + char password[ZFTP_PASSWORD_LEN]; + char server_ip[ZFTP_SERVER_IP_LEN]; + char data_port[6]; + char control_port[6]; + int control_socket; + int data_socket; + DownCallbackType download_write; + UpCallbackType upload_read; + void *user_data; + int errorno; +}ZftpClientType; +``` +`ZftpClientType`结构体定义了一个FTP客户端的基本内容,包含服务器登陆的用户名、密码、服务器地址和端口号,以及处理数据上传和下载的回调函数指针。 + +### 2.2 FTP客户端下载流程与对应功能实现 +#### 1. FTP客户端下载流程 +ftp客户端从服务器下载文件基本流程如下: +从FTP服务器下载文件的基本流程如下: +1. 建立TCP连接,默认使用21端口。 +2. 连接成功之后,服务器会发送一行欢迎文字,例如:220 welcome. + 其中左边的数字220表示就绪状态,220后面有一个空格,空格后面是提示文字。 + 在解析命令应答的时候,只需要获取前面的数字即可。 +3. 收到欢迎信息后,开始登陆,先用USER命令发送用户名,服务器返回331状态。 + 然后再用PASS命令发送登陆密码,服务器返回530表示密码错误,返回230表示密码正确。 + 发送:USER XXX + 接收:331 Please, specify the password. + 发送:PASS XXX + 接收:230 Login successful. +4. 登陆成功之后,再发送一条TYPE I命令,进入二进制模式,这样获取文件数据的时候,就会以二进制字节流发送。避免以ASCII码格式发送文件数据。 +5. 获取文件长度 + 发送:SIZE /path/filename + 失败:550 /path/filename: No such file or directory + 成功:213 [filesize] + 返回[filesize]是十进制数字,表示该文件在大小,字节为单位 +6. 下载文件 + 下载文件前,先发送PASV命令,进入被动模式,服务器开放一个新的端口,用于接收文件数据。 + 客户端连接数据端口后,发送RETR命令请求下载文件。 + 发送:PASV + 接收:227 Entering Passive Mode (145,24,145,107,207,235). + 发送:RETR /path/filename + 接收:150 Opening BINARY mode data connection for /path/filename + 从数据端口接收文件数据 + 接收:226 Transfer complete +#### 2. 功能实现说明 +```c +/** + * @brief ftp客户端连接服务器 + * + * @param user_name + * @param password + * @param server_ip + * @return ZftpClientType* + */ +ZftpClientType *ZFTPLogin(char *user_name, char *password, char *server_ip); +/** + * @brief 设置ftp上传下载功能回调函数 + * + * @param ftp + * @param dw_write + * @param up_read + * @param user_data + * @return int + */ +int ZFTPSetCallback(ZftpClientType *ftp, DownCallbackType dw_write, UpCallbackType up_read, void *user_data); +/** + * @brief 获取文件名的对应文件大小 + * + * @param ftp + * @param file_name + * @param file_size + * @return int + */ +int ZFTPGetFilesize(ZftpClientType *ftp, char *file_name, uint32_t *file_size); +/** + * @brief 切换服务器文件路径 + * + * @param ftp + * @param path + * @return int + */ +int ZFTPChangePath(ZftpClientType *ftp, char *path); +/** + * @brief 下载对应大小的文件 + * + * @param ftp + * @param file_name + * @param file_size + * @return int + */ +int ZFTPDownloadFile(ZftpClientType *ftp, char *file_name, int file_size); +/** + * @brief 退出服务器 + * + * @param ftp + * @return int + */ +int ZFTPQuit(ZftpClientType *ftp); +``` +## 3. 测试程序说明 +测试程序通过`TestFtpFileDownload`指令下载服务器中的10个文件名为1-10的4kb文本文件。 +FTP服务器为FileZilla Server1.61。 + +## 4. 运行结果 +1. 首先配置并编译代码。在配置选项中需要开启LWIP和SD-Card功能。 +2. 设置本地FileZilla Server的服务器用户名和密码,服务器文件路径,并创建10个测试文件。 +3. 通过`TestFtpFileDownload`执行文件下载功能测试。 + 1. 其中,FTP Server的结果如下: +![Alt text](image-2.png) + 可以看到,在成功连接FTPserver后,切换至服务器目录/,之后下载了文件名分别为1.txt~10.txt的10个个文件。每个文件大小均为4kb。 + 2. FTP Client的执行结果如下: +![Alt text](image-3.png) + - 首先配置客户端IP和子网掩码等信息,之后进行了ftp登录并进入PASV模式。 + - 接着对每个文件分别进行下载,知道文件内容全部下载完成。 + + 3. 通过本地ls指令可以看到下载的文件大小为4096,与原文件大小一致 +![Alt text](image.png) + 4. 通过cat指令查看文件内容,与原文件一致。 +![Alt text](image-1.png) + diff --git a/APP_Framework/Applications/app_test/test_ftpclient/image-1.png b/APP_Framework/Applications/app_test/test_ftpclient/image-1.png new file mode 100644 index 000000000..172c37895 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/image-1.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/image-2.png b/APP_Framework/Applications/app_test/test_ftpclient/image-2.png new file mode 100644 index 000000000..a9ff3f5ba Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/image-2.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/image-3.png b/APP_Framework/Applications/app_test/test_ftpclient/image-3.png new file mode 100644 index 000000000..a612ec817 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/image-3.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/image.png b/APP_Framework/Applications/app_test/test_ftpclient/image.png new file mode 100644 index 000000000..1e2ad5008 Binary files /dev/null and b/APP_Framework/Applications/app_test/test_ftpclient/image.png differ diff --git a/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.c b/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.c index dae5939b3..effdf9408 100644 --- a/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.c +++ b/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.c @@ -1,27 +1,24 @@ /****************************************Copyright (c)**************************************************** -** fhqlongteng@163.com -** QQ:283669063 -**--------------File Info--------------------------------------------------------------------------------- -** File name: zFTP.c -** Last modified Date: 2020-12-01 -** Last Version: V1.00 -** Descriptions: ZFTP协议实现程序 -** -**-------------------------------------------------------------------------------------------------------- -** Created by: Zhao shimin -** Created date: 2020-12-01 -** Version: V1.00 -** Descriptions: -** -** -**-------------------------------------------------------------------------------------------------------- -** Modified by: -** Modified date: -** Version: -** Descriptions: -** -** Rechecked by: -*********************************************************************************************************/ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* 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. +*/ + +/* + * @Description: 基于Lwip的Ftp协议实现 + * @Version: V1.0.0 + * @Author: 好果汁有限公司 + * @Date: 2023-09-24 03:59:45 + * @LastEditors: blackcat 18436010132@163.com + * @LastEditTime: 2023-09-30 16:53:39 + */ #include "libftp.h" @@ -30,6 +27,7 @@ #include #include "lwip/sys.h" #include +#include #endif #ifdef ADD_NUTTX_FEATURES @@ -37,18 +35,20 @@ #include #include #include "stdio.h" +#include #endif -/********************************************************************************************************* -** Function name: zFTP_wait_server_ack() -** Descriptions: FTP client wait server ack -** input parameters: socket, ack_code, wait_time -** output parameters: None -** Returned value: EOK, -ERROR -*********************************************************************************************************/ -static int zFTP_wait_server_ack(int socket, uint32_t *ack_code, uint32_t wait_time) +/** + * @brief 等待服务器响应 + * + * @param socket + * @param ack_code + * @param wait_time + * @return EOK ERROR + */ +static int ZFTPWaitServerAck(int socket, uint32_t *ack_code, uint32_t wait_time) { fd_set readset; struct timeval timeout; @@ -60,7 +60,6 @@ static int zFTP_wait_server_ack(int socket, uint32_t *ack_code, uint32_t wait_t timeout.tv_usec = 0; /*wait the ack*/ - FD_ZERO(&readset); FD_SET(socket, &readset); @@ -79,8 +78,6 @@ static int zFTP_wait_server_ack(int socket, uint32_t *ack_code, uint32_t wait_t return -ERROR; } - - if(1 == sscanf(ftp_recv_buf, "%d", &code)) { *ack_code = code; @@ -94,14 +91,18 @@ static int zFTP_wait_server_ack(int socket, uint32_t *ack_code, uint32_t wait_t } -/********************************************************************************************************* -** Function name: zFTP_send_cmd_wait_server_ack() -** Descriptions: FTP client send the command and wait the sever ack -** input parameters: socket, cmd, cmd_len, ack_code, wait_time -** output parameters: None -** Returned value: EOK, -ERROR -*********************************************************************************************************/ -static int zFTP_send_cmd_wait_server_ack(int socket, char *cmd, uint32_t cmd_len, + +/** + * @brief 发送命令并等待响应 + * + * @param socket + * @param cmd + * @param cmd_len + * @param ack_code + * @param wait_time + * @return int + */ +static int ZFTPSendComandWaitServerAck(int socket, char *cmd, uint32_t cmd_len, uint32_t *ack_code, uint32_t wait_time) { fd_set readset; @@ -156,14 +157,19 @@ static int zFTP_send_cmd_wait_server_ack(int socket, char *cmd, uint32_t cmd_len } -/********************************************************************************************************* -** Function name: zFTP_filesize_send_cmd() -** Descriptions: zFTP send the get filesize command -** input parameters: 无 -** output parameters: 无 -** Returned value: 无 -*********************************************************************************************************/ -static int zFTP_filesize_send_cmd(int socket, char *cmd, uint32_t cmd_len, uint32_t *ack_code, + +/** + * @brief 获取文件大小 + * + * @param socket + * @param cmd + * @param cmd_len + * @param ack_code + * @param file_size + * @param wait_time + * @return int + */ +static int ZFTPFilesizeSendCmd(int socket, char *cmd, uint32_t cmd_len, uint32_t *ack_code, uint32_t *file_size, uint32_t wait_time) { fd_set readset; @@ -220,18 +226,19 @@ static int zFTP_filesize_send_cmd(int socket, char *cmd, uint32_t cmd_len, uint3 return -ERROR; } - } -/********************************************************************************************************* -** Function name: ftp_pasv_mode() -** Descriptions: FTP客户端发送命令给服务器进入pasv模式 -** input parameters: 无 -** output parameters: 无 -** Returned value: 无 -*********************************************************************************************************/ +/** + * @brief FTP客户端发送命令给服务器进入pasv模式 + * + * @param socket + * @param ack_code + * @param server_port + * @param wait_time + * @return int + */ static int zFTP_pasv_mode(int socket,uint32_t *ack_code, uint16_t *server_port, uint32_t wait_time) { fd_set readset; @@ -292,90 +299,17 @@ static int zFTP_pasv_mode(int socket,uint32_t *ack_code, uint16_t *server_port, -/********************************************************************************************************* -** Function name: zFTP_upload_file_data() -** Descriptions: zFTP download the file data -** input parameters: socket, buf, buf_size, wait_time -** output parameters: rd_len -** Returned value: EOK, -ERROR -*********************************************************************************************************/ -static int zFTP_upload_file_data(zftp_client *ftp, char *file_name, uint32_t wait_time) -{ - struct timeval timeout; - fd_set writeset; - int socket= -1; - uint8_t *file_buf = NULL; - uint32_t rd_len = 0, file_pos= 0, total_len = 0; - - - - timeout.tv_sec = wait_time/1000; - timeout.tv_usec = 0; - - - socket = ftp->data_socket; - - file_buf = malloc(ZFTP_FILE_DATA_BUF_SIZE); - if(file_buf == NULL) - { - printf("Cannot malloc the file data buf!"); - return -ERROR; - } - - if(ftp->upload_read == NULL) - { - return -ERROR; - } - - while(1) - { - if(EOK != ftp->upload_read(ftp, file_name, file_buf, ZFTP_FILE_DATA_BUF_SIZE, file_pos, &rd_len, &total_len)) - { - free(file_buf); - return -ERROR; - } - FD_ZERO(&writeset); - FD_SET(socket, &writeset); - if (select(socket + 1, NULL, &writeset, NULL, &timeout) <= 0) - { - free(file_buf); - printf("select data write socket timeout!"); - return -ERROR; - } - - // Wait and receive the packet back from the server. If n == -1, it failed. - if(rd_len != send(socket, (char*)file_buf, rd_len, 0)) - { - free(file_buf); - printf("reading data socket error!"); - return -ERROR; - } - - file_pos = file_pos + rd_len; - - if(file_pos >= total_len) - { - /*upload the file finish!*/ - break; - } - - } - - free(file_buf); - return EOK; - -} - - - -/********************************************************************************************************* -** Function name: zFTP_download_file_data() -** Descriptions: zFTP download the file data -** input parameters: socket, buf, buf_size, wait_time -** output parameters: rd_len -** Returned value: EOK, -ERROR -*********************************************************************************************************/ -static int zFTP_download_file_data(int socket, uint8_t *buf, uint32_t buf_size, +/** + * @brief 下载文件数据 + * + * @param socket + * @param buf + * @param buf_size + * @param rd_len + * @param wait_time + * @return int + */ +static int ZFTPDownloadFileData(int socket, uint8_t *buf, uint32_t buf_size, uint32_t *rd_len, uint32_t wait_time) { struct timeval timeout; @@ -412,14 +346,19 @@ static int zFTP_download_file_data(int socket, uint8_t *buf, uint32_t buf_size, } -/********************************************************************************************************* -** Function name: zFTP_download_send_cmd() -** Descriptions: zFTP send the download file command -** input parameters: 无 -** output parameters: 无 -** Returned value: 无 -*********************************************************************************************************/ -static int zFTP_download_send_cmd(int socket, char *cmd, uint32_t cmd_len, uint32_t *ack_code, + +/** + * @brief 请求下载文件 + * + * @param socket + * @param cmd + * @param cmd_len + * @param ack_code + * @param file_size + * @param wait_time + * @return int + */ +static int ZFTPDownloadSendCmd(int socket, char *cmd, uint32_t cmd_len, uint32_t *ack_code, uint32_t *file_size, uint32_t wait_time) { fd_set readset; @@ -463,17 +402,10 @@ static int zFTP_download_send_cmd(int socket, char *cmd, uint32_t cmd_len, uint3 return -ERROR; } - /*获取文件大小和应答码*/ - // if(2 == sscanf(ftp_recv_buf, "%d%*[^(](%d", &code,&a)) - // { - // *ack_code = code; - // *file_size = a; - // return EOK; - // } + /*获取应答码*/ if(1 == sscanf(ftp_recv_buf, "%d%*[^(](", &code)) { *ack_code = code; - // *file_size = a; //通过ftp zilla抓包分析,response中不含size return EOK; } else @@ -481,28 +413,25 @@ static int zFTP_download_send_cmd(int socket, char *cmd, uint32_t cmd_len, uint3 printf("Rcv data:%s\n", ftp_recv_buf); return -ERROR; } - - } -/********************************************************************************************************* -** Function name: zFTP_quit() -** Descriptions: ftp logout and realse the zftp_client -** input parameters: ftp -** output parameters: None -** Returned value: EOK -*********************************************************************************************************/ -int zFTP_quit(zftp_client *ftp) +/** + * @brief 退出服务器并释放客户端资源 + * + * @param ftp + * @return int + */ +int ZFTPQuit(ZftpClientType *ftp) { uint32_t ack_code = 0; char cmd_buf[50] = {0}; - //ASSERT(ftp); + assert(ftp); /*退出登陆*/ strcpy(cmd_buf, "QUIT\r\n"); - if((EOK != zFTP_send_cmd_wait_server_ack(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPSendComandWaitServerAck(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 221)) { printf("Server logout error, ack_code:%d", ack_code); @@ -518,132 +447,16 @@ int zFTP_quit(zftp_client *ftp) } -/********************************************************************************************************* -** Function name: zFTP_upload_file() -** Descriptions: upload the file to FTP server -** input parameters: ftp, path, file_name -** output parameters: file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_upload_file(zftp_client *ftp, char *file_name) -{ - char cmd_buf[50] = {0}; - uint32_t ack_code = 0; - int ret = EOK, fd = 0; - struct addrinfo hints, *addr_list = NULL, *cur = NULL; - uint16_t port = 0; - - //ASSERT(ftp); - - /*Enter the pasv mode */ - if(EOK != zFTP_pasv_mode(ftp->control_socket, &ack_code, &port, ZFTP_CMD_TIMEOUT) || (ack_code != 227)) - { - printf("Enter pasv mode error, ack_code:%d", ack_code); - ret = -ERROR; - goto __exit; - } - - - /*creat the data socket link */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - sprintf(ftp->data_port, "%d", port); - - /* Do name resolution with both IPv6 and IPv4 */ - if (getaddrinfo(ftp->server_ip, ftp->data_port, &hints, &addr_list) != EOK) - { - goto __exit; - } - - for (cur = addr_list; cur != NULL; cur = cur->ai_next) - { - fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); - if (fd < 0) - { - continue; - } - - if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) - { - ftp->data_socket = fd; - break; - } - - closesocket(fd); - - } - freeaddrinfo(addr_list); - - if(ftp->data_socket < 0) - { - ret = -ERROR; - goto __exit; - } - - /*send download the file command*/ - sprintf(cmd_buf, "STOR %s\r\n", file_name); - if((EOK != zFTP_send_cmd_wait_server_ack(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || - (ack_code != 150)) - { - printf("upload file error, ack_code:%d", ack_code); - ret = -ERROR; - goto __exit; - } - - - /* read the file send to FTP server */ - if(EOK == zFTP_upload_file_data(ftp, file_name, ZFTP_CMD_TIMEOUT)) - { - - } - else - { - ret = -ERROR; - goto __exit; - } - - /*close the data socket*/ - if(ftp->data_socket >= 0) - { - closesocket(ftp->data_socket); - ftp->data_socket = -1; - } - - - - /*waite the upload file finish */ - if((EOK != zFTP_wait_server_ack(ftp->control_socket, &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 226)) - { - printf("Server not ack download complete, ack_code:%d", ack_code); - } - - ret = EOK; - -__exit: - if(ftp->data_socket >= 0) - { - closesocket(ftp->data_socket); - ftp->data_socket = -1; - } - - return ret; - -} - - - -/********************************************************************************************************* -** Function name: zFTP_download_file() -** Descriptions: download the file from FTP server -** input parameters: ftp, path, file_name -** output parameters: file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_download_file(zftp_client *ftp, char *file_name, int _file_size) +/** + * @brief 从服务器下载文件 + * + * @param ftp + * @param file_name + * @param _file_size + * @return int + */ +int ZFTPDownloadFile(ZftpClientType *ftp, char *file_name, int _file_size) { char cmd_buf[50] = {0}; uint32_t ack_code = 0; @@ -655,7 +468,7 @@ int zFTP_download_file(zftp_client *ftp, char *file_name, int _file_size) uint16_t port = 0; uint32_t file_size = _file_size; - //ASSERT(ftp); + assert(ftp); file_buf = malloc(ZFTP_FILE_DATA_BUF_SIZE); if(file_buf == NULL) @@ -715,7 +528,7 @@ int zFTP_download_file(zftp_client *ftp, char *file_name, int _file_size) /*send download the file command*/ sprintf(cmd_buf, "RETR %s\r\n", file_name); - if((EOK != zFTP_download_send_cmd(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, &file_size, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPDownloadSendCmd(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, &file_size, ZFTP_CMD_TIMEOUT)) || (ack_code != 150)) { printf("Download file error, ack_code:%d\n", ack_code); @@ -727,7 +540,7 @@ int zFTP_download_file(zftp_client *ftp, char *file_name, int _file_size) /* read the file */ while(file_size > file_pos) { - if(EOK == zFTP_download_file_data(ftp->data_socket, file_buf, ZFTP_FILE_DATA_BUF_SIZE, &rd_len, ZFTP_CMD_TIMEOUT)) + if(EOK == ZFTPDownloadFileData(ftp->data_socket, file_buf, ZFTP_FILE_DATA_BUF_SIZE, &rd_len, ZFTP_CMD_TIMEOUT)) { if((rd_len) && (ftp->download_write)) { @@ -748,7 +561,7 @@ int zFTP_download_file(zftp_client *ftp, char *file_name, int _file_size) } /*waite the download file finish */ - if((EOK != zFTP_wait_server_ack(ftp->control_socket, &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 226) || (file_pos !=file_size )) + if((EOK != ZFTPWaitServerAck(ftp->control_socket, &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 226) || (file_pos !=file_size )) { printf("Server not ack download complete, ack_code:%d\n", ack_code); ret = ERROR; @@ -778,25 +591,23 @@ __exit: -/********************************************************************************************************* -** Function name: zFTP_change_path() -** Descriptions: change the path of FTP server -** input parameters: ftp, path, path -** output parameters: file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_change_path(zftp_client *ftp, char *path) +/** + * @brief 切换服务器路径 + * + * @param ftp + * @param path + * @return int + */ +int ZFTPChangePath(ZftpClientType *ftp, char *path) { char cmd_buf[50] = {0}; uint32_t ack_code = 0; - //ASSERT(ftp); - //ASSERT(path); - + assert(ftp); + assert(path); /*change path*/ - sprintf(cmd_buf, "CWD %s\r\n", path); - if((EOK != zFTP_send_cmd_wait_server_ack(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPSendComandWaitServerAck(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 250)) { printf("Switch dir error, ack_code:%d", ack_code); @@ -811,26 +622,24 @@ int zFTP_change_path(zftp_client *ftp, char *path) } - -/********************************************************************************************************* -** Function name: zFTP_get_filesize() -** Descriptions: get the file size from FTP server -** input parameters: ftp, path, file_name -** output parameters: file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_get_filesize(zftp_client *ftp, char *file_name, uint32_t *file_size) +/** + * @brief 获取文件大小 + * + * @param ftp + * @param file_name + * @param file_size + * @return int + */ +int ZFTPGetFilesize(ZftpClientType *ftp, char *file_name, uint32_t *file_size) { char cmd_buf[50] = {0}; uint32_t ack_code = 0; - //ASSERT(ftp); - //ASSERT(file_name); - - + assert(ftp); + assert(file_name); /*get the file size*/ sprintf(cmd_buf, "SIZE %s\r\n", file_name); - if((EOK != zFTP_filesize_send_cmd(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, file_size, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPFilesizeSendCmd(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, file_size, ZFTP_CMD_TIMEOUT)) || (ack_code != 213)) { printf("Get file size error, ack_code:%d", ack_code); @@ -845,16 +654,19 @@ int zFTP_get_filesize(zftp_client *ftp, char *file_name, uint32_t *file_size) } -/********************************************************************************************************* -** Function name: zFTP_set_callback() -** Descriptions: set the file download and upload callback function -** input parameters: ftp, dw_write, up_read, user_data -** output parameters: None -** Returned value: EOK -*********************************************************************************************************/ -int zFTP_set_callback(zftp_client *ftp, down_callback dw_write, up_callback up_read, void *user_data) + +/** + * @brief 设置客户端上传与下载回调函数 + * + * @param ftp + * @param dw_write + * @param up_read + * @param user_data + * @return int + */ +int ZFTPSetCallback(ZftpClientType *ftp, DownCallbackType dw_write, UpCallbackType up_read, void *user_data) { - //ASSERT(ftp); + assert(ftp); ftp->download_write = dw_write; ftp->upload_read = up_read; @@ -864,16 +676,17 @@ int zFTP_set_callback(zftp_client *ftp, down_callback dw_write, up_callback up_ } -/********************************************************************************************************* -** Function name: zFTP_login() -** Descriptions: ftp login server -** input parameters: user_name, password, server_ip -** output parameters: None -** Returned value: zftp_client -*********************************************************************************************************/ -zftp_client *zFTP_login(char *user_name, char *password, char *server_ip) +/** + * @brief 客户端登录 + * + * @param user_name + * @param password + * @param server_ip + * @return ZftpClientType* + */ +ZftpClientType *ZFTPLogin(char *user_name, char *password, char *server_ip) { - zftp_client *ftp = NULL; + ZftpClientType *ftp = NULL; int fd = -1; uint32_t ack_code = 0; char cmd_buf[50] = {0}; @@ -887,11 +700,11 @@ zftp_client *zFTP_login(char *user_name, char *password, char *server_ip) } /*create a zftp client buf*/ - ftp = malloc(sizeof(zftp_client)); + ftp = malloc(sizeof(ZftpClientType)); if(ftp) { - memset(ftp, 0, sizeof(zftp_client)); + memset(ftp, 0, sizeof(ZftpClientType)); ftp->data_socket = -1; ftp->control_socket = -1; @@ -935,7 +748,7 @@ zftp_client *zFTP_login(char *user_name, char *password, char *server_ip) if(ftp->control_socket >= 0) { /* wait the login success and welcome*/ - if(EOK != zFTP_wait_server_ack(ftp->control_socket, &ack_code, ZFTP_CMD_TIMEOUT) || (ack_code != 220)) + if(EOK != ZFTPWaitServerAck(ftp->control_socket, &ack_code, ZFTP_CMD_TIMEOUT) || (ack_code != 220)) { printf("Server not ack welcome, ack_code:%d", ack_code); goto __exit; @@ -943,7 +756,7 @@ zftp_client *zFTP_login(char *user_name, char *password, char *server_ip) /*input the user name */ sprintf(cmd_buf, "USER %s\r\n", ftp->user_name); - if((EOK != zFTP_send_cmd_wait_server_ack(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPSendComandWaitServerAck(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 331)) { printf("Login user error, ack_code:%d", ack_code); @@ -952,7 +765,7 @@ zftp_client *zFTP_login(char *user_name, char *password, char *server_ip) /*input the password */ sprintf(cmd_buf, "PASS %s\r\n", ftp->password); - if((EOK != zFTP_send_cmd_wait_server_ack(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPSendComandWaitServerAck(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 230)) { printf("Login password error, ack_code:%d", ack_code); @@ -961,7 +774,7 @@ zftp_client *zFTP_login(char *user_name, char *password, char *server_ip) /*change bin mode*/ strcpy(cmd_buf, "TYPE I\r\n"); - if((EOK != zFTP_send_cmd_wait_server_ack(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || + if((EOK != ZFTPSendComandWaitServerAck(ftp->control_socket, cmd_buf, strlen(cmd_buf), &ack_code, ZFTP_CMD_TIMEOUT)) || (ack_code != 200)) { printf("Switch bin mode error, ack_code:%d", ack_code); @@ -989,7 +802,5 @@ __exit: return NULL; } -/********************************************************************************************************* -** End of file -*********************************************************************************************************/ + diff --git a/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.h b/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.h index 20eaeb454..4ca942c7c 100644 --- a/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.h +++ b/APP_Framework/Applications/app_test/test_ftpclient/libftp/libftp.h @@ -1,34 +1,30 @@ -/****************************************Copyright (c)**************************************************** -** fhqlongteng@163.com -** QQ:283669063 -**--------------File Info--------------------------------------------------------------------------------- -** File name: zFTP.h -** Last modified Date: 2020-12-01 -** Last Version: V1.00 -** Descriptions: FTPͨЭͷļ -** -**-------------------------------------------------------------------------------------------------------- -** Created by: Zhao shimin -** Created date: 2020-12-01 -** Version: V1.00 -** Descriptions: -** -**-------------------------------------------------------------------------------------------------------- -** Modified by: -** Modified date: -** Version: -** Descriptions: -** -** Rechecked by: -*********************************************************************************************************/ -#ifndef __zFTP_H_ -#define __zFTP_H_ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* 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. +*/ + +/* + * @Description: 基于Lwip的Ftp协议实现 + * @Version: V1.0.0 + * @Author: 好果汁有限公司 + * @Date: 2023-09-24 03:59:45 + * @LastEditors: blackcat 18436010132@163.com + * @LastEditTime: 2023-09-30 16:53:39 + */ + +#ifndef __LIBFTP_H_ +#define __LIBFTP_H_ #include -/********************************************************************************************************* -* FTPĿͻ˵Ĵ洢Ļ -*********************************************************************************************************/ + #ifndef ZFTP_USER_NAME_LEN #define ZFTP_USER_NAME_LEN 20 #endif @@ -53,89 +49,91 @@ #define ZFTP_CMD_TIMEOUT 2000 -typedef int (*down_callback)(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t total_len); -typedef int (*up_callback)(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t *read_len, uint32_t *total_len); -/********************************************************************************************************* -* zFTPͨŹݽṹ -*********************************************************************************************************/ -typedef struct zftp_client_struct +typedef int (*DownCallbackType)(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t total_len); +typedef int (*UpCallbackType)(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t *read_len, uint32_t *total_len); + + +typedef struct ZftpClientStruct { char user_name[ZFTP_USER_NAME_LEN]; char password[ZFTP_PASSWORD_LEN]; char server_ip[ZFTP_SERVER_IP_LEN]; char data_port[6]; char control_port[6]; - int control_socket; /* FTPsocket */ - int data_socket; /* FTPsocket */ - down_callback download_write; - up_callback upload_read; + int control_socket; /* FTP control socket */ + int data_socket; /* FTP data socket */ + DownCallbackType download_write; + UpCallbackType upload_read; void *user_data; int errorno; -}zftp_client; +}ZftpClientType; -/********************************************************************************************************* -** Function name zFTP_login() -** Descriptions: ftp login server -** input parameters user_name, password, server_ip -** output parameters None -** Returned value: zftp_client -*********************************************************************************************************/ -zftp_client *zFTP_login(char *user_name, char *password, char *server_ip); -/********************************************************************************************************* -** Function name zFTP_set_callback() -** Descriptions: set the file download and upload callback function -** input parameters ftp, dw_write, up_read, user_data -** output parameters None -** Returned value: RT_EOK -*********************************************************************************************************/ -int zFTP_set_callback(zftp_client *ftp, down_callback dw_write, up_callback up_read, void *user_data); +/** + * @brief ftp客户端连接服务器 + * + * @param user_name + * @param password + * @param server_ip + * @return ZftpClientType* + */ +ZftpClientType *ZFTPLogin(char *user_name, char *password, char *server_ip); -/********************************************************************************************************* -** Function name zFTP_get_filesize() -** Descriptions: get the file size from FTP server -** input parameters ftp, path, file_name -** output parameters file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_get_filesize(zftp_client *ftp, char *file_name, uint32_t *file_size); -/********************************************************************************************************* -** Function name zFTP_change_path() -** Descriptions: change the path of FTP server -** input parameters ftp, path, path -** output parameters file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_change_path(zftp_client *ftp, char *path); +/** + * @brief 设置ftp上传下载功能回调函数 + * + * @param ftp + * @param dw_write + * @param up_read + * @param user_data + * @return int + */ +int ZFTPSetCallback(ZftpClientType *ftp, DownCallbackType dw_write, UpCallbackType up_read, void *user_data); -/********************************************************************************************************* -** Function name zFTP_download_file() -** Descriptions: download the file from FTP server -** input parameters ftp, path, file_name -** output parameters file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_download_file(zftp_client *ftp, char *file_name, int file_size); -/********************************************************************************************************* -** Function name zFTP_upload_file() -** Descriptions: upload the file to FTP server -** input parameters ftp, path, file_name -** output parameters file_size -** Returned value: zftp_client -*********************************************************************************************************/ -int zFTP_upload_file(zftp_client *ftp, char *file_name); +/** + * @brief 获取文件名的对应文件大小 + * + * @param ftp + * @param file_name + * @param file_size + * @return int + */ +int ZFTPGetFilesize(ZftpClientType *ftp, char *file_name, uint32_t *file_size); -/********************************************************************************************************* -** Function name zFTP_quit() -** Descriptions: ftp logout and realse the zftp_client -** input parameters ftp -** output parameters None -** Returned value: RT_EOK -*********************************************************************************************************/ -int zFTP_quit(zftp_client *ftp); + +/** + * @brief 切换服务器文件路径 + * + * @param ftp + * @param path + * @return int + */ +int ZFTPChangePath(ZftpClientType *ftp, char *path); + + +/** + * @brief 下载对应大小的文件 + * + * @param ftp + * @param file_name + * @param file_size + * @return int + */ +int ZFTPDownloadFile(ZftpClientType *ftp, char *file_name, int file_size); + + + + +/** + * @brief 退出服务器 + * + * @param ftp + * @return int + */ +int ZFTPQuit(ZftpClientType *ftp); #endif diff --git a/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c index 1df536a8b..663ee328a 100644 --- a/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c +++ b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.c @@ -1,27 +1,24 @@ /****************************************Copyright (c)**************************************************** -** fhqlongteng@163.com -** QQ:283669063 -**--------------File Info--------------------------------------------------------------------------------- -** File name: zFTP_demo.c -** Last modified Date: 2020-12-01 -** Last Version: V1.00 -** Descriptions: zFTP demo -** -**-------------------------------------------------------------------------------------------------------- -** Created by: Zhao shimin -** Created date: 2020-12-01 -** Version: V1.00 -** Descriptions: -** -** -**-------------------------------------------------------------------------------------------------------- -** Modified by: -** Modified date: -** Version: -** Descriptions: -** -** Rechecked by: -*********************************************************************************************************/ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* 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. +*/ + +/* + * @Description: Ftp客户端功能测试 + * @Version: V1.0.0 + * @Author: 好果汁有限公司 + * @Date: 2023-09-24 03:59:45 + * @LastEditors: blackcat 18436010132@163.com + * @LastEditTime: 2023-09-30 16:53:39 + */ #include "./libftp/libftp.h" #ifdef ADD_XIZI_FEATURES @@ -29,76 +26,30 @@ #include #include "lwip/sys.h" #endif -#define PKG_USING_ZFTP 1 - -#ifdef PKG_USING_ZFTP -/********************************************************************************************************* -*       定义FTP的默认用户名称,服务器地址,端口等 -*********************************************************************************************************/ -#define FTP_SVR_ADDR "192.168.1.100" // +#define FTP_SVR_ADDR "192.168.1.100" #define FTP_SVR_PATH "/" #define FTP_USER_NAME "test" #define FTP_PASSWORD "123456" -#define FTP_FILENAME "test.txt" -#define FIRMWARE_FLASH_PARTITION "firmware" -#define FIRMWARE_STORE_ADDR 0 - -static char tcp_demo_ipaddr[] = {192, 168, 1, 110}; -static char tcp_demo_netmask[] = {255, 255, 255, 0}; -static char tcp_demo_gwaddr[] = {192, 168, 1, 1}; - -/********************************************************************************************************* -** Function name: file_read() -** Descriptions: read file from flash -** input parameters: ftp, buf, len, file_pos, total_len -** output parameters: None -** Returned value: RT_OK, ERROR -*********************************************************************************************************/ -int file_read(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t *read_len, uint32_t *total_len) -{ - const struct fal_partition *partition = NULL; - - *total_len = 600 * 1024; - - // partition = fal_partition_find(FIRMWARE_FLASH_PARTITION); - if (partition == NULL) - { - // LOG_E("Find partition (%s) failed, Cannot save the net para!", FIRMWARE_FLASH_PARTITION); - return -ERROR; - } - - if(file_pos + len <= *total_len) - { - *read_len = len; - } - else - { - *read_len = *total_len - file_pos; - } - - // if(*read_len != fal_partition_read(partition, FIRMWARE_STORE_ADDR + file_pos, buf, *read_len)) - { - // LOG_E("write file error, file_pos = %d", file_pos); - } - return EOK; +static char TcpIpAddr[] = {192, 168, 1, 110}; +static char TcpNetmask[] = {255, 255, 255, 0}; +static char TcpGatewayAddr[] = {192, 168, 1, 1}; - -} - - - -/********************************************************************************************************* -** Function name: file_write() -** Descriptions: write file into flash -** input parameters: ftp, buf, len, file_pos, total_len -** output parameters: None -** Returned value: RT_OK, ERROR -*********************************************************************************************************/ -int file_write(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t total_len) +/** + * @brief ftp客户端下载回调函数 + * + * @param handle + * @param file_name + * @param buf + * @param len + * @param file_pos + * @param total_len + * @return int + */ +int FileWrite(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint32_t file_pos, uint32_t total_len) { //open the file in sdcard FILE* fp = fopen(file_name,"a+"); @@ -106,11 +57,8 @@ int file_write(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint3 printf("file open error.\n"); return -ERROR; } + printf("open file %s\n", file_name); - //move to file pos to write - // if(fseek(fp, file_pos, SEEK_SET) != 0){ - // printf("fseek tp %d failed.\n", file_pos); - // } int err_flag = fwrite(buf, sizeof(uint8_t),len,fp); if(err_flag<0){ printf("write failed,error:%d\n",err_flag); @@ -121,103 +69,17 @@ int file_write(void * handle, char *file_name, uint8_t *buf, uint32_t len, uint3 fclose(fp); return EOK; - - } -/********************************************************************************************************* -** Function name: file_write() -** Descriptions: write file into flash -** input parameters: ftp, buf, len, file_pos, total_len -** output parameters: None -** Returned value: RT_OK, ERROR -*********************************************************************************************************/ -int file_erase(uint32_t file_len) -{ - - - - return EOK; - - -} - - -/********************************************************************************************************* -** Function name: cmd_ftp_download() -** Descriptions: ftp download command line -** input parameters: argc, argv -** output parameters: None -** Returned value: RT_OK, ERROR -*********************************************************************************************************/ -int cmd_ftp_download(int argc, char **argv) -{ - lwip_config_tcp(0, tcp_demo_ipaddr, tcp_demo_netmask, tcp_demo_gwaddr); - - zftp_client *ftp; - uint32_t file_size = 0; - - - - ftp = zFTP_login(FTP_USER_NAME, FTP_PASSWORD, FTP_SVR_ADDR); - - if(ftp == NULL) - { - printf("zFTP login fail!\n"); - } - else - { - zFTP_set_callback(ftp, file_write, file_read, NULL); - - zFTP_change_path(ftp, FTP_SVR_PATH); - - if(strcmp(argv[2], "upload") == 0) - { - if(EOK == zFTP_upload_file(ftp, argv[1])) - { - printf("zFTP upload success!\n"); - } - else - { - printf("zFTP upload %s faile!\n", argv[1]); - } - } - else - { - if(EOK == zFTP_get_filesize(ftp, argv[1], &file_size)) - { - printf("zFTP file %s size:%d!\n", argv[1], file_size); - // file_erase(file_size); - fopen(argv[1], "w+"); //清除原文件内容,实现覆盖下载文件 - - if(EOK == zFTP_download_file(ftp, argv[1], file_size)) - { - printf("zFTP download success len: %d!\n", file_size); - } - - } - } - - zFTP_quit(ftp); - - } - - return 0; -} - -PRIV_SHELL_CMD_FUNCTION(cmd_ftp_download, a ftp client download sample, PRIV_SHELL_CMD_MAIN_ATTR); - void TestFtpFileDownload(){ - lwip_config_tcp(0, tcp_demo_ipaddr, tcp_demo_netmask, tcp_demo_gwaddr); - zftp_client *ftp; + lwip_config_tcp(0, TcpIpAddr, TcpNetmask, TcpGatewayAddr); + ZftpClientType *ftp; uint32_t file_size = 0; uint32_t total_size = 0; - - - ftp = zFTP_login(FTP_USER_NAME, FTP_PASSWORD, FTP_SVR_ADDR); + ftp = ZFTPLogin(FTP_USER_NAME, FTP_PASSWORD, FTP_SVR_ADDR); if(ftp == NULL) { @@ -225,17 +87,17 @@ void TestFtpFileDownload(){ } else { - zFTP_set_callback(ftp, file_write, file_read, NULL); - zFTP_change_path(ftp, FTP_SVR_PATH); + ZFTPSetCallback(ftp, FileWrite, NULL, NULL); + ZFTPChangePath(ftp, FTP_SVR_PATH); for(int i=1; i<11; i++){ char file_name[10] = ""; sprintf(file_name, "%d.txt", i); - if(EOK == zFTP_get_filesize(ftp, file_name, &file_size)) + if(EOK == ZFTPGetFilesize(ftp, file_name, &file_size)) { printf("zFTP file %s size:%d!\n", file_name, file_size); fopen(file_name, "w+"); //清除原文件内容,实现覆盖下载文件 - if(EOK == zFTP_download_file(ftp, file_name, file_size)) + if(EOK == ZFTPDownloadFile(ftp, file_name, file_size)) { printf("zFTP download success len: %d!\n", file_size); } @@ -245,14 +107,8 @@ void TestFtpFileDownload(){ printf("All download finished. Total size: %d\n", total_size); } - zFTP_quit(ftp); + ZFTPQuit(ftp); } PRIV_SHELL_CMD_FUNCTION(TestFtpFileDownload, a ftp client test sample, PRIV_SHELL_CMD_MAIN_ATTR); - -/********************************************************************************************************* -** End of file -*********************************************************************************************************/ -#endif - diff --git a/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.h b/APP_Framework/Applications/app_test/test_ftpclient/test_ftpclient.h deleted file mode 100644 index e69de29bb..000000000