summaryrefslogtreecommitdiff
path: root/components/net
diff options
context:
space:
mode:
authorweety <[email protected]>2015-05-14 22:41:31 +0800
committerweety <[email protected]>2015-05-14 22:41:31 +0800
commit707a6577446594653a3a8cec77dce4e4604ec108 (patch)
treefda975d0484a9f04f93d020cc77aa6c6e0444b46 /components/net
parent2f5c5b676ddd1db13d2b850e39b6fbfb000f907e (diff)
[FTP server]
1.Fixed PASV mode issue; 2.Implement RNFR and RNTO command; 3.Change some command code according RFC959; 4.Add command for msh shell; 5.Implement "noop" command.
Diffstat (limited to 'components/net')
-rw-r--r--components/net/lwip/apps/ftpd.c264
1 files changed, 229 insertions, 35 deletions
diff --git a/components/net/lwip/apps/ftpd.c b/components/net/lwip/apps/ftpd.c
index af48237e42..df1609fe1d 100644
--- a/components/net/lwip/apps/ftpd.c
+++ b/components/net/lwip/apps/ftpd.c
@@ -11,17 +11,24 @@
#define FTP_MAX_CONNECTION 2
#define FTP_USER "rtt"
#define FTP_PASSWORD "demo"
-#define FTP_WELCOME_MSG "220-= welcome on RT-Thread FTP server =-\r\n220 \r\n"
+#define FTP_WELCOME_MSG "220 welcome on RT-Thread FTP server.\r\n"
#define FTP_BUFFER_SIZE 1024
+#define INET_ADDRSTRLEN 16
+
+
struct ftp_session
{
rt_bool_t is_anonymous;
int sockfd;
struct sockaddr_in remote;
+ struct sockaddr_in server;
+
+ char serveraddr[INET_ADDRSTRLEN];
/* pasv data */
+ int pasv_listen_sockfd;
char pasv_active;
int pasv_sockfd;
@@ -43,6 +50,7 @@ struct ftp_session* ftp_new_session()
struct ftp_session* session;
session = (struct ftp_session*)rt_malloc(sizeof(struct ftp_session));
+ rt_memset((void *)session, 0, sizeof(struct ftp_session));
session->next = session_list;
session_list = session;
@@ -71,6 +79,83 @@ void ftp_close_session(struct ftp_session* session)
rt_free(session);
}
+static int open_data_connection(struct ftp_session* session)
+{
+ socklen_t len = sizeof(struct sockaddr);
+ struct sockaddr_in sin;
+#if 0
+ /* Previous PORT command from client */
+ if (ctrl->data_address[0]) {
+ ctrl->data_sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (-1 == ctrl->data_sd) {
+ printf("Failed creating data socket");
+ return -1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(ctrl->data_port);
+ inet_aton(ctrl->data_address, &(sin.sin_addr));
+
+ if (connect(ctrl->data_sd, (struct sockaddr *)&sin, len) == -1) {
+ printf("Failed connecting data socket to client");
+ close(ctrl->data_sd);
+ ctrl->data_sd = -1;
+
+ return -1;
+ }
+
+ DBG("Connected successfully to client's previously requested address:PORT %s:%d", ctrl->data_address, ctrl->data_port);
+ return 0;
+ }
+#endif
+ /* Previous PASV command, accept connect from client */
+ if (session->pasv_listen_sockfd > 0) {
+ char client_ip[100];
+
+ session->pasv_sockfd = accept(session->pasv_listen_sockfd, (struct sockaddr *)&sin, &len);
+ if (-1 == session->pasv_sockfd) {
+ printf("Failed accepting connection from client");
+ return -1;
+ }
+
+ len = sizeof(struct sockaddr);
+ if (-1 == getpeername(session->pasv_sockfd, (struct sockaddr *)&sin, &len)) {
+ printf("Cannot determine client address");
+ closesocket(session->pasv_sockfd);
+ session->pasv_sockfd = -1;
+ return -1;
+ }
+
+ printf("Client PASV data connection from %s\n", inet_ntoa(sin.sin_addr));
+ }
+
+ return 0;
+}
+
+static void close_data_connection(struct ftp_session* session)
+{
+ /* PASV server listening socket */
+ if (session->pasv_listen_sockfd > 0) {
+ closesocket(session->pasv_listen_sockfd);
+ session->pasv_listen_sockfd = -1;
+ }
+
+ /* PASV client socket */
+ if (session->pasv_sockfd > 0) {
+ closesocket(session->pasv_sockfd);
+ session->pasv_sockfd = -1;
+ }
+#if 0
+ /* PORT */
+ if (ctrl->data_address[0]) {
+ ctrl->data_address[0] = 0;
+ ctrl->data_port = 0;
+ }
+#endif
+}
+
+
int ftp_get_filesize(char * filename)
{
int pos;
@@ -179,6 +264,10 @@ void ftpd_thread_entry(void* parameter)
session = ftp_new_session();
if (session != NULL)
{
+ if (-1 == getsockname(com_socket, (struct sockaddr *)&session->server, &addr_len)) {
+ printf("Cannot determine our address, need it if client should connect to us\n");
+ }
+ ipaddr_ntoa_r(&(session->server.sin_addr), session->serveraddr, sizeof(session->serveraddr));
strcpy(session->currentdir, FTP_SRV_ROOT);
session->sockfd = com_socket;
session->remote = remote;
@@ -201,6 +290,7 @@ void ftpd_thread_entry(void* parameter)
rt_kprintf("Client %s disconnected\n", inet_ntoa(session->remote.sin_addr));
FD_CLR(session->sockfd, &readfds);
closesocket(session->sockfd);
+ session->sockfd = -1;
ftp_close_session(session);
}
else
@@ -210,6 +300,7 @@ void ftpd_thread_entry(void* parameter)
{
rt_kprintf("Client %s disconnected\r\n", inet_ntoa(session->remote.sin_addr));
closesocket(session->sockfd);
+ session->sockfd = -1;
ftp_close_session(session);
}
}
@@ -359,7 +450,7 @@ int ftp_process_request(struct ftp_session* session, char *buf)
}
else if (strcmp(parameter_ptr, FTP_USER) == 0)
{
- session->is_anonymous = RT_FALSE;
+ session->is_anonymous = RT_FALSE;
rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
@@ -380,25 +471,26 @@ int ftp_process_request(struct ftp_session* session, char *buf)
session->is_anonymous == RT_TRUE)
{
// password correct
- rt_sprintf(sbuf, "230 User logged in\r\n");
+ rt_sprintf(sbuf, "230 User logged in.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
- rt_free(sbuf);
+ rt_free(sbuf);
return 0;
}
// incorrect password
rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
- rt_free(sbuf);
+ rt_free(sbuf);
return -1;
}
else if(str_begin_with(buf, "LIST")==0 )
{
memset(sbuf,0,FTP_BUFFER_SIZE);
+ open_data_connection(session);
rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
do_list(session->currentdir, session->pasv_sockfd);
- closesocket(session->pasv_sockfd);
+ close_data_connection(session);
session->pasv_active = 0;
rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
@@ -408,8 +500,9 @@ int ftp_process_request(struct ftp_session* session, char *buf)
memset(sbuf, 0, FTP_BUFFER_SIZE);
rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
+ open_data_connection(session);
do_simple_list(session->currentdir, session->pasv_sockfd);
- closesocket(session->pasv_sockfd);
+ close_data_connection(session);
session->pasv_active = 0;
rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
@@ -436,8 +529,20 @@ int ftp_process_request(struct ftp_session* session, char *buf)
else if(str_begin_with(buf, "PASV")==0)
{
int dig1, dig2;
- int sockfd;
- char optval='1';
+ //int sockfd;
+ int optval=1;
+ int port;
+ struct sockaddr_in data;
+ socklen_t len = sizeof(struct sockaddr);
+ char *msg, *p;
+
+ if (session->pasv_sockfd > 0) {
+ closesocket(session->pasv_sockfd);
+ session->pasv_sockfd = -1;
+ }
+
+ if (session->pasv_listen_sockfd > 0)
+ closesocket(session->pasv_listen_sockfd);
session->pasv_port = 10000;
session->pasv_active = 1;
@@ -448,40 +553,63 @@ int ftp_process_request(struct ftp_session* session, char *buf)
dig2 = session->pasv_port % 256;
FD_ZERO(&readfds);
- if((sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1)
+ if((session->pasv_listen_sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1)
{
- rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+ rt_sprintf(sbuf, "425 Can't open data connection0.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
- if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1)
+ if(setsockopt(session->pasv_listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1)
{
- rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+ rt_sprintf(sbuf, "425 Can't open data connection1.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
- if(bind(sockfd, (struct sockaddr *)&local, addr_len)==-1)
+ if(bind(session->pasv_listen_sockfd, (struct sockaddr *)&local, addr_len)==-1)
{
- rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+ rt_sprintf(sbuf, "425 Can't open data connection2.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
- if(listen(sockfd, 1)==-1)
+ if(listen(session->pasv_listen_sockfd, 1)==-1)
{
- rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+ rt_sprintf(sbuf, "425 Can't open data connection3.\r\n");
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ goto err1;
+ }
+ if (-1 == getsockname(session->pasv_listen_sockfd, (struct sockaddr *)&data, &len)) {
+ rt_kprintf("Cannot determine our address, need it if client should connect to us\n");
+ goto err1;
+ }
+
+ port = ntohs(data.sin_port);
+ rt_kprintf("Port %d\n", port);
+
+ /* Convert server IP address and port to comma separated list */
+ msg = strdup(session->serveraddr);
+ if (!msg) {
+ rt_sprintf(sbuf, "426 Internal server error.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
+ p = msg;
+ while ((p = strchr(p, '.')))
+ *p++ = ',';
+
rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port);
- rt_sprintf(sbuf, "227 Entering passive mode (%d,%d,%d,%d,%d,%d)\r\n", 127, 0, 0, 1, dig1, dig2);
+ rt_sprintf(sbuf, "227 Entering passive mode (%s,%d,%d)\r\n", msg, port / 256, port % 256);
send(session->sockfd, sbuf, strlen(sbuf), 0);
+ rt_free(sbuf);
+ rt_free(msg);
+ return 0;
+ #if 0
FD_SET(sockfd, &readfds);
select(0, &readfds, 0, 0, &tv);
if(FD_ISSET(sockfd, &readfds))
{
if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1)
{
- rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+ rt_sprintf(sbuf, "425 Can't open data connection4.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
@@ -500,11 +628,21 @@ err1:
rt_free(sbuf);
return 0;
}
+ #endif
+err1:
+ close_data_connection(session);
+ session->pasv_active = 0;
+ rt_free(sbuf);
+ rt_free(msg);
+ return 0;
+
}
else if (str_begin_with(buf, "RETR")==0)
{
int file_size;
+ open_data_connection(session);
+
strcpy(filename, buf + 5);
build_full_path(session, parameter_ptr, filename, 256);
@@ -514,13 +652,15 @@ err1:
rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
session->offset=0;
- rt_free(sbuf);
+ close_data_connection(session);
+ rt_free(sbuf);
return 0;
}
fd = open(filename, O_RDONLY, 0);
if (fd < 0)
{
+ close_data_connection(session);
rt_free(sbuf);
return 0;
}
@@ -543,14 +683,16 @@ err1:
rt_sprintf(sbuf, "226 Finished.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
close(fd);
- closesocket(session->pasv_sockfd);
+ close_data_connection(session);
}
else if (str_begin_with(buf, "STOR")==0)
{
+ open_data_connection(session);
if(session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "550 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
+ close_data_connection(session);
rt_free(sbuf);
return 0;
}
@@ -562,6 +704,7 @@ err1:
{
rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
+ close_data_connection(session);
rt_free(sbuf);
return 0;
}
@@ -579,7 +722,7 @@ err1:
else if(numbytes==0)
{
close(fd);
- closesocket(session->pasv_sockfd);
+ close_data_connection(session);
rt_sprintf(sbuf, "226 Finished.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
break;
@@ -587,12 +730,12 @@ err1:
else if(numbytes==-1)
{
close(fd);
- closesocket(session->pasv_sockfd);
+ close_data_connection(session);
rt_free(sbuf);
return -1;
}
}
- closesocket(session->pasv_sockfd);
+ close_data_connection(session);
}
else if(str_begin_with(buf, "SIZE")==0)
{
@@ -659,7 +802,7 @@ err1:
send(session->sockfd, sbuf, strlen(sbuf), 0);
closesocket(session->pasv_sockfd);
session->pasv_active = 0;
- rt_free(sbuf);
+ rt_free(sbuf);
return 0;
}
pasvremote.sin_addr.s_addr=inet_addr(tmpip);
@@ -674,7 +817,7 @@ err1:
rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
closesocket(session->pasv_sockfd);
- rt_free(sbuf);
+ rt_free(sbuf);
return 0;
}
}
@@ -697,9 +840,9 @@ err1:
{
if (session->is_anonymous == RT_TRUE)
{
- rt_sprintf(sbuf, "550 Permission denied.\r\n");
+ rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
- rt_free(sbuf);
+ rt_free(sbuf);
return 0;
}
@@ -720,7 +863,7 @@ err1:
{
if (session->is_anonymous == RT_TRUE)
{
- rt_sprintf(sbuf, "550 Permission denied.\r\n");
+ rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
@@ -740,9 +883,9 @@ err1:
{
if (session->is_anonymous == RT_TRUE)
{
- rt_sprintf(sbuf, "550 Permission denied.\r\n");
+ rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
- rt_free(sbuf);
+ rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, filename, 256);
@@ -758,12 +901,53 @@ err1:
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
-
+ else if(str_begin_with(buf, "RNFR")==0)
+ {
+ if (session->is_anonymous == RT_TRUE)
+ {
+ rt_sprintf(sbuf, "530 Permission denied.\r\n");
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ rt_free(sbuf);
+ return 0;
+ }
+ build_full_path(session, parameter_ptr, filename, 256);
+
+ rt_sprintf(sbuf, "350 Successfully rececive old file \"%s\".\r\n", filename);
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ }
+ else if(str_begin_with(buf, "RNTO")==0)
+ {
+ char new_filename[256];
+ if (session->is_anonymous == RT_TRUE)
+ {
+ rt_sprintf(sbuf, "530 Permission denied.\r\n");
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ rt_free(sbuf);
+ return 0;
+ }
+ build_full_path(session, parameter_ptr, new_filename, 256);
+
+ if(rename(filename, new_filename) == -1)
+ {
+ rt_sprintf(sbuf, "553 rename file \"%s\" error.\r\n", filename);
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ }
+ else
+ {
+ rt_sprintf(sbuf, "250 Successfully rename to new file \"%s\".\r\n", filename);
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ }
+ }
+ else if((str_begin_with(buf, "NOOP")==0) || str_begin_with(buf, "noop")==0)
+ {
+ rt_sprintf(sbuf, "200 noop!\r\n");
+ send(session->sockfd, sbuf, strlen(sbuf), 0);
+ }
else if(str_begin_with(buf, "QUIT")==0)
{
rt_sprintf(sbuf, "221 Bye!\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
- rt_free(sbuf);
+ rt_free(sbuf);
return -1;
}
else
@@ -771,7 +955,7 @@ err1:
rt_sprintf(sbuf, "502 Not Implemented.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
- rt_free(sbuf);
+ rt_free(sbuf);
return 0;
}
@@ -787,5 +971,15 @@ void ftpd_start()
#ifdef RT_USING_FINSH
#include <finsh.h>
-FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server)
+FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server);
+
+#ifdef FINSH_USING_MSH
+int cmd_ftpd_start(int argc, char** argv)
+{
+ ftpd_start();
+ return 0;
+}
+FINSH_FUNCTION_EXPORT_ALIAS(cmd_ftpd_start, __cmd_ftpd_start, start ftp server.);
+#endif
+
#endif