ftpd.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. #include "ftpd.h"
  2. #include "avltree.h"
  3. #include "bsp_fatfs.h"
  4. #include "ff.h"
  5. #include "fly_param.h"
  6. #include "ftp_server.h"
  7. #include "os_cpu.h"
  8. #include "sockets.h"
  9. #include "ucos_ii.h"
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. static struct avl_root ftp_root = {.avl_node = NULL}; // 命令匹配的平衡二叉树树根
  13. /* Private variables ------------------------------------------------------------*/
  14. static const char normal_format[] = "-rw-rw-rw- 1 user ftp %11ld %s %02i %5i %s\r\n";
  15. static const char this_year_format[] = "-rw-rw-rw- 1 user ftp %11ld %s %02i %02i:%02i %s\r\n";
  16. static const char *month_list[] = { // 月份从 1 到 12 ,0 填充 NULL
  17. NULL,
  18. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  19. "Jul", "Aug", "Sep", "Oct", "Nov", "Dez"};
  20. // ftp 命令树构建
  21. #define FTP_REGISTER_COMMAND(CMD) \
  22. do \
  23. { \
  24. static ftp_cmd_t CmdBuf; \
  25. CmdBuf.index = FTP_STR2ID(#CMD); \
  26. CmdBuf.func = cmd_##CMD; \
  27. ftp_insert_command(&CmdBuf); \
  28. } while (0)
  29. // ftp 文件列表格式
  30. #define NORMAL_LIST(listbuf, filesize, month, day, year, filename) \
  31. sprintf(listbuf, normal_format, (filesize), month_list[(month)], (day), (year), (filename))
  32. #define THIS_YEAR_LIST(listbuf, filesize, month, day, hour, min, filename) \
  33. sprintf(listbuf, this_year_format, (filesize), month_list[(month)], (day), (hour), (min), (filename))
  34. // ftp 格式一般为 xxxx /dirx/diry/\r\n ,去掉 /\r\n 提取可用路径
  35. #define FTP_PATH_GET(path, pathend) \
  36. do \
  37. { \
  38. while (*path == ' ') \
  39. ++path; \
  40. if (*pathend == '\n') \
  41. *pathend-- = 0; \
  42. if (*pathend == '\r') \
  43. *pathend-- = 0; \
  44. if (*pathend == '/') \
  45. *pathend = 0; \
  46. } while (0)
  47. /**
  48. * @brief ftp_insert_command
  49. * 命令树插入
  50. * @param pCmd 命令控制块
  51. * @return 成功返回 0
  52. */
  53. int ftp_insert_command(ftp_cmd_t *p_cmd)
  54. {
  55. struct avl_node **tmp = &ftp_root.avl_node;
  56. struct avl_node *parent = NULL;
  57. while (*tmp)
  58. {
  59. ftp_cmd_t *this = container_of(*tmp, ftp_cmd_t, cmd_node);
  60. parent = *tmp;
  61. if (p_cmd->index < this->index)
  62. tmp = &((*tmp)->avl_left);
  63. else if (p_cmd->index > this->index)
  64. tmp = &((*tmp)->avl_right);
  65. else
  66. return 1;
  67. }
  68. avl_insert(&ftp_root, &p_cmd->cmd_node, parent, tmp);
  69. return 0;
  70. }
  71. /**
  72. * @brief ftp_search_command
  73. * 命令树查找,根据 Index 号找到对应的控制块
  74. * @param index 命令号
  75. * @return 成功 Index 号对应的控制块
  76. */
  77. ftp_cmd_t *ftp_search_command(int i_ctrl_cmd)
  78. {
  79. struct avl_node *node = ftp_root.avl_node;
  80. while (node)
  81. {
  82. ftp_cmd_t *p_cmd = container_of(node, ftp_cmd_t, cmd_node);
  83. if (i_ctrl_cmd < p_cmd->index)
  84. node = node->avl_left;
  85. else if (i_ctrl_cmd > p_cmd->index)
  86. node = node->avl_right;
  87. else
  88. return p_cmd;
  89. }
  90. return NULL;
  91. }
  92. // 登录系统用户名
  93. static void cmd_user(ftp_mbox_t *msgbox)
  94. {
  95. if (strcasecmp(msgbox->arg, "root") == 0)
  96. {
  97. send(msgbox->cmd_socket, msg331, sizeof(msg331) - 1, 0);
  98. }
  99. else
  100. {
  101. send(msgbox->cmd_socket, msg331, sizeof(msg331) - 1, 0);
  102. }
  103. }
  104. // 登录系统密码
  105. static void cmd_pass(ftp_mbox_t *msgbox)
  106. {
  107. // printf(msgbox->arg);
  108. // if (strcasecmp(msgbox->arg, "ASASAS") == 0)
  109. // {
  110. send(msgbox->cmd_socket, msg230, sizeof(msg230) - 1, 0);
  111. // }
  112. // else
  113. // {
  114. // send(msgbox->cmd_socket, msg503, sizeof(msg503) - 1, 0);
  115. // }
  116. }
  117. // 操作系统类型
  118. static void cmd_syst(ftp_mbox_t *msgbox)
  119. {
  120. static const char reply_msg[] = "215 UNIX Type: L8\r\n"; // 215 系统类型回复
  121. send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  122. }
  123. // 显示当前工作目录
  124. static void cmd_pwd(ftp_mbox_t *msgbox)
  125. {
  126. #if 1
  127. char reply_msg[128]; // 257 路径名建立
  128. // sprintf(reply_msg, "257 \"%s/\"\r\n", msgbox->current_dir);
  129. sprintf(reply_msg, "257 \"%s/\"\r\n", "LINUX");
  130. #else
  131. static const char reply_msg[] = "257 \"/\"\r\n";
  132. #endif
  133. send(msgbox->cmd_socket, reply_msg, strlen(reply_msg), 0);
  134. }
  135. /**
  136. * @brief cmd_noop
  137. * ftp 命令端口输入 noop
  138. * @param arg 命令所跟参数
  139. * @return NULL
  140. */
  141. static void cmd_noop(ftp_mbox_t *msgbox)
  142. {
  143. static const char reply_msg[] = "200 Operation successful\r\n";
  144. send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  145. }
  146. // 路径名建立
  147. static void cmd_cwd(ftp_mbox_t *msgbox)
  148. {
  149. static const char reply_msg[] = "250 Operation successful\r\n";
  150. DIR fsdir;
  151. char *pcFilePath = msgbox->arg;
  152. char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
  153. FTP_PATH_GET(pcFilePath, pcPathEnd);
  154. if (FR_OK != f_opendir(&fsdir, pcFilePath))
  155. {
  156. goto cmddone;
  157. }
  158. f_closedir(&fsdir);
  159. if (pcPathEnd != pcFilePath)
  160. memcpy(msgbox->current_dir, pcFilePath, pcPathEnd - pcFilePath);
  161. msgbox->current_dir[pcPathEnd - pcFilePath] = 0;
  162. cmddone:
  163. send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  164. }
  165. // static void cmd_feat(ftp_mbox_t *msgbox)
  166. // {
  167. // static const char reply_msg[] = "211-feature:\r\n";
  168. // static const char msgtprt[] = "EPRT\r\n";
  169. // send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  170. // send(msgbox->cmd_socket, msgtprt, sizeof(msgtprt) - 1, 0);
  171. // }
  172. // 被动模式
  173. static void cmd_pasv(ftp_mbox_t *msgbox)
  174. {
  175. static char reply_msg[64] = {0};
  176. INT32S stor = strlen(reply_msg);
  177. if (0 == stor) // 未初始化信息
  178. {
  179. sprintf(reply_msg, "227 pasv ok(%d,%d,%d,%d,%d,%d)\r\n",
  180. 192, 168, 1, 40, (FTP_DATA_PORT >> 8), FTP_DATA_PORT & 0x00ff);
  181. stor = strlen(reply_msg);
  182. }
  183. send(msgbox->cmd_socket, reply_msg, stor, 0);
  184. }
  185. /**
  186. * @brief cmd_nlst
  187. * ftp 命令端口输入 nlst ,被动模式
  188. *
  189. * @param arg 命令所跟参数
  190. * @return NULL
  191. */
  192. static void cmd_nlst(ftp_mbox_t *msgbox)
  193. {
  194. static const char reply_msg[] = "150 Directory listing\r\n"; // 150 打开连接
  195. // 1.在控制端口对 list 命令进行回复
  196. // 2.在数据端口发送 "total 0",这个貌似可以没有
  197. // 3.在数据端口发送文件列表
  198. // 4.关闭数据端口
  199. send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  200. msgbox->event = FTP_LIST; // 事件为列表事件
  201. OSMboxPost(ftp_mbox, msgbox);
  202. }
  203. /**
  204. * @brief cmd_list
  205. * ftp 命令端口输入 list , 获取当前文件列表
  206. * @param arg 命令所跟参数
  207. * @return NULL
  208. */
  209. static void cmd_list(ftp_mbox_t *msgbox)
  210. {
  211. static const char reply_msg[] = "150 Directory listing\r\n"; // 150 打开连接
  212. // 1.在控制端口对 list 命令进行回复
  213. // 2.在数据端口发送 "total 0",这个貌似可以没有
  214. // 3.在数据端口发送文件列表
  215. // 4.关闭数据端口
  216. send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  217. msgbox->event = FTP_LIST; // 事件为列表事件
  218. OSMboxPost(ftp_mbox, msgbox);
  219. }
  220. /**
  221. * @brief cmd_size
  222. * ftp 命令端口输入 size , 获取当前文件列表
  223. * @param arg 命令所跟参数
  224. * @return NULL
  225. */
  226. static void cmd_size(ftp_mbox_t *msgbox)
  227. {
  228. char acFtpBuf[128];
  229. uint32_t iFilesize;
  230. char *pcFilePath = msgbox->arg;
  231. char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
  232. FTP_PATH_GET(pcFilePath, pcPathEnd);
  233. if (*pcFilePath != '/') // 相对路径补全为绝对路径
  234. {
  235. pcFilePath = acFtpBuf;
  236. }
  237. if (FR_OK != f_open(&file_object, pcFilePath, FA_READ))
  238. {
  239. goto sizedone;
  240. }
  241. iFilesize = f_size(&file_object);
  242. f_close(&file_object);
  243. sizedone:
  244. send(msgbox->cmd_socket, acFtpBuf, strlen(acFtpBuf), 0);
  245. }
  246. /**
  247. * @brief cmd_retr
  248. * ftp 命令端口输入 retr
  249. * @param arg 命令所跟参数
  250. * @return NULL
  251. */
  252. static void cmd_retr(ftp_mbox_t *msgbox)
  253. {
  254. static const char reply_msg[] = "108 Operation successful\r\n";
  255. send(msgbox->cmd_socket, reply_msg, sizeof(reply_msg) - 1, 0);
  256. msgbox->event = FTP_SEND_FILE_DATA;
  257. OSMboxPost(ftp_mbox, msgbox);
  258. }
  259. /**
  260. * @brief cmd_dele
  261. * ftp 命令端口输入 dele
  262. * @param arg 命令所跟参数
  263. * @return NULL
  264. */
  265. static void cmd_dele(ftp_mbox_t *msgbox)
  266. {
  267. FRESULT res;
  268. char databuf[128];
  269. char *pcFilePath = msgbox->arg;
  270. char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
  271. FTP_PATH_GET(pcFilePath, pcPathEnd);
  272. if (*pcFilePath != '/') // 相对路径
  273. {
  274. sprintf(databuf, "%s/%s", msgbox->current_dir, pcFilePath);
  275. pcFilePath = databuf;
  276. }
  277. res = f_unlink(pcFilePath);
  278. if (FR_OK != res)
  279. goto deleError;
  280. send(msgbox->cmd_socket, msg250, sizeof(msg250) - 1, 0);
  281. return;
  282. deleError:
  283. send(msgbox->cmd_socket, msg450, sizeof(msg450) - 1, 0);
  284. return;
  285. }
  286. /**
  287. * @brief cmd_stor
  288. * ftp 命令端口输入 stor
  289. * @param arg 命令所跟参数
  290. * @return NULL
  291. */
  292. static void cmd_stor(ftp_mbox_t *msgbox)
  293. {
  294. static const char reply_msgOK[] = "125 Waiting\r\n";
  295. send(msgbox->cmd_socket, reply_msgOK, sizeof(reply_msgOK) - 1, 0);
  296. msgbox->event = FTP_RECV_FILE;
  297. OSMboxPost(ftp_mbox, msgbox);
  298. }
  299. static const char ftp_msg_451[] = "451 errors";
  300. static const char ftp_msg_226[] = "226 transfer complete\r\n";
  301. /* Start node to be scanned (***also used as work area***) */
  302. char *data_port_list_file(ftp_mbox_t *msgbox)
  303. {
  304. char *ctrl_msg = (char *)ftp_msg_226;
  305. char list_buf[128];
  306. DIR dir;
  307. FILINFO fno;
  308. if (FR_OK != f_opendir(&dir, msgbox->current_dir))
  309. {
  310. goto ScanDirDone;
  311. }
  312. for (;;)
  313. {
  314. struct FileDate *pStDate;
  315. struct FileTime *pStTime;
  316. FRESULT res = f_readdir(&dir, &fno); /* Read a directory item */
  317. if (res != FR_OK || fno.fname[0] == 0) /* Break on error or end of dir */
  318. break;
  319. if ((fno.fattrib & AM_DIR) && (fno.fattrib != AM_DIR)) // 不显示只读/系统/隐藏文件夹
  320. continue;
  321. pStDate = (struct FileDate *)(&fno.fdate);
  322. pStTime = (struct FileTime *)(&fno.ftime);
  323. if (fno.fdate == 0 || fno.ftime == 0) // 没有日期的文件
  324. NORMAL_LIST(list_buf, fno.fsize, 1, 1, 1980, fno.fname);
  325. else if (pStDate->Year + 1980 == 2018) // 同一年的文件
  326. THIS_YEAR_LIST(list_buf, fno.fsize, pStDate->Month, pStDate->Day, pStTime->Hour, pStTime->Min, fno.fname);
  327. else
  328. NORMAL_LIST(list_buf, fno.fsize, pStDate->Month, pStDate->Day, pStDate->Year + 1980, fno.fname);
  329. if (fno.fattrib & AM_DIR) /* It is a directory */
  330. list_buf[0] = 'd';
  331. send(g_ftp_data_socket, list_buf, strlen(list_buf), 0);
  332. }
  333. f_closedir(&dir); // 把路径关闭
  334. ScanDirDone:
  335. return ctrl_msg;
  336. }
  337. // char *data_port_recv_file(ftp_mbox_t *msgbox)
  338. // {
  339. // // static __align(4) char recv_buf[TCP_MSS]; // fatfs 写文件的时候,buf要地址对齐,否则容易出错
  340. // char *ctrl_msg = (char *)ftp_msg_451;
  341. // FIL RecvFile; /* File object */
  342. // FRESULT res;
  343. // char *pcFile = msgbox->arg;
  344. // char *pcPathEnd = msgbox->arg + msgbox->arglen - 1;
  345. // char databuf[128];
  346. // uint16_t sRxlen;
  347. // uint32_t byteswritten;
  348. // struct netbuf *data_netbuf;
  349. // int ret;
  350. // // vFtp_GetLegalPath(pcFile, pcPathEnd);
  351. // if (*pcFile != '/') // 相对路径
  352. // {
  353. // sprintf(databuf, "%s/%s", msgbox->current_dir, pcFile);
  354. // pcFile = databuf;
  355. // }
  356. // res = f_open(&RecvFile, pcFile, FA_CREATE_ALWAYS | FA_WRITE);
  357. // if (res != FR_OK)
  358. // {
  359. // Errors("cannot open/create \"%s\",error code = %d\r\n", pcFile, res);
  360. // goto RecvEnd;
  361. // }
  362. // ret = recv(g_ftp_data_socket, data_netbuf, sizeof(data_netbuf) - 1, 0);
  363. // // while (ERR_OK == recv(g_ftp_data_socket, &data_netbuf)) // 阻塞直到收到数据
  364. // // {
  365. // // do
  366. // // {
  367. // // netbuf_data(data_netbuf, (void **)&pcFile, &sRxlen); // 提取数据指针
  368. // // #if 1
  369. // // memcpy(recv_buf, pcFile, sRxlen); // 把数据拷出来,否则容易出错
  370. // // pcFile = recv_buf;
  371. // // #endif
  372. // // res = f_write(&RecvFile, (void *)pcFile, sRxlen, &byteswritten);
  373. // // printk(".");
  374. // // if ((byteswritten == 0) || (res != FR_OK))
  375. // // {
  376. // // f_close(&RecvFile);
  377. // // Errors("write file error\r\n");
  378. // // goto RecvEnd;
  379. // // }
  380. // // } while (netbuf_next(data_netbuf) >= 0);
  381. // // netbuf_delete(data_netbuf);
  382. // // }
  383. // ctrl_msg = (char *)ftp_msg_226;
  384. // f_close(&RecvFile);
  385. // RecvEnd:
  386. // return ctrl_msg;
  387. // }
  388. // void ftp_data_deal(void)
  389. // {
  390. // INT8U err = 0;
  391. // ftp_mbox_t *msgbox;
  392. // char *ctrl_msg;
  393. // while (g_ftp_data_socket != -1)
  394. // {
  395. // msgbox = (ftp_mbox_t *)OSMboxPend(ftp_mbox, 50, &err);
  396. // printf((char *)msgbox->event);
  397. // if ((err == OS_ERR_NONE) && (msgbox->arglen >= 2))
  398. // {
  399. // switch (msgbox->event) // 根据不同的操作命令进行操作
  400. // {
  401. // case FTP_LIST:
  402. // ctrl_msg = data_port_list_file(msgbox);
  403. // break;
  404. // // case FTP_SEND_FILE_DATA:
  405. // // ctrl_msg = data_port_send_file(data_port_conn, msgbox);
  406. // // break;
  407. // // case FTP_RECV_FILE:
  408. // // ctrl_msg = data_port_recv_file(data_port_conn, msgbox);
  409. // // break;
  410. // default:;
  411. // }
  412. // send(msgbox->cmd_socket, ctrl_msg, strlen(ctrl_msg), 0); // 控制端口反馈
  413. // lwip_close(g_ftp_data_socket); // 关闭链接
  414. // g_ftp_data_socket = -1; // 清空释放连接的内存
  415. // }
  416. // else
  417. // {
  418. // lwip_close(g_ftp_data_socket); // 关闭链接
  419. // g_ftp_data_socket = -1; // 清空释放连接的内存
  420. // }
  421. // }
  422. // }
  423. void ftp_server_init(void)
  424. {
  425. ftp_cmd_func cmd_type = cmd_noop;
  426. // 生成相关的命令二叉树
  427. FTP_REGISTER_COMMAND(user);
  428. FTP_REGISTER_COMMAND(pass);
  429. FTP_REGISTER_COMMAND(syst);
  430. FTP_REGISTER_COMMAND(pwd);
  431. FTP_REGISTER_COMMAND(cwd);
  432. // FTP_REGISTER_COMMAND(feat);
  433. FTP_REGISTER_COMMAND(pasv);
  434. FTP_REGISTER_COMMAND(nlst);
  435. FTP_REGISTER_COMMAND(list);
  436. FTP_REGISTER_COMMAND(noop);
  437. FTP_REGISTER_COMMAND(type);
  438. FTP_REGISTER_COMMAND(size);
  439. FTP_REGISTER_COMMAND(retr);
  440. FTP_REGISTER_COMMAND(dele);
  441. FTP_REGISTER_COMMAND(stor);
  442. }