ftpd.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <rtthread.h>
  4. #include <dfs_posix.h>
  5. #include <lwip/sockets.h>
  6. #include <time.h>
  7. #define FTP_PORT 21
  8. #define FTP_SRV_ROOT "/"
  9. #define FTP_MAX_CONNECTION 2
  10. #define FTP_USER "rtt"
  11. #define FTP_PASSWORD "demo"
  12. #define FTP_WELCOME_MSG "220 welcome on RT-Thread FTP server.\r\n"
  13. #define FTP_BUFFER_SIZE 1024
  14. #define INET_ADDRSTRLEN 16
  15. struct ftp_session
  16. {
  17. rt_bool_t is_anonymous;
  18. int sockfd;
  19. struct sockaddr_in remote;
  20. struct sockaddr_in server;
  21. char serveraddr[INET_ADDRSTRLEN];
  22. /* pasv data */
  23. int pasv_listen_sockfd;
  24. char pasv_active;
  25. int pasv_sockfd;
  26. unsigned short pasv_port;
  27. size_t offset;
  28. /* current directory */
  29. char currentdir[256];
  30. struct ftp_session* next;
  31. };
  32. static struct ftp_session* session_list = NULL;
  33. int ftp_process_request(struct ftp_session* session, char * buf);
  34. int ftp_get_filesize(char *filename);
  35. struct ftp_session* ftp_new_session()
  36. {
  37. struct ftp_session* session;
  38. session = (struct ftp_session*)rt_malloc(sizeof(struct ftp_session));
  39. rt_memset((void *)session, 0, sizeof(struct ftp_session));
  40. session->next = session_list;
  41. session_list = session;
  42. return session;
  43. }
  44. void ftp_close_session(struct ftp_session* session)
  45. {
  46. struct ftp_session* list;
  47. if (session_list == session)
  48. {
  49. session_list = session_list->next;
  50. session->next = NULL;
  51. }
  52. else
  53. {
  54. list = session_list;
  55. while (list->next != session) list = list->next;
  56. list->next = session->next;
  57. session->next = NULL;
  58. }
  59. rt_free(session);
  60. }
  61. static int open_data_connection(struct ftp_session* session)
  62. {
  63. socklen_t len = sizeof(struct sockaddr);
  64. struct sockaddr_in sin;
  65. #if 0
  66. /* Previous PORT command from client */
  67. if (ctrl->data_address[0]) {
  68. ctrl->data_sd = socket(AF_INET, SOCK_STREAM, 0);
  69. if (-1 == ctrl->data_sd) {
  70. printf("Failed creating data socket");
  71. return -1;
  72. }
  73. memset(&sin, 0, sizeof(sin));
  74. sin.sin_family = AF_INET;
  75. sin.sin_port = htons(ctrl->data_port);
  76. inet_aton(ctrl->data_address, &(sin.sin_addr));
  77. if (connect(ctrl->data_sd, (struct sockaddr *)&sin, len) == -1) {
  78. printf("Failed connecting data socket to client");
  79. close(ctrl->data_sd);
  80. ctrl->data_sd = -1;
  81. return -1;
  82. }
  83. DBG("Connected successfully to client's previously requested address:PORT %s:%d", ctrl->data_address, ctrl->data_port);
  84. return 0;
  85. }
  86. #endif
  87. /* Previous PASV command, accept connect from client */
  88. if (session->pasv_listen_sockfd > 0) {
  89. char client_ip[100];
  90. session->pasv_sockfd = accept(session->pasv_listen_sockfd, (struct sockaddr *)&sin, &len);
  91. if (-1 == session->pasv_sockfd) {
  92. printf("Failed accepting connection from client");
  93. return -1;
  94. }
  95. len = sizeof(struct sockaddr);
  96. if (-1 == getpeername(session->pasv_sockfd, (struct sockaddr *)&sin, &len)) {
  97. printf("Cannot determine client address");
  98. closesocket(session->pasv_sockfd);
  99. session->pasv_sockfd = -1;
  100. return -1;
  101. }
  102. printf("Client PASV data connection from %s\n", inet_ntoa(sin.sin_addr));
  103. }
  104. return 0;
  105. }
  106. static void close_data_connection(struct ftp_session* session)
  107. {
  108. /* PASV server listening socket */
  109. if (session->pasv_listen_sockfd > 0) {
  110. closesocket(session->pasv_listen_sockfd);
  111. session->pasv_listen_sockfd = -1;
  112. }
  113. /* PASV client socket */
  114. if (session->pasv_sockfd > 0) {
  115. closesocket(session->pasv_sockfd);
  116. session->pasv_sockfd = -1;
  117. }
  118. #if 0
  119. /* PORT */
  120. if (ctrl->data_address[0]) {
  121. ctrl->data_address[0] = 0;
  122. ctrl->data_port = 0;
  123. }
  124. #endif
  125. }
  126. int ftp_get_filesize(char * filename)
  127. {
  128. int pos;
  129. int end;
  130. int fd;
  131. fd = open(filename, O_RDONLY, 0);
  132. if (fd < 0) return -1;
  133. pos = lseek(fd, 0, SEEK_CUR);
  134. end = lseek(fd, 0, SEEK_END);
  135. lseek (fd, pos, SEEK_SET);
  136. close(fd);
  137. return end;
  138. }
  139. rt_bool_t is_absolute_path(char* path)
  140. {
  141. #ifdef _WIN32
  142. if (path[0] == '\\' ||
  143. (path[1] == ':' && path[2] == '\\'))
  144. return RT_TRUE;
  145. #else
  146. if (path[0] == '/') return RT_TRUE;
  147. #endif
  148. return RT_FALSE;
  149. }
  150. int build_full_path(struct ftp_session* session, char* path, char* new_path, size_t size)
  151. {
  152. if (is_absolute_path(path) == RT_TRUE)
  153. strcpy(new_path, path);
  154. else
  155. {
  156. rt_sprintf(new_path, "%s/%s", session->currentdir, path);
  157. }
  158. return 0;
  159. }
  160. void ftpd_thread_entry(void* parameter)
  161. {
  162. int numbytes;
  163. int sockfd, maxfdp1;
  164. struct sockaddr_in local;
  165. fd_set readfds, tmpfds;
  166. struct ftp_session* session;
  167. rt_uint32_t addr_len = sizeof(struct sockaddr);
  168. char * buffer = (char *) rt_malloc(FTP_BUFFER_SIZE);
  169. local.sin_port=htons(FTP_PORT);
  170. local.sin_family=PF_INET;
  171. local.sin_addr.s_addr=INADDR_ANY;
  172. FD_ZERO(&readfds);
  173. FD_ZERO(&tmpfds);
  174. sockfd=socket(AF_INET, SOCK_STREAM, 0);
  175. if(sockfd < 0)
  176. {
  177. rt_kprintf("create socket failed\n");
  178. return ;
  179. }
  180. bind(sockfd, (struct sockaddr *)&local, addr_len);
  181. listen(sockfd, FTP_MAX_CONNECTION);
  182. FD_SET(sockfd, &readfds);
  183. for(;;)
  184. {
  185. /* get maximum fd */
  186. maxfdp1 = sockfd + 1;
  187. session = session_list;
  188. while (session != RT_NULL)
  189. {
  190. if (maxfdp1 < session->sockfd + 1)
  191. maxfdp1 = session->sockfd + 1;
  192. FD_SET(session->sockfd, &readfds);
  193. session = session->next;
  194. }
  195. tmpfds=readfds;
  196. if (select(maxfdp1, &tmpfds, 0, 0, 0) == 0) continue;
  197. if(FD_ISSET(sockfd, &tmpfds))
  198. {
  199. int com_socket;
  200. struct sockaddr_in remote;
  201. com_socket = accept(sockfd, (struct sockaddr*)&remote, &addr_len);
  202. if(com_socket == -1)
  203. {
  204. rt_kprintf("Error on accept()\nContinuing...\n");
  205. continue;
  206. }
  207. else
  208. {
  209. rt_kprintf("Got connection from %s\n", inet_ntoa(remote.sin_addr));
  210. send(com_socket, FTP_WELCOME_MSG, strlen(FTP_WELCOME_MSG), 0);
  211. FD_SET(com_socket, &readfds);
  212. /* new session */
  213. session = ftp_new_session();
  214. if (session != NULL)
  215. {
  216. if (-1 == getsockname(com_socket, (struct sockaddr *)&session->server, &addr_len)) {
  217. printf("Cannot determine our address, need it if client should connect to us\n");
  218. }
  219. ipaddr_ntoa_r(&(session->server.sin_addr), session->serveraddr, sizeof(session->serveraddr));
  220. strcpy(session->currentdir, FTP_SRV_ROOT);
  221. session->sockfd = com_socket;
  222. session->remote = remote;
  223. }
  224. }
  225. }
  226. {
  227. struct ftp_session* next;
  228. session = session_list;
  229. while (session != NULL)
  230. {
  231. next = session->next;
  232. if (FD_ISSET(session->sockfd, &tmpfds))
  233. {
  234. numbytes=recv(session->sockfd, buffer, FTP_BUFFER_SIZE, 0);
  235. if(numbytes==0 || numbytes==-1)
  236. {
  237. rt_kprintf("Client %s disconnected\n", inet_ntoa(session->remote.sin_addr));
  238. FD_CLR(session->sockfd, &readfds);
  239. closesocket(session->sockfd);
  240. session->sockfd = -1;
  241. ftp_close_session(session);
  242. }
  243. else
  244. {
  245. buffer[numbytes]=0;
  246. if(ftp_process_request(session, buffer)==-1)
  247. {
  248. rt_kprintf("Client %s disconnected\r\n", inet_ntoa(session->remote.sin_addr));
  249. closesocket(session->sockfd);
  250. session->sockfd = -1;
  251. ftp_close_session(session);
  252. }
  253. }
  254. }
  255. session = next;
  256. }
  257. }
  258. }
  259. // rt_free(buffer);
  260. }
  261. int do_list(char* directory, int sockfd)
  262. {
  263. DIR* dirp;
  264. struct dirent* entry;
  265. char line_buffer[256], line_length;
  266. #ifdef _WIN32
  267. struct _stat s;
  268. #else
  269. struct stat s;
  270. #endif
  271. dirp = opendir(directory);
  272. if (dirp == NULL)
  273. {
  274. line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
  275. send(sockfd, line_buffer, line_length, 0);
  276. return -1;
  277. }
  278. while (1)
  279. {
  280. entry = readdir(dirp);
  281. if (entry == NULL) break;
  282. rt_sprintf(line_buffer, "%s/%s", directory, entry->d_name);
  283. #ifdef _WIN32
  284. if (_stat(line_buffer, &s) ==0)
  285. #else
  286. if (stat(line_buffer, &s) == 0)
  287. #endif
  288. {
  289. if (s.st_mode & S_IFDIR)
  290. line_length = rt_sprintf(line_buffer, "drw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", 0, entry->d_name);
  291. else
  292. line_length = rt_sprintf(line_buffer, "-rw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", s.st_size, entry->d_name);
  293. send(sockfd, line_buffer, line_length, 0);
  294. }
  295. else
  296. {
  297. rt_kprintf("Get directory entry error\n");
  298. break;
  299. }
  300. }
  301. closedir(dirp);
  302. return 0;
  303. }
  304. int do_simple_list(char* directory, int sockfd)
  305. {
  306. DIR* dirp;
  307. struct dirent* entry;
  308. char line_buffer[256], line_length;
  309. dirp = opendir(directory);
  310. if (dirp == NULL)
  311. {
  312. line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
  313. send(sockfd, line_buffer, line_length, 0);
  314. return -1;
  315. }
  316. while (1)
  317. {
  318. entry = readdir(dirp);
  319. if (entry == NULL) break;
  320. line_length = rt_sprintf(line_buffer, "%s\r\n", entry->d_name);
  321. send(sockfd, line_buffer, line_length, 0);
  322. }
  323. closedir(dirp);
  324. return 0;
  325. }
  326. int str_begin_with(char* src, char* match)
  327. {
  328. while (*match)
  329. {
  330. /* check source */
  331. if (*src == 0) return -1;
  332. if (*match != *src) return -1;
  333. match ++; src ++;
  334. }
  335. return 0;
  336. }
  337. int ftp_process_request(struct ftp_session* session, char *buf)
  338. {
  339. int fd;
  340. struct timeval tv;
  341. fd_set readfds;
  342. char filename[256];
  343. int numbytes;
  344. char *sbuf;
  345. char *parameter_ptr, *ptr;
  346. rt_uint32_t addr_len = sizeof(struct sockaddr_in);
  347. struct sockaddr_in local, pasvremote;
  348. sbuf =(char *)rt_malloc(FTP_BUFFER_SIZE);
  349. tv.tv_sec=3, tv.tv_usec=0;
  350. local.sin_family=PF_INET;
  351. local.sin_addr.s_addr=INADDR_ANY;
  352. /* remove \r\n */
  353. ptr = buf;
  354. while (*ptr)
  355. {
  356. if (*ptr == '\r' || *ptr == '\n') *ptr = 0;
  357. ptr ++;
  358. }
  359. /* get request parameter */
  360. parameter_ptr = strchr(buf, ' '); if (parameter_ptr != NULL) parameter_ptr ++;
  361. // debug:
  362. rt_kprintf("%s requested: \"%s\"\n", inet_ntoa(session->remote.sin_addr), buf);
  363. //
  364. //-----------------------
  365. if(str_begin_with(buf, "USER")==0)
  366. {
  367. rt_kprintf("%s sent login \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
  368. // login correct
  369. if(strcmp(parameter_ptr, "anonymous") == 0)
  370. {
  371. session->is_anonymous = RT_TRUE;
  372. rt_sprintf(sbuf, "331 Anonymous login OK send e-mail address for password.\r\n", parameter_ptr);
  373. send(session->sockfd, sbuf, strlen(sbuf), 0);
  374. }
  375. else if (strcmp(parameter_ptr, FTP_USER) == 0)
  376. {
  377. session->is_anonymous = RT_FALSE;
  378. rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr);
  379. send(session->sockfd, sbuf, strlen(sbuf), 0);
  380. }
  381. else
  382. {
  383. // incorrect login
  384. rt_sprintf(sbuf, "530 Login incorrect. Bye.\r\n");
  385. send(session->sockfd, sbuf, strlen(sbuf), 0);
  386. rt_free(sbuf);
  387. return -1;
  388. }
  389. return 0;
  390. }
  391. else if(str_begin_with(buf, "PASS")==0)
  392. {
  393. rt_kprintf("%s sent password \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
  394. if (strcmp(parameter_ptr, FTP_PASSWORD)==0 ||
  395. session->is_anonymous == RT_TRUE)
  396. {
  397. // password correct
  398. rt_sprintf(sbuf, "230 User logged in.\r\n");
  399. send(session->sockfd, sbuf, strlen(sbuf), 0);
  400. rt_free(sbuf);
  401. return 0;
  402. }
  403. // incorrect password
  404. rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n");
  405. send(session->sockfd, sbuf, strlen(sbuf), 0);
  406. rt_free(sbuf);
  407. return -1;
  408. }
  409. else if(str_begin_with(buf, "LIST")==0 )
  410. {
  411. memset(sbuf,0,FTP_BUFFER_SIZE);
  412. open_data_connection(session);
  413. rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
  414. send(session->sockfd, sbuf, strlen(sbuf), 0);
  415. do_list(session->currentdir, session->pasv_sockfd);
  416. close_data_connection(session);
  417. session->pasv_active = 0;
  418. rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
  419. send(session->sockfd, sbuf, strlen(sbuf), 0);
  420. }
  421. else if(str_begin_with(buf, "NLST")==0 )
  422. {
  423. memset(sbuf, 0, FTP_BUFFER_SIZE);
  424. rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
  425. send(session->sockfd, sbuf, strlen(sbuf), 0);
  426. open_data_connection(session);
  427. do_simple_list(session->currentdir, session->pasv_sockfd);
  428. close_data_connection(session);
  429. session->pasv_active = 0;
  430. rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
  431. send(session->sockfd, sbuf, strlen(sbuf), 0);
  432. }
  433. else if(str_begin_with(buf, "PWD")==0 || str_begin_with(buf, "XPWD")==0)
  434. {
  435. rt_sprintf(sbuf, "257 \"%s\" is current directory.\r\n", session->currentdir);
  436. send(session->sockfd, sbuf, strlen(sbuf), 0);
  437. }
  438. else if(str_begin_with(buf, "TYPE")==0)
  439. {
  440. // Ignore it
  441. if(strcmp(parameter_ptr, "I")==0)
  442. {
  443. rt_sprintf(sbuf, "200 Type set to binary.\r\n");
  444. send(session->sockfd, sbuf, strlen(sbuf), 0);
  445. }
  446. else
  447. {
  448. rt_sprintf(sbuf, "200 Type set to ascii.\r\n");
  449. send(session->sockfd, sbuf, strlen(sbuf), 0);
  450. }
  451. }
  452. else if(str_begin_with(buf, "PASV")==0)
  453. {
  454. int dig1, dig2;
  455. //int sockfd;
  456. int optval=1;
  457. int port;
  458. struct sockaddr_in data;
  459. socklen_t len = sizeof(struct sockaddr);
  460. char *msg, *p;
  461. if (session->pasv_sockfd > 0) {
  462. closesocket(session->pasv_sockfd);
  463. session->pasv_sockfd = -1;
  464. }
  465. if (session->pasv_listen_sockfd > 0)
  466. closesocket(session->pasv_listen_sockfd);
  467. session->pasv_port = 10000;
  468. session->pasv_active = 1;
  469. local.sin_port=htons(session->pasv_port);
  470. local.sin_addr.s_addr=INADDR_ANY;
  471. dig1 = (int)(session->pasv_port/256);
  472. dig2 = session->pasv_port % 256;
  473. FD_ZERO(&readfds);
  474. if((session->pasv_listen_sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1)
  475. {
  476. rt_sprintf(sbuf, "425 Can't open data connection0.\r\n");
  477. send(session->sockfd, sbuf, strlen(sbuf), 0);
  478. goto err1;
  479. }
  480. if(setsockopt(session->pasv_listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1)
  481. {
  482. rt_sprintf(sbuf, "425 Can't open data connection1.\r\n");
  483. send(session->sockfd, sbuf, strlen(sbuf), 0);
  484. goto err1;
  485. }
  486. if(bind(session->pasv_listen_sockfd, (struct sockaddr *)&local, addr_len)==-1)
  487. {
  488. rt_sprintf(sbuf, "425 Can't open data connection2.\r\n");
  489. send(session->sockfd, sbuf, strlen(sbuf), 0);
  490. goto err1;
  491. }
  492. if(listen(session->pasv_listen_sockfd, 1)==-1)
  493. {
  494. rt_sprintf(sbuf, "425 Can't open data connection3.\r\n");
  495. send(session->sockfd, sbuf, strlen(sbuf), 0);
  496. goto err1;
  497. }
  498. if (-1 == getsockname(session->pasv_listen_sockfd, (struct sockaddr *)&data, &len)) {
  499. rt_kprintf("Cannot determine our address, need it if client should connect to us\n");
  500. goto err1;
  501. }
  502. port = ntohs(data.sin_port);
  503. rt_kprintf("Port %d\n", port);
  504. /* Convert server IP address and port to comma separated list */
  505. msg = strdup(session->serveraddr);
  506. if (!msg) {
  507. rt_sprintf(sbuf, "426 Internal server error.\r\n");
  508. send(session->sockfd, sbuf, strlen(sbuf), 0);
  509. goto err1;
  510. }
  511. p = msg;
  512. while ((p = strchr(p, '.')))
  513. *p++ = ',';
  514. rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port);
  515. rt_sprintf(sbuf, "227 Entering passive mode (%s,%d,%d)\r\n", msg, port / 256, port % 256);
  516. send(session->sockfd, sbuf, strlen(sbuf), 0);
  517. rt_free(sbuf);
  518. rt_free(msg);
  519. return 0;
  520. #if 0
  521. FD_SET(sockfd, &readfds);
  522. select(0, &readfds, 0, 0, &tv);
  523. if(FD_ISSET(sockfd, &readfds))
  524. {
  525. if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1)
  526. {
  527. rt_sprintf(sbuf, "425 Can't open data connection4.\r\n");
  528. send(session->sockfd, sbuf, strlen(sbuf), 0);
  529. goto err1;
  530. }
  531. else
  532. {
  533. rt_kprintf("Got Data(PASV) connection from %s\n", inet_ntoa(pasvremote.sin_addr));
  534. session->pasv_active = 1;
  535. closesocket(sockfd);
  536. }
  537. }
  538. else
  539. {
  540. err1:
  541. closesocket(session->pasv_sockfd);
  542. session->pasv_active = 0;
  543. rt_free(sbuf);
  544. return 0;
  545. }
  546. #endif
  547. err1:
  548. close_data_connection(session);
  549. session->pasv_active = 0;
  550. rt_free(sbuf);
  551. rt_free(msg);
  552. return 0;
  553. }
  554. else if (str_begin_with(buf, "RETR")==0)
  555. {
  556. int file_size;
  557. open_data_connection(session);
  558. strcpy(filename, buf + 5);
  559. build_full_path(session, parameter_ptr, filename, 256);
  560. file_size = ftp_get_filesize(filename);
  561. if (file_size == -1)
  562. {
  563. rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
  564. send(session->sockfd, sbuf, strlen(sbuf), 0);
  565. session->offset=0;
  566. close_data_connection(session);
  567. rt_free(sbuf);
  568. return 0;
  569. }
  570. fd = open(filename, O_RDONLY, 0);
  571. if (fd < 0)
  572. {
  573. close_data_connection(session);
  574. rt_free(sbuf);
  575. return 0;
  576. }
  577. if(session->offset>0 && session->offset < file_size)
  578. {
  579. lseek(fd, session->offset, SEEK_SET);
  580. rt_sprintf(sbuf, "150 Opening binary mode data connection for partial \"%s\" (%d/%d bytes).\r\n",
  581. filename, file_size - session->offset, file_size);
  582. }
  583. else
  584. {
  585. rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\" (%d bytes).\r\n", filename, file_size);
  586. }
  587. send(session->sockfd, sbuf, strlen(sbuf), 0);
  588. while((numbytes = read(fd, sbuf, FTP_BUFFER_SIZE))>0)
  589. {
  590. send(session->pasv_sockfd, sbuf, numbytes, 0);
  591. }
  592. rt_sprintf(sbuf, "226 Finished.\r\n");
  593. send(session->sockfd, sbuf, strlen(sbuf), 0);
  594. close(fd);
  595. close_data_connection(session);
  596. }
  597. else if (str_begin_with(buf, "STOR")==0)
  598. {
  599. open_data_connection(session);
  600. if(session->is_anonymous == RT_TRUE)
  601. {
  602. rt_sprintf(sbuf, "550 Permission denied.\r\n");
  603. send(session->sockfd, sbuf, strlen(sbuf), 0);
  604. close_data_connection(session);
  605. rt_free(sbuf);
  606. return 0;
  607. }
  608. build_full_path(session, parameter_ptr, filename, 256);
  609. fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
  610. if(fd < 0)
  611. {
  612. rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename);
  613. send(session->sockfd, sbuf, strlen(sbuf), 0);
  614. close_data_connection(session);
  615. rt_free(sbuf);
  616. return 0;
  617. }
  618. rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\".\r\n", filename);
  619. send(session->sockfd, sbuf, strlen(sbuf), 0);
  620. FD_ZERO(&readfds);
  621. FD_SET(session->pasv_sockfd, &readfds);
  622. rt_kprintf("Waiting %d seconds for data...\n", tv.tv_sec);
  623. while(select(session->pasv_sockfd+1, &readfds, 0, 0, &tv)>0 )
  624. {
  625. if((numbytes=recv(session->pasv_sockfd, sbuf, FTP_BUFFER_SIZE, 0))>0)
  626. {
  627. write(fd, sbuf, numbytes);
  628. }
  629. else if(numbytes==0)
  630. {
  631. close(fd);
  632. close_data_connection(session);
  633. rt_sprintf(sbuf, "226 Finished.\r\n");
  634. send(session->sockfd, sbuf, strlen(sbuf), 0);
  635. break;
  636. }
  637. else if(numbytes==-1)
  638. {
  639. close(fd);
  640. close_data_connection(session);
  641. rt_free(sbuf);
  642. return -1;
  643. }
  644. }
  645. close_data_connection(session);
  646. }
  647. else if(str_begin_with(buf, "SIZE")==0)
  648. {
  649. int file_size;
  650. build_full_path(session, parameter_ptr, filename, 256);
  651. file_size = ftp_get_filesize(filename);
  652. if( file_size == -1)
  653. {
  654. rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
  655. send(session->sockfd, sbuf, strlen(sbuf), 0);
  656. }
  657. else
  658. {
  659. rt_sprintf(sbuf, "213 %d\r\n", file_size);
  660. send(session->sockfd, sbuf, strlen(sbuf), 0);
  661. }
  662. }
  663. else if(str_begin_with(buf, "MDTM")==0)
  664. {
  665. rt_sprintf(sbuf, "550 \"/\" : not a regular file\r\n");
  666. send(session->sockfd, sbuf, strlen(sbuf), 0);
  667. }
  668. else if(str_begin_with(buf, "SYST")==0)
  669. {
  670. rt_sprintf(sbuf, "215 %s\r\n", "RT-Thread RTOS");
  671. send(session->sockfd, sbuf, strlen(sbuf), 0);
  672. }
  673. else if(str_begin_with(buf, "CWD")==0)
  674. {
  675. build_full_path(session, parameter_ptr, filename, 256);
  676. rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
  677. send(session->sockfd, sbuf, strlen(sbuf), 0);
  678. strcpy(session->currentdir, filename);
  679. rt_kprintf("Changed to directory %s", filename);
  680. }
  681. else if(str_begin_with(buf, "CDUP")==0)
  682. {
  683. rt_sprintf(filename, "%s/%s", session->currentdir, "..");
  684. rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
  685. send(session->sockfd, sbuf, strlen(sbuf), 0);
  686. strcpy(session->currentdir, filename);
  687. rt_kprintf("Changed to directory %s", filename);
  688. }
  689. else if(str_begin_with(buf, "PORT")==0)
  690. {
  691. int i;
  692. int portcom[6];
  693. char tmpip[100];
  694. i=0;
  695. portcom[i++]=atoi(strtok(parameter_ptr, ".,;()"));
  696. for(;i<6;i++)
  697. portcom[i]=atoi(strtok(0, ".,;()"));
  698. rt_sprintf(tmpip, "%d.%d.%d.%d", portcom[0], portcom[1], portcom[2], portcom[3]);
  699. FD_ZERO(&readfds);
  700. if((session->pasv_sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
  701. {
  702. rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
  703. send(session->sockfd, sbuf, strlen(sbuf), 0);
  704. closesocket(session->pasv_sockfd);
  705. session->pasv_active = 0;
  706. rt_free(sbuf);
  707. return 0;
  708. }
  709. pasvremote.sin_addr.s_addr=inet_addr(tmpip);
  710. pasvremote.sin_port=htons(portcom[4] * 256 + portcom[5]);
  711. pasvremote.sin_family=PF_INET;
  712. if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
  713. {
  714. // is it only local address?try using gloal ip addr
  715. pasvremote.sin_addr=session->remote.sin_addr;
  716. if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
  717. {
  718. rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
  719. send(session->sockfd, sbuf, strlen(sbuf), 0);
  720. closesocket(session->pasv_sockfd);
  721. rt_free(sbuf);
  722. return 0;
  723. }
  724. }
  725. session->pasv_active=1;
  726. session->pasv_port = portcom[4] * 256 + portcom[5];
  727. rt_kprintf("Connected to Data(PORT) %s @ %d\n", tmpip, portcom[4] * 256 + portcom[5]);
  728. rt_sprintf(sbuf, "200 Port Command Successful.\r\n");
  729. send(session->sockfd, sbuf, strlen(sbuf), 0);
  730. }
  731. else if(str_begin_with(buf, "REST")==0)
  732. {
  733. if(atoi(parameter_ptr)>=0)
  734. {
  735. session->offset=atoi(parameter_ptr);
  736. rt_sprintf(sbuf, "350 Send RETR or STOR to start transfert.\r\n");
  737. send(session->sockfd, sbuf, strlen(sbuf), 0);
  738. }
  739. }
  740. else if(str_begin_with(buf, "MKD")==0)
  741. {
  742. if (session->is_anonymous == RT_TRUE)
  743. {
  744. rt_sprintf(sbuf, "530 Permission denied.\r\n");
  745. send(session->sockfd, sbuf, strlen(sbuf), 0);
  746. rt_free(sbuf);
  747. return 0;
  748. }
  749. build_full_path(session, parameter_ptr, filename, 256);
  750. if(mkdir(filename, 0) == -1)
  751. {
  752. rt_sprintf(sbuf, "550 File \"%s\" exists.\r\n", filename);
  753. send(session->sockfd, sbuf, strlen(sbuf), 0);
  754. }
  755. else
  756. {
  757. rt_sprintf(sbuf, "257 directory \"%s\" successfully created.\r\n", filename);
  758. send(session->sockfd, sbuf, strlen(sbuf), 0);
  759. }
  760. }
  761. else if(str_begin_with(buf, "DELE")==0)
  762. {
  763. if (session->is_anonymous == RT_TRUE)
  764. {
  765. rt_sprintf(sbuf, "530 Permission denied.\r\n");
  766. send(session->sockfd, sbuf, strlen(sbuf), 0);
  767. rt_free(sbuf);
  768. return 0;
  769. }
  770. build_full_path(session, parameter_ptr, filename, 256);
  771. if(unlink(filename)==0)
  772. rt_sprintf(sbuf, "250 Successfully deleted file \"%s\".\r\n", filename);
  773. else
  774. {
  775. rt_sprintf(sbuf, "550 Not such file or directory: %s.\r\n", filename);
  776. }
  777. send(session->sockfd, sbuf, strlen(sbuf), 0);
  778. }
  779. else if(str_begin_with(buf, "RMD")==0)
  780. {
  781. if (session->is_anonymous == RT_TRUE)
  782. {
  783. rt_sprintf(sbuf, "530 Permission denied.\r\n");
  784. send(session->sockfd, sbuf, strlen(sbuf), 0);
  785. rt_free(sbuf);
  786. return 0;
  787. }
  788. build_full_path(session, parameter_ptr, filename, 256);
  789. if(unlink(filename) == -1)
  790. {
  791. rt_sprintf(sbuf, "550 Directory \"%s\" doesn't exist.\r\n", filename);
  792. send(session->sockfd, sbuf, strlen(sbuf), 0);
  793. }
  794. else
  795. {
  796. rt_sprintf(sbuf, "257 directory \"%s\" successfully deleted.\r\n", filename);
  797. send(session->sockfd, sbuf, strlen(sbuf), 0);
  798. }
  799. }
  800. else if(str_begin_with(buf, "RNFR")==0)
  801. {
  802. if (session->is_anonymous == RT_TRUE)
  803. {
  804. rt_sprintf(sbuf, "530 Permission denied.\r\n");
  805. send(session->sockfd, sbuf, strlen(sbuf), 0);
  806. rt_free(sbuf);
  807. return 0;
  808. }
  809. build_full_path(session, parameter_ptr, filename, 256);
  810. rt_sprintf(sbuf, "350 Successfully rececive old file \"%s\".\r\n", filename);
  811. send(session->sockfd, sbuf, strlen(sbuf), 0);
  812. }
  813. else if(str_begin_with(buf, "RNTO")==0)
  814. {
  815. char new_filename[256];
  816. if (session->is_anonymous == RT_TRUE)
  817. {
  818. rt_sprintf(sbuf, "530 Permission denied.\r\n");
  819. send(session->sockfd, sbuf, strlen(sbuf), 0);
  820. rt_free(sbuf);
  821. return 0;
  822. }
  823. build_full_path(session, parameter_ptr, new_filename, 256);
  824. if(rename(filename, new_filename) == -1)
  825. {
  826. rt_sprintf(sbuf, "553 rename file \"%s\" error.\r\n", filename);
  827. send(session->sockfd, sbuf, strlen(sbuf), 0);
  828. }
  829. else
  830. {
  831. rt_sprintf(sbuf, "250 Successfully rename to new file \"%s\".\r\n", filename);
  832. send(session->sockfd, sbuf, strlen(sbuf), 0);
  833. }
  834. }
  835. else if((str_begin_with(buf, "NOOP")==0) || str_begin_with(buf, "noop")==0)
  836. {
  837. rt_sprintf(sbuf, "200 noop!\r\n");
  838. send(session->sockfd, sbuf, strlen(sbuf), 0);
  839. }
  840. else if(str_begin_with(buf, "QUIT")==0)
  841. {
  842. rt_sprintf(sbuf, "221 Bye!\r\n");
  843. send(session->sockfd, sbuf, strlen(sbuf), 0);
  844. rt_free(sbuf);
  845. return -1;
  846. }
  847. else
  848. {
  849. rt_sprintf(sbuf, "502 Not Implemented.\r\n");
  850. send(session->sockfd, sbuf, strlen(sbuf), 0);
  851. }
  852. rt_free(sbuf);
  853. return 0;
  854. }
  855. void ftpd_start()
  856. {
  857. rt_thread_t tid;
  858. tid = rt_thread_create("ftpd",
  859. ftpd_thread_entry, RT_NULL,
  860. 4096, 30, 5);
  861. if (tid != RT_NULL) rt_thread_startup(tid);
  862. }
  863. #ifdef RT_USING_FINSH
  864. #include <finsh.h>
  865. FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server);
  866. #ifdef FINSH_USING_MSH
  867. int cmd_ftpd_start(int argc, char** argv)
  868. {
  869. ftpd_start();
  870. return 0;
  871. }
  872. FINSH_FUNCTION_EXPORT_ALIAS(cmd_ftpd_start, __cmd_ftpd_start, start ftp server.);
  873. #endif
  874. #endif