123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- #include "ftpd.h"
- #include "avltree.h"
- #include "bsp_fatfs.h"
- #include "ff.h"
- #include "fly_param.h"
- #include "ftp_server.h"
- #include "os_cpu.h"
- #include "sockets.h"
- #include "ucos_ii.h"
- #include <stdint.h>
- #include <stdio.h>
- static struct avl_root ftp_root = {.avl_node = NULL}; // 命令匹配的平衡二叉树树根
- /* Private variables ------------------------------------------------------------*/
- static const char normal_format[] = "-rw-rw-rw- 1 user ftp %11ld %s %02i %5i %s\r\n";
- static const char this_year_format[] = "-rw-rw-rw- 1 user ftp %11ld %s %02i %02i:%02i %s\r\n";
- static const char *month_list[] = { // 月份从 1 到 12 ,0 填充 NULL
- NULL,
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dez"};
- // ftp 命令树构建
- #define FTP_REGISTER_COMMAND(CMD) \
- do \
- { \
- static ftp_cmd_t CmdBuf; \
- CmdBuf.index = FTP_STR2ID(#CMD); \
- CmdBuf.func = cmd_##CMD; \
- ftp_insert_command(&CmdBuf); \
- } while (0)
- // ftp 文件列表格式
- #define NORMAL_LIST(listbuf, filesize, month, day, year, filename) \
- sprintf(listbuf, normal_format, (filesize), month_list[(month)], (day), (year), (filename))
- #define THIS_YEAR_LIST(listbuf, filesize, month, day, hour, min, filename) \
- sprintf(listbuf, this_year_format, (filesize), month_list[(month)], (day), (hour), (min), (filename))
- // ftp 格式一般为 xxxx /dirx/diry/\r\n ,去掉 /\r\n 提取可用路径
- #define FTP_PATH_GET(path, pathend) \
- do \
- { \
- while (*path == ' ') \
- ++path; \
- if (*pathend == '\n') \
- *pathend-- = 0; \
- if (*pathend == '\r') \
- *pathend-- = 0; \
- if (*pathend == '/') \
- *pathend = 0; \
- } while (0)
- /**
- * @brief ftp_insert_command
- * 命令树插入
- * @param pCmd 命令控制块
- * @return 成功返回 0
- */
- int ftp_insert_command(ftp_cmd_t *p_cmd)
- {
- struct avl_node **tmp = &ftp_root.avl_node;
- struct avl_node *parent = NULL;
- while (*tmp)
- {
- ftp_cmd_t *this = container_of(*tmp, ftp_cmd_t, cmd_node);
- parent = *tmp;
- if (p_cmd->index < this->index)
- tmp = &((*tmp)->avl_left);
- else if (p_cmd->index > this->index)
- tmp = &((*tmp)->avl_right);
- else
- return 1;
- }
- avl_insert(&ftp_root, &p_cmd->cmd_node, parent, tmp);
- return 0;
- }
- /**
- * @brief ftp_search_command
- * 命令树查找,根据 Index 号找到对应的控制块
- * @param index 命令号
- * @return 成功 Index 号对应的控制块
- */
- ftp_cmd_t *ftp_search_command(int i_ctrl_cmd)
- {
- struct avl_node *node = ftp_root.avl_node;
- while (node)
- {
- ftp_cmd_t *p_cmd = container_of(node, ftp_cmd_t, cmd_node);
- if (i_ctrl_cmd < p_cmd->index)
- node = node->avl_left;
- else if (i_ctrl_cmd > p_cmd->index)
- node = node->avl_right;
- else
- return p_cmd;
- }
- return NULL;
- }
- // 登录系统用户名
- static void cmd_user(ftp_mbox_t *msgbox)
- {
- if (strcasecmp(msgbox->arg, "root") == 0)
- {
- send(msgbox->cmd_socket, msg331, sizeof(msg331) - 1, 0);
- }
- else
- {
- send(msgbox->cmd_socket, msg331, sizeof(msg331) - 1, 0);
- }
- }
- // 登录系统密码
- static void cmd_pass(ftp_mbox_t *msgbox)
- {
- // printf(msgbox->arg);
- // if (strcasecmp(msgbox->arg, "ASASAS") == 0)
- // {
- send(msgbox->cmd_socket, msg230, sizeof(msg230) - 1, 0);
- // }
- // else
- // {
- // send(msgbox->cmd_socket, msg503, sizeof(msg503) - 1, 0);
- // }
- }
- // 操作系统类型
- static void cmd_syst(ftp_mbox_t *msgbox)
- {
- static const char reply_msg[] = "215 UNIX Type: L8\r\n"; // 215 系统类型回复
- send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- }
- // 显示当前工作目录
- static void cmd_pwd(ftp_mbox_t *msgbox)
- {
- #if 1
- char reply_msg[128]; // 257 路径名建立
- // sprintf(reply_msg, "257 \"%s/\"\r\n", msgbox->current_dir);
- sprintf(reply_msg, "257 \"%s/\"\r\n", "LINUX");
- #else
- static const char reply_msg[] = "257 \"/\"\r\n";
- #endif
- send(msgbox->cmd_socket, reply_msg, strlen(reply_msg), 0);
- }
- /**
- * @brief cmd_noop
- * ftp 命令端口输入 noop
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_noop(ftp_mbox_t *msgbox)
- {
- static const char reply_msg[] = "200 Operation successful\r\n";
- send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- }
- // 路径名建立
- static void cmd_cwd(ftp_mbox_t *msgbox)
- {
- static const char reply_msg[] = "250 Operation successful\r\n";
- DIR fsdir;
- char *pcFilePath = msgbox->arg;
- char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
- FTP_PATH_GET(pcFilePath, pcPathEnd);
- if (FR_OK != f_opendir(&fsdir, pcFilePath))
- {
- goto cmddone;
- }
- f_closedir(&fsdir);
- if (pcPathEnd != pcFilePath)
- memcpy(msgbox->current_dir, pcFilePath, pcPathEnd - pcFilePath);
- msgbox->current_dir[pcPathEnd - pcFilePath] = 0;
- cmddone:
- send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- }
- // static void cmd_feat(ftp_mbox_t *msgbox)
- // {
- // static const char reply_msg[] = "211-feature:\r\n";
- // static const char msgtprt[] = "EPRT\r\n";
- // send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- // send(msgbox->cmd_socket, msgtprt, sizeof(msgtprt) - 1, 0);
- // }
- // 被动模式
- static void cmd_pasv(ftp_mbox_t *msgbox)
- {
- static char reply_msg[64] = {0};
- INT32S stor = strlen(reply_msg);
- if (0 == stor) // 未初始化信息
- {
- sprintf(reply_msg, "227 pasv ok(%d,%d,%d,%d,%d,%d)\r\n",
- 192, 168, 1, 40, (FTP_DATA_PORT >> 8), FTP_DATA_PORT & 0x00ff);
- stor = strlen(reply_msg);
- }
- send(msgbox->cmd_socket, reply_msg, stor, 0);
- }
- /**
- * @brief cmd_nlst
- * ftp 命令端口输入 nlst ,被动模式
- *
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_nlst(ftp_mbox_t *msgbox)
- {
- static const char reply_msg[] = "150 Directory listing\r\n"; // 150 打开连接
- // 1.在控制端口对 list 命令进行回复
- // 2.在数据端口发送 "total 0",这个貌似可以没有
- // 3.在数据端口发送文件列表
- // 4.关闭数据端口
- send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- msgbox->event = FTP_LIST; // 事件为列表事件
- OSMboxPost(ftp_mbox, msgbox);
- }
- /**
- * @brief cmd_list
- * ftp 命令端口输入 list , 获取当前文件列表
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_list(ftp_mbox_t *msgbox)
- {
- static const char reply_msg[] = "150 Directory listing\r\n"; // 150 打开连接
- // 1.在控制端口对 list 命令进行回复
- // 2.在数据端口发送 "total 0",这个貌似可以没有
- // 3.在数据端口发送文件列表
- // 4.关闭数据端口
- send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- msgbox->event = FTP_LIST; // 事件为列表事件
- OSMboxPost(ftp_mbox, msgbox);
- }
- /**
- * @brief cmd_size
- * ftp 命令端口输入 size , 获取当前文件列表
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_size(ftp_mbox_t *msgbox)
- {
- char acFtpBuf[128];
- uint32_t iFilesize;
- char *pcFilePath = msgbox->arg;
- char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
- FTP_PATH_GET(pcFilePath, pcPathEnd);
- if (*pcFilePath != '/') // 相对路径补全为绝对路径
- {
- pcFilePath = acFtpBuf;
- }
- if (FR_OK != f_open(&file_object, pcFilePath, FA_READ))
- {
- goto sizedone;
- }
- iFilesize = f_size(&file_object);
- f_close(&file_object);
- sizedone:
- send(msgbox->cmd_socket, acFtpBuf, strlen(acFtpBuf), 0);
- }
- /**
- * @brief cmd_retr
- * ftp 命令端口输入 retr
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_retr(ftp_mbox_t *msgbox)
- {
- static const char reply_msg[] = "108 Operation successful\r\n";
- send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
- msgbox->event = FTP_SEND_FILE_DATA;
- OSMboxPost(ftp_mbox, msgbox);
- }
- /**
- * @brief cmd_dele
- * ftp 命令端口输入 dele
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_dele(ftp_mbox_t *msgbox)
- {
- FRESULT res;
- char databuf[128];
- char *pcFilePath = msgbox->arg;
- char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
- FTP_PATH_GET(pcFilePath, pcPathEnd);
- if (*pcFilePath != '/') // 相对路径
- {
- sprintf(databuf, "%s/%s", msgbox->current_dir, pcFilePath);
- pcFilePath = databuf;
- }
- res = f_unlink(pcFilePath);
- if (FR_OK != res)
- goto deleError;
- send(msgbox->cmd_socket, msg250, sizeof(msg250) - 1, 0);
- return;
- deleError:
- send(msgbox->cmd_socket, msg450, sizeof(msg450) - 1, 0);
- return;
- }
- /**
- * @brief cmd_stor
- * ftp 命令端口输入 stor
- * @param arg 命令所跟参数
- * @return NULL
- */
- static void cmd_stor(ftp_mbox_t *msgbox)
- {
- static const char reply_msgOK[] = "125 Waiting\r\n";
- send(msgbox->cmd_socket, reply_msgOK, sizeof(reply_msgOK) - 1, 0);
- msgbox->event = FTP_RECV_FILE;
- OSMboxPost(ftp_mbox, msgbox);
- }
- static const char ftp_msg_451[] = "451 errors";
- static const char ftp_msg_226[] = "226 transfer complete\r\n";
- /* Start node to be scanned (***also used as work area***) */
- char *data_port_list_file(ftp_mbox_t *msgbox)
- {
- char *ctrl_msg = (char *)ftp_msg_226;
- char list_buf[128];
- DIR dir;
- FILINFO fno;
- if (FR_OK != f_opendir(&dir, msgbox->current_dir))
- {
- goto ScanDirDone;
- }
- for (;;)
- {
- struct FileDate *pStDate;
- struct FileTime *pStTime;
- FRESULT res = f_readdir(&dir, &fno); /* Read a directory item */
- if (res != FR_OK || fno.fname[0] == 0) /* Break on error or end of dir */
- break;
- if ((fno.fattrib & AM_DIR) && (fno.fattrib != AM_DIR)) // 不显示只读/系统/隐藏文件夹
- continue;
- pStDate = (struct FileDate *)(&fno.fdate);
- pStTime = (struct FileTime *)(&fno.ftime);
- if (fno.fdate == 0 || fno.ftime == 0) // 没有日期的文件
- NORMAL_LIST(list_buf, fno.fsize, 1, 1, 1980, fno.fname);
- else if (pStDate->Year + 1980 == 2018) // 同一年的文件
- THIS_YEAR_LIST(list_buf, fno.fsize, pStDate->Month, pStDate->Day, pStTime->Hour, pStTime->Min, fno.fname);
- else
- NORMAL_LIST(list_buf, fno.fsize, pStDate->Month, pStDate->Day, pStDate->Year + 1980, fno.fname);
- if (fno.fattrib & AM_DIR) /* It is a directory */
- list_buf[0] = 'd';
- send(g_ftp_data_socket, list_buf, strlen(list_buf), 0);
- }
- f_closedir(&dir); // 把路径关闭
- ScanDirDone:
- return ctrl_msg;
- }
- // char *data_port_recv_file(ftp_mbox_t *msgbox)
- // {
- // // static __align(4) char recv_buf[TCP_MSS]; // fatfs 写文件的时候,buf要地址对齐,否则容易出错
- // char *ctrl_msg = (char *)ftp_msg_451;
- // FIL RecvFile; /* File object */
- // FRESULT res;
- // char *pcFile = msgbox->arg;
- // char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
- // char databuf[128];
- // uint16_t sRxlen;
- // uint32_t byteswritten;
- // struct netbuf *data_netbuf;
- // int ret;
- // // vFtp_GetLegalPath(pcFile, pcPathEnd);
- // if (*pcFile != '/') // 相对路径
- // {
- // sprintf(databuf, "%s/%s", msgbox->current_dir, pcFile);
- // pcFile = databuf;
- // }
- // res = f_open(&RecvFile, pcFile, FA_CREATE_ALWAYS | FA_WRITE);
- // if (res != FR_OK)
- // {
- // Errors("cannot open/create \"%s\",error code = %d\r\n", pcFile, res);
- // goto RecvEnd;
- // }
- // ret = recv(g_ftp_data_socket, data_netbuf, sizeof(data_netbuf) - 1, 0);
- // // while (ERR_OK == recv(g_ftp_data_socket, &data_netbuf)) // 阻塞直到收到数据
- // // {
- // // do
- // // {
- // // netbuf_data(data_netbuf, (void **)&pcFile, &sRxlen); // 提取数据指针
- // // #if 1
- // // memcpy(recv_buf, pcFile, sRxlen); // 把数据拷出来,否则容易出错
- // // pcFile = recv_buf;
- // // #endif
- // // res = f_write(&RecvFile, (void *)pcFile, sRxlen, &byteswritten);
- // // printk(".");
- // // if ((byteswritten == 0) || (res != FR_OK))
- // // {
- // // f_close(&RecvFile);
- // // Errors("write file error\r\n");
- // // goto RecvEnd;
- // // }
- // // } while (netbuf_next(data_netbuf) >= 0);
- // // netbuf_delete(data_netbuf);
- // // }
- // ctrl_msg = (char *)ftp_msg_226;
- // f_close(&RecvFile);
- // RecvEnd:
- // return ctrl_msg;
- // }
- // void ftp_data_deal(void)
- // {
- // INT8U err = 0;
- // ftp_mbox_t *msgbox;
- // char *ctrl_msg;
- // while (g_ftp_data_socket != -1)
- // {
- // msgbox = (ftp_mbox_t *)OSMboxPend(ftp_mbox, 50, &err);
- // printf((char *)msgbox->event);
- // if ((err == OS_ERR_NONE) && (msgbox->arglen >= 2))
- // {
- // switch (msgbox->event) // 根据不同的操作命令进行操作
- // {
- // case FTP_LIST:
- // ctrl_msg = data_port_list_file(msgbox);
- // break;
- // // case FTP_SEND_FILE_DATA:
- // // ctrl_msg = data_port_send_file(data_port_conn, msgbox);
- // // break;
- // // case FTP_RECV_FILE:
- // // ctrl_msg = data_port_recv_file(data_port_conn, msgbox);
- // // break;
- // default:;
- // }
- // send(msgbox->cmd_socket, ctrl_msg, strlen(ctrl_msg), 0); // 控制端口反馈
- // lwip_close(g_ftp_data_socket); // 关闭链接
- // g_ftp_data_socket = -1; // 清空释放连接的内存
- // }
- // else
- // {
- // lwip_close(g_ftp_data_socket); // 关闭链接
- // g_ftp_data_socket = -1; // 清空释放连接的内存
- // }
- // }
- // }
- void ftp_server_init(void)
- {
- ftp_cmd_func cmd_type = cmd_noop;
- // 生成相关的命令二叉树
- FTP_REGISTER_COMMAND(user);
- FTP_REGISTER_COMMAND(pass);
- FTP_REGISTER_COMMAND(syst);
- FTP_REGISTER_COMMAND(pwd);
- FTP_REGISTER_COMMAND(cwd);
- // FTP_REGISTER_COMMAND(feat);
- FTP_REGISTER_COMMAND(pasv);
- FTP_REGISTER_COMMAND(nlst);
- FTP_REGISTER_COMMAND(list);
- FTP_REGISTER_COMMAND(noop);
- FTP_REGISTER_COMMAND(type);
- FTP_REGISTER_COMMAND(size);
- FTP_REGISTER_COMMAND(retr);
- FTP_REGISTER_COMMAND(dele);
- FTP_REGISTER_COMMAND(stor);
- }
|