[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.
This commit is contained in:
parent
2f5c5b676d
commit
707a657744
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue