C++实现FTP参考代码 2011
2012-11-13 11:11
295 查看
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdarg.h> //to use va_list
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/socket.h>
#include <fcntl.h> //file
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(arr[0])) //结构体元素个数
#include "ftp_server.h"
int ftp_srv_port =21;
int ftp_quit_flag;
struct ftp_user_struct *ftp_cur_user;
int ftp_pasv_socket = -1;
int ftp_pasv_control_socket = -1;
int ftp_port_control_socket = -1;
char ftp_home_dir[PATH_MAX];
int ftp_cur_child_num;
struct ftp_user_struct *ftp_cur_user;
static int
ftp_create_srv(void) // Create ftp server's listening socket.
{
int listen_socket;
int on = 1;
int nresult;
struct sockaddr_in srvaddr;
if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("socket() failed\n");
return listen_socket;
}
nresult = setsockopt(listen_socket, SOL_SOCKET
, SO_REUSEADDR, &on, sizeof(on));
if (nresult < 0)
{
printf("setsockopt() failed\n");
close(listen_socket);
return -1;
}
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(ftp_srv_port);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); //The address is local host
nresult = bind(listen_socket, (struct sockaddr*)&srvaddr,
sizeof(srvaddr)); //to bind the port and address
if (nresult < 0) {
printf("bind() failed \n");
close(listen_socket);
return -1;
}
nresult = listen(listen_socket, FTP_LISTEN_QU_LEN);
//the max queue is 8 by default
if (nresult < 0) {
printf("listen() failed: %s\n", strerror(errno));
close(listen_socket);
return -1;
}
// message
int len = sizeof(srvaddr);
getsockname(listen_socket, (struct sockaddr*)&srvaddr, &len);
printf("Create server listen socket successed: %s:%d\n",
inet_ntoa(srvaddr.sin_addr), ntohs(srvaddr.sin_port));
// end message
return sock;
}
static int mul_client_run(int listenfd)
{
int connfd;
int pid;
while (1) {
printf("Server ready, wait client's connection...%s", "\n");
connfd = accept(listenfd, NULL, NULL);// no need to save the resquset host address information
if (connfd < 0) {
printf("accept() failed: %s\n", strerror(errno));
continue;
}
// message
struct sockaddr_in client_addr;
int len = sizeof(client_addr);
getpeername(connfd, (struct sockaddr*)&client_addr, &len);
printf("accept a conn from %s:%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
// message
switch(pid=fork()) //为每一个新进来的客户端创建子进程,单独处理
{
case -1:
{
perror("The fork failed!");
}
case 0:
{
close(listenfd);
printf("child");
if (ftp_conn_handler(connfd) != 0)
exit(-1);
exit(0);
}
default:
{
close(connfd);
ftp_cur_child_num++;
printf("client number: %d",ftp_cur_child_num);
continue;
}
}
exit(0);
}
return 0;
}
static int ftp_conn_handler(int connfd) //处理客户端的函数
{
char buf[BUFSIZ];
int buflen;
int err =0;
// Control connection has set up,
if (ftp_send_resp(connfd, 220) != 0)
//给客户端发送命令
{
close(connfd);
printf("Close the ctrl connection OK%s", "\n");
return -1;
}
while (1) //死循环接收客户端发送的消息
{
buflen = ftp_recv_msg(connfd, buf, sizeof(buf));
if (buflen < 0) {
printf("ftp_recv_msg() failed: %s\n", strerror(errno));
err =-1;
break;
}
if (buflen == 0)
break;
buf[buflen] = '\0';
analy_ftp_requestmsg(connfd, buf);
//分析客户端发送的消息内容
if (ftp_quit_flag)
break;
}
close(connfd);
printf("Close the controll connection OK%s", "\n");
return err;
}
static int ftp_send_resp(int fd, int num, ...)
{
int i;
char buf[8];
snprintf(buf, sizeof(buf), "%d", num);
if (strlen(buf) != 3)
return NULL;
char* cp;
for (i = 0; i < ARRAY_LENGTH(ftp_srv_resps_struct); i++)
{
if (strncmp(buf, ftp_srv_resps_struct[i], 3) == 0)
//比较字符串str1和str2的前3个字符
{
cp = ftp_srv_resps_struct[i]; //返回命令号
break;
}
}
va_list ap;
char buf[BUFSIZ];
va_start(ap, num);
vsnprintf(buf, sizeof(buf), cp, ap);
va_end(ap);
printf("Server response code:%s\n", buf);
if (ftp_send_msg(fd, buf, strlen(buf)) != strlen(buf)) {
printf("ftp_send_msg() failed: %s\n", strerror(errno));
return -1;
}
return 0;
}
static int ftp_send_msg(int fd, char *msgbuffer, int len)
{
int nsendnum, nhave_send = 0;
int nsend_left = len;
while (1)
{
nsendnum = write(fd, msgbuffer + nhave_send, nsend_left);
if (nsendnum < 0)
{
if (errno == EINTR)
continue;
return n;
}
if (nsendnum < left)
{
nsend_left -= nsendnum;
nhave_send += nsendnum;
continue;
}
return len;
}
}
static int ftp_recv_msg(int fd, char buf[], int len)
{
int nrecv_num;
while (1)
{
nrecv_num = read(fd, buf, len);
if (nrecv_num < 0) {
continue;
return nrecv_num;
}
return nrecv_num;
}
}
//分析客户端发送的消息内容
static int analy_ftp_requestmsg(int connsockfd, char buf[])
{
char *pstrend = &buf[strlen(buf) - 1];
if (*pstrend == '\n' || *pstrend == '\r') //判断客户端是否执行了回车
{
if (buf && strlen(buf) > 0)
{
for (int i = 0; ftp_cmds[i].cmd_name; i++)
{
if (strcmp(buf, ftp_cmds[i].cmd_name) == 0) //数据判断正确
{
printf("recved a valid ftp cmd:%s\n", buf);
return ftp_cmds[i].cmd_handler(connsockfd, buf);
//接收数据正确,函数指针则执行对应的函数
}
}
return ftp_send_resp(connsockfd, 500, buf);
printf("recved a unsupported ftp cmd:%s\n", buf);
}
}
printf("recved a invalid ftp cmd:%s\n", buf);
return ftp_send_resp(connsockfd, 550);
}
static int ftp_user(int connsockfd, char *cmdbuffer)
//客户端发送命令USER时,服务器执行函数
{
// char *cp = strchr(cmdbuffer, ' '); //查找字符串s中首次出现空字符的位置
if (cmdbuffer)
{
int i;
for (i = 0; i < ARRAY_LENGTH(ftp_users); i++)
//循环查找对应的ftp用户名
if (strcmp(cp + 1, ftp_users[i].user) == 0)
{
printf("user(%s) is found\n", cp + 1);
ftp_cur_user = &ftp_users[i]; //set current user
break;
}
if (!ftp_cur_user)
printf("user(%s) not found\n", cp + 1);
return ftp_send_resp(connsockfd, 331, cp + 1);
//如果用户名正确则发送密码请求
}
return ftp_send_resp(connsockfd, 550);
}
//判断密码确认正确
static int ftp_pass(int ctrlfd, char *cmdbuffer)
{
if (cmdbuffer && ftp_cur_user)
{
printf("papapssss%s\n", cmdbuffer);
if (strlen(ftp_cur_user->pass) != 0 ||
strcmp(cmdbuffer, ftp_cur_user->pass) == 0)
{
printf("Password for %s OK\n", ftp_cur_user->user);
return ftp_send_resp(ctrlfd, 230, ftp_cur_user
->user);//The pass word is correct
}
printf("password for %s ERR\n", ftp_cur_user->user);
}
ftp_cur_user = NULL;
return ftp_send_resp(ctrlfd, 530, "Login failed!");
}
//客户端要求服务器开始socket服务,进入passive模式
static int ftp_pasv(int ctrlfd, char *cmdline)
{
struct sockaddr_in pasvaddr;
int len;
unsigned int ip;
unsigned short port;
FTP_CHECK_LOGIN();
if (ftp_pasv_socket >= 0)
{
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
}
ftp_pasv_socket = socket(AF_INET, SOCK_STREAM, 0);
if (ftp_pasv_socket < 0) {
printf("socket() failed: %s\n", strerror(errno));
return ftp_send_resp(ctrlfd, 550);
}
len = sizeof(pasvaddr);
getsockname(ctrlfd, (struct sockaddr*)&pasvaddr, &len);
pasvaddr.sin_port = 0;
if (bind(ftp_pasv_socket, (struct sockaddr*)&pasvaddr, sizeof(pasvaddr)) < 0) {
printf("bind() failed: %s\n", strerror(errno));
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
return ftp_send_resp(ctrlfd, 550);
}
if (listen(ftp_pasv_socket, FTP_LISTEN_QU_LEN) < 0) {
printf("listen() failed: %s\n", strerror(errno));
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
return ftp_send_resp(ctrlfd, 550);
}
len = sizeof(pasvaddr);
getsockname(ftp_pasv_socket, (struct sockaddr*)&pasvaddr, &len);
ip = ntohl(pasvaddr.sin_addr.s_addr);
port = ntohs(pasvaddr.sin_port);
printf("local bind: %s:%d\n", inet_ntoa(pasvaddr.sin_addr), port);
// write local ip/port into response msg and send to client.
return ftp_send_resp(ctrlfd, 227, (ip>>24)&0xff, (ip>>16)&0xff,
(ip>>8)&0xff, ip&0xff, (port>>8)&0xff, port&0xff);
}
// 给客户设置ip和端口号
static int ftp_port(int ctrlfd, char *cmdline)
{
unsigned int ip;
unsigned short port;
struct sockaddr_in sin;
FTP_CHECK_LOGIN();
char *cp = strchr(cmdline, ' ');
unsigned char buf[6];
cp++;
for ( int i = 0; i < ARRAY_LENGTH(buf); i++)
{
buf[i] = atoi(cp);
cp++;
}
*ip = *(unsigned int*)&buf[0];
*port = *(unsigned short*)&buf[4];
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip;
sin.sin_port = port;
printf("PORT cmd:%s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
if (ftp_port_control_socket >= 0)
{
close(ftp_port_control_socket);
ftp_port_control_socket = -1;
}
ftp_port_control_socket = socket(AF_INET, SOCK_STREAM, 0);
if (connect(ftp_port_control_socket, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
printf("bind() failed:%s\n", strerror(errno));
if (ftp_port_control_socket >= 0)
{
close(ftp_port_control_socket);
ftp_port_control_socket = -1;
}
return ftp_send_resp(ctrlfd, 550);
}
printf("PORT mode connect OK%s", "\n");
return ftp_send_resp(ctrlfd, 200);
}
static int ftp_stor(int ctrlfd, char *cmdline) //服务端接收文件操作函数
{
char buf[BUFSIZ];
struct stat st;
int fd = -1, n;
int left, off;
int connfd;
char* space = strchr(cmdline, ' ') ;
FTP_CHECK_LOGIN();
if (!space || lstat(space + 1, &st) == 0)
{
printf("STOR cmd err: %s\n", cmdline);
goto err_label;
}
if ((connfd = ftp_get_control_sock()) < 0)
//服务端接受请求并为客户创造单独的socket
{
printf("ftp_get_control_sock() failed%s", "\n");
goto err_label;
}
ftp_send_resp(ctrlfd, 150);
//新建一个可读写文件
if ((fd = open(space + 1, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0)
{
printf("open() failed: %s\n", strerror(errno));
goto err_label;
}
//begin to read data from socket and wirte to disk file
while (1) //死循环接受客户文件信息
{
if ((n = ftp_recv_msg(connfd, buf, sizeof(buf))) < 0)
{
printf("ftp_recv_msg() failed: %s\n", strerror(errno));
return -1;
}
if (n == 0)
break;
left = n;
off = 0;
while (left > 0)
{
int nwrite;
if ((nwrite = write(fd, buf + off, left)) < 0)
{ //循环将接受到的内容写入新建文件
if (errno == EINTR)
continue;
printf("write() failed:%s\n", strerror(errno));
}
off += nwrite;
left -= nwrite;
}
}
printf("STOR(%s) OK\n", space+1);
if (fd >= 0)
close(fd);
ftp_close_all_fd();
sync();
return ftp_send_resp(ctrlfd, 226);
}
static int ftp_get_control_sock(void)
{
int fd;
if (ftp_pasv_socket >= 0)
{
fd = accept(ftp_pasv_socket, NULL, NULL);
if (fd >= 0)
{
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
ftp_pasv_control_socket = fd;
return fd;
}
else
printf("accept() failed:%s\n", strerror(errno));
}
else if (ftp_port_control_socket >= 0)
return ftp_port_control_socket;
return (-1);
}
static int ftp_retr(int ctrlfd, char *cmdline) //发送文件函数
{
char buf[BUFSIZ];
struct stat st;
int fd = -1, n;
int connfd;
FTP_CHECK_LOGIN();
if (!strchr(cmdline, ' ') || lstat(space + 1, &st) < 0)
{
printf("RETR cmd err: %s\n", cmdline);
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
if ((connfd = ftp_get_control_sock()) < 0) //新建客户端对象
{
printf("ftp_get_control_sock() failed%s", "\n");
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
ftp_send_resp(ctrlfd, 150);
if ((fd = open(space + 1, O_RDONLY)) < 0) {
printf("open() failed: %s\n", strerror(errno));
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
while (1) //循环传输文件
{
if ((n = read(fd, buf, sizeof(buf))) < 0) //从文件中读取信息放入buf
{
if (errno == EINTR)
continue;
printf("read() failed: %s\n", strerror(errno));
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
if (n == 0)
break;
if (ftp_send_msg(connfd, buf, n) != n) //发送buf中的信息到客户
{
printf("ftp_send_msg() failed: %s\n", strerror(errno));
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
}
printf("RETR(%s) OK\n", space + 1);
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 226);
}
static int ftp_close_all_fd(void)
{
if (ftp_pasv_socket >= 0) {
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
}
if (ftp_pasv_control_socket >= 0) {
close(ftp_pasv_control_socket);
ftp_pasv_control_socket = -1;
}
if (ftp_port_control_socket >= 0) {
close(ftp_port_control_socket);
ftp_port_control_socket = -1;
}
return 0;
}
//This function acts as a implementation as 'ls -l' shell command.
static int ftp_list(int ctrlfd, char *cmdline)
{
char buf[BUFSIZ];
int n;
int fd;
FTP_CHECK_LOGIN();
if ((fd = ftp_get_control_sock()) < 0) {
printf("LIST cmd:no available fd%s", "\n");
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
ftp_send_resp(ctrlfd, 150);
// send the 'ls -l' result to client.
// n = ftp_get_list(buf, sizeof(buf));
int temp,n;
system("ls -l>.temp");
temp=open("./.temp", O_RDONLY);
if(temp<0)
{
puts ("OPEN .temp ERROR");
}
else
{
n=read(temp,buf,len);
//printf("hahah%s\n",buf);
}
system("rm -f ./.temp");
if (n >= 0) {
if (ftp_send_msg(fd, buf, n) != n) {
printf("ftp_send_msg() failed: %s\n", strerror(errno));
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
}
else {
printf("ftp_get_list() failed %s", "\n");
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 226);
// data transfer successed and close the data connection
}
char ftp_srv_resps_struct[][256] = { //服务器发送命令消息
"150 Begin transfer" "\r\n", //开始传输
"200 OK" "\r\n",
"213 %d" "\r\n",
"220 MyServer" "\r\n",
//
"221 Goodbye" "\r\n",
//离开
"226 Transfer complete" "\r\n", //传输完成
"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)" "\r\n", //进入Passive模式
"230 User %s logged in" "\r\n", //用户登录
"250 CWD command successful" "\r\n", //
"257 \"%s\" is current directory" "\r\n", //当前目录
"331 Password required for %s" "\r\n", //密码请求
"500 Unsupport command %s" "\r\n", //不支持的ftp类型
"530 Login %s" "\r\n", //登录服务器
"550 Error" "\r\n"
};
struct ftp_cmd_struct { //客户端命令消息结构体
char *cmd_name;
int (*cmd_handler)(int ctrlfd, char *cmd_line); //函数指针
};
struct ftp_cmd_struct ftp_cmds[] = {
{"USER", ftp_user},
{"PASS", ftp_pass},
{"PWD", ftp_pwd},
{"CWD", ftp_cwd},
{"LIST", ftp_list},
{"TYPE", ftp_type},
{"PORT", ftp_port},
{"PASV", ftp_pasv},
{"RETR", ftp_retr},
{"STOR", ftp_stor},
{"QUIT", ftp_quit},
};
struct ftp_user_struct {
char user[128];
char pass[128];
};
struct ftp_user_struct ftp_users[] = {
{"anonymous", ""},
{"user9", "ftp"},
{"movie9","lslslslslsls"}
};
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdarg.h> //to use va_list
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/socket.h>
#include <fcntl.h> //file
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(arr[0])) //结构体元素个数
#include "ftp_server.h"
int ftp_srv_port =21;
int ftp_quit_flag;
struct ftp_user_struct *ftp_cur_user;
int ftp_pasv_socket = -1;
int ftp_pasv_control_socket = -1;
int ftp_port_control_socket = -1;
char ftp_home_dir[PATH_MAX];
int ftp_cur_child_num;
struct ftp_user_struct *ftp_cur_user;
static int
ftp_create_srv(void) // Create ftp server's listening socket.
{
int listen_socket;
int on = 1;
int nresult;
struct sockaddr_in srvaddr;
if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("socket() failed\n");
return listen_socket;
}
nresult = setsockopt(listen_socket, SOL_SOCKET
, SO_REUSEADDR, &on, sizeof(on));
if (nresult < 0)
{
printf("setsockopt() failed\n");
close(listen_socket);
return -1;
}
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(ftp_srv_port);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); //The address is local host
nresult = bind(listen_socket, (struct sockaddr*)&srvaddr,
sizeof(srvaddr)); //to bind the port and address
if (nresult < 0) {
printf("bind() failed \n");
close(listen_socket);
return -1;
}
nresult = listen(listen_socket, FTP_LISTEN_QU_LEN);
//the max queue is 8 by default
if (nresult < 0) {
printf("listen() failed: %s\n", strerror(errno));
close(listen_socket);
return -1;
}
// message
int len = sizeof(srvaddr);
getsockname(listen_socket, (struct sockaddr*)&srvaddr, &len);
printf("Create server listen socket successed: %s:%d\n",
inet_ntoa(srvaddr.sin_addr), ntohs(srvaddr.sin_port));
// end message
return sock;
}
static int mul_client_run(int listenfd)
{
int connfd;
int pid;
while (1) {
printf("Server ready, wait client's connection...%s", "\n");
connfd = accept(listenfd, NULL, NULL);// no need to save the resquset host address information
if (connfd < 0) {
printf("accept() failed: %s\n", strerror(errno));
continue;
}
// message
struct sockaddr_in client_addr;
int len = sizeof(client_addr);
getpeername(connfd, (struct sockaddr*)&client_addr, &len);
printf("accept a conn from %s:%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
// message
switch(pid=fork()) //为每一个新进来的客户端创建子进程,单独处理
{
case -1:
{
perror("The fork failed!");
}
case 0:
{
close(listenfd);
printf("child");
if (ftp_conn_handler(connfd) != 0)
exit(-1);
exit(0);
}
default:
{
close(connfd);
ftp_cur_child_num++;
printf("client number: %d",ftp_cur_child_num);
continue;
}
}
exit(0);
}
return 0;
}
static int ftp_conn_handler(int connfd) //处理客户端的函数
{
char buf[BUFSIZ];
int buflen;
int err =0;
// Control connection has set up,
if (ftp_send_resp(connfd, 220) != 0)
//给客户端发送命令
{
close(connfd);
printf("Close the ctrl connection OK%s", "\n");
return -1;
}
while (1) //死循环接收客户端发送的消息
{
buflen = ftp_recv_msg(connfd, buf, sizeof(buf));
if (buflen < 0) {
printf("ftp_recv_msg() failed: %s\n", strerror(errno));
err =-1;
break;
}
if (buflen == 0)
break;
buf[buflen] = '\0';
analy_ftp_requestmsg(connfd, buf);
//分析客户端发送的消息内容
if (ftp_quit_flag)
break;
}
close(connfd);
printf("Close the controll connection OK%s", "\n");
return err;
}
static int ftp_send_resp(int fd, int num, ...)
{
int i;
char buf[8];
snprintf(buf, sizeof(buf), "%d", num);
if (strlen(buf) != 3)
return NULL;
char* cp;
for (i = 0; i < ARRAY_LENGTH(ftp_srv_resps_struct); i++)
{
if (strncmp(buf, ftp_srv_resps_struct[i], 3) == 0)
//比较字符串str1和str2的前3个字符
{
cp = ftp_srv_resps_struct[i]; //返回命令号
break;
}
}
va_list ap;
char buf[BUFSIZ];
va_start(ap, num);
vsnprintf(buf, sizeof(buf), cp, ap);
va_end(ap);
printf("Server response code:%s\n", buf);
if (ftp_send_msg(fd, buf, strlen(buf)) != strlen(buf)) {
printf("ftp_send_msg() failed: %s\n", strerror(errno));
return -1;
}
return 0;
}
static int ftp_send_msg(int fd, char *msgbuffer, int len)
{
int nsendnum, nhave_send = 0;
int nsend_left = len;
while (1)
{
nsendnum = write(fd, msgbuffer + nhave_send, nsend_left);
if (nsendnum < 0)
{
if (errno == EINTR)
continue;
return n;
}
if (nsendnum < left)
{
nsend_left -= nsendnum;
nhave_send += nsendnum;
continue;
}
return len;
}
}
static int ftp_recv_msg(int fd, char buf[], int len)
{
int nrecv_num;
while (1)
{
nrecv_num = read(fd, buf, len);
if (nrecv_num < 0) {
continue;
return nrecv_num;
}
return nrecv_num;
}
}
//分析客户端发送的消息内容
static int analy_ftp_requestmsg(int connsockfd, char buf[])
{
char *pstrend = &buf[strlen(buf) - 1];
if (*pstrend == '\n' || *pstrend == '\r') //判断客户端是否执行了回车
{
if (buf && strlen(buf) > 0)
{
for (int i = 0; ftp_cmds[i].cmd_name; i++)
{
if (strcmp(buf, ftp_cmds[i].cmd_name) == 0) //数据判断正确
{
printf("recved a valid ftp cmd:%s\n", buf);
return ftp_cmds[i].cmd_handler(connsockfd, buf);
//接收数据正确,函数指针则执行对应的函数
}
}
return ftp_send_resp(connsockfd, 500, buf);
printf("recved a unsupported ftp cmd:%s\n", buf);
}
}
printf("recved a invalid ftp cmd:%s\n", buf);
return ftp_send_resp(connsockfd, 550);
}
static int ftp_user(int connsockfd, char *cmdbuffer)
//客户端发送命令USER时,服务器执行函数
{
// char *cp = strchr(cmdbuffer, ' '); //查找字符串s中首次出现空字符的位置
if (cmdbuffer)
{
int i;
for (i = 0; i < ARRAY_LENGTH(ftp_users); i++)
//循环查找对应的ftp用户名
if (strcmp(cp + 1, ftp_users[i].user) == 0)
{
printf("user(%s) is found\n", cp + 1);
ftp_cur_user = &ftp_users[i]; //set current user
break;
}
if (!ftp_cur_user)
printf("user(%s) not found\n", cp + 1);
return ftp_send_resp(connsockfd, 331, cp + 1);
//如果用户名正确则发送密码请求
}
return ftp_send_resp(connsockfd, 550);
}
//判断密码确认正确
static int ftp_pass(int ctrlfd, char *cmdbuffer)
{
if (cmdbuffer && ftp_cur_user)
{
printf("papapssss%s\n", cmdbuffer);
if (strlen(ftp_cur_user->pass) != 0 ||
strcmp(cmdbuffer, ftp_cur_user->pass) == 0)
{
printf("Password for %s OK\n", ftp_cur_user->user);
return ftp_send_resp(ctrlfd, 230, ftp_cur_user
->user);//The pass word is correct
}
printf("password for %s ERR\n", ftp_cur_user->user);
}
ftp_cur_user = NULL;
return ftp_send_resp(ctrlfd, 530, "Login failed!");
}
//客户端要求服务器开始socket服务,进入passive模式
static int ftp_pasv(int ctrlfd, char *cmdline)
{
struct sockaddr_in pasvaddr;
int len;
unsigned int ip;
unsigned short port;
FTP_CHECK_LOGIN();
if (ftp_pasv_socket >= 0)
{
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
}
ftp_pasv_socket = socket(AF_INET, SOCK_STREAM, 0);
if (ftp_pasv_socket < 0) {
printf("socket() failed: %s\n", strerror(errno));
return ftp_send_resp(ctrlfd, 550);
}
len = sizeof(pasvaddr);
getsockname(ctrlfd, (struct sockaddr*)&pasvaddr, &len);
pasvaddr.sin_port = 0;
if (bind(ftp_pasv_socket, (struct sockaddr*)&pasvaddr, sizeof(pasvaddr)) < 0) {
printf("bind() failed: %s\n", strerror(errno));
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
return ftp_send_resp(ctrlfd, 550);
}
if (listen(ftp_pasv_socket, FTP_LISTEN_QU_LEN) < 0) {
printf("listen() failed: %s\n", strerror(errno));
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
return ftp_send_resp(ctrlfd, 550);
}
len = sizeof(pasvaddr);
getsockname(ftp_pasv_socket, (struct sockaddr*)&pasvaddr, &len);
ip = ntohl(pasvaddr.sin_addr.s_addr);
port = ntohs(pasvaddr.sin_port);
printf("local bind: %s:%d\n", inet_ntoa(pasvaddr.sin_addr), port);
// write local ip/port into response msg and send to client.
return ftp_send_resp(ctrlfd, 227, (ip>>24)&0xff, (ip>>16)&0xff,
(ip>>8)&0xff, ip&0xff, (port>>8)&0xff, port&0xff);
}
// 给客户设置ip和端口号
static int ftp_port(int ctrlfd, char *cmdline)
{
unsigned int ip;
unsigned short port;
struct sockaddr_in sin;
FTP_CHECK_LOGIN();
char *cp = strchr(cmdline, ' ');
unsigned char buf[6];
cp++;
for ( int i = 0; i < ARRAY_LENGTH(buf); i++)
{
buf[i] = atoi(cp);
cp++;
}
*ip = *(unsigned int*)&buf[0];
*port = *(unsigned short*)&buf[4];
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip;
sin.sin_port = port;
printf("PORT cmd:%s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
if (ftp_port_control_socket >= 0)
{
close(ftp_port_control_socket);
ftp_port_control_socket = -1;
}
ftp_port_control_socket = socket(AF_INET, SOCK_STREAM, 0);
if (connect(ftp_port_control_socket, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
printf("bind() failed:%s\n", strerror(errno));
if (ftp_port_control_socket >= 0)
{
close(ftp_port_control_socket);
ftp_port_control_socket = -1;
}
return ftp_send_resp(ctrlfd, 550);
}
printf("PORT mode connect OK%s", "\n");
return ftp_send_resp(ctrlfd, 200);
}
static int ftp_stor(int ctrlfd, char *cmdline) //服务端接收文件操作函数
{
char buf[BUFSIZ];
struct stat st;
int fd = -1, n;
int left, off;
int connfd;
char* space = strchr(cmdline, ' ') ;
FTP_CHECK_LOGIN();
if (!space || lstat(space + 1, &st) == 0)
{
printf("STOR cmd err: %s\n", cmdline);
goto err_label;
}
if ((connfd = ftp_get_control_sock()) < 0)
//服务端接受请求并为客户创造单独的socket
{
printf("ftp_get_control_sock() failed%s", "\n");
goto err_label;
}
ftp_send_resp(ctrlfd, 150);
//新建一个可读写文件
if ((fd = open(space + 1, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0)
{
printf("open() failed: %s\n", strerror(errno));
goto err_label;
}
//begin to read data from socket and wirte to disk file
while (1) //死循环接受客户文件信息
{
if ((n = ftp_recv_msg(connfd, buf, sizeof(buf))) < 0)
{
printf("ftp_recv_msg() failed: %s\n", strerror(errno));
return -1;
}
if (n == 0)
break;
left = n;
off = 0;
while (left > 0)
{
int nwrite;
if ((nwrite = write(fd, buf + off, left)) < 0)
{ //循环将接受到的内容写入新建文件
if (errno == EINTR)
continue;
printf("write() failed:%s\n", strerror(errno));
}
off += nwrite;
left -= nwrite;
}
}
printf("STOR(%s) OK\n", space+1);
if (fd >= 0)
close(fd);
ftp_close_all_fd();
sync();
return ftp_send_resp(ctrlfd, 226);
}
static int ftp_get_control_sock(void)
{
int fd;
if (ftp_pasv_socket >= 0)
{
fd = accept(ftp_pasv_socket, NULL, NULL);
if (fd >= 0)
{
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
ftp_pasv_control_socket = fd;
return fd;
}
else
printf("accept() failed:%s\n", strerror(errno));
}
else if (ftp_port_control_socket >= 0)
return ftp_port_control_socket;
return (-1);
}
static int ftp_retr(int ctrlfd, char *cmdline) //发送文件函数
{
char buf[BUFSIZ];
struct stat st;
int fd = -1, n;
int connfd;
FTP_CHECK_LOGIN();
if (!strchr(cmdline, ' ') || lstat(space + 1, &st) < 0)
{
printf("RETR cmd err: %s\n", cmdline);
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
if ((connfd = ftp_get_control_sock()) < 0) //新建客户端对象
{
printf("ftp_get_control_sock() failed%s", "\n");
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
ftp_send_resp(ctrlfd, 150);
if ((fd = open(space + 1, O_RDONLY)) < 0) {
printf("open() failed: %s\n", strerror(errno));
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
while (1) //循环传输文件
{
if ((n = read(fd, buf, sizeof(buf))) < 0) //从文件中读取信息放入buf
{
if (errno == EINTR)
continue;
printf("read() failed: %s\n", strerror(errno));
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
if (n == 0)
break;
if (ftp_send_msg(connfd, buf, n) != n) //发送buf中的信息到客户
{
printf("ftp_send_msg() failed: %s\n", strerror(errno));
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
}
printf("RETR(%s) OK\n", space + 1);
if (fd >= 0)
close(fd);
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 226);
}
static int ftp_close_all_fd(void)
{
if (ftp_pasv_socket >= 0) {
close(ftp_pasv_socket);
ftp_pasv_socket = -1;
}
if (ftp_pasv_control_socket >= 0) {
close(ftp_pasv_control_socket);
ftp_pasv_control_socket = -1;
}
if (ftp_port_control_socket >= 0) {
close(ftp_port_control_socket);
ftp_port_control_socket = -1;
}
return 0;
}
//This function acts as a implementation as 'ls -l' shell command.
static int ftp_list(int ctrlfd, char *cmdline)
{
char buf[BUFSIZ];
int n;
int fd;
FTP_CHECK_LOGIN();
if ((fd = ftp_get_control_sock()) < 0) {
printf("LIST cmd:no available fd%s", "\n");
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
ftp_send_resp(ctrlfd, 150);
// send the 'ls -l' result to client.
// n = ftp_get_list(buf, sizeof(buf));
int temp,n;
system("ls -l>.temp");
temp=open("./.temp", O_RDONLY);
if(temp<0)
{
puts ("OPEN .temp ERROR");
}
else
{
n=read(temp,buf,len);
//printf("hahah%s\n",buf);
}
system("rm -f ./.temp");
if (n >= 0) {
if (ftp_send_msg(fd, buf, n) != n) {
printf("ftp_send_msg() failed: %s\n", strerror(errno));
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
}
else {
printf("ftp_get_list() failed %s", "\n");
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 550);
}
ftp_close_all_fd();
return ftp_send_resp(ctrlfd, 226);
// data transfer successed and close the data connection
}
char ftp_srv_resps_struct[][256] = { //服务器发送命令消息
"150 Begin transfer" "\r\n", //开始传输
"200 OK" "\r\n",
"213 %d" "\r\n",
"220 MyServer" "\r\n",
//
"221 Goodbye" "\r\n",
//离开
"226 Transfer complete" "\r\n", //传输完成
"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)" "\r\n", //进入Passive模式
"230 User %s logged in" "\r\n", //用户登录
"250 CWD command successful" "\r\n", //
"257 \"%s\" is current directory" "\r\n", //当前目录
"331 Password required for %s" "\r\n", //密码请求
"500 Unsupport command %s" "\r\n", //不支持的ftp类型
"530 Login %s" "\r\n", //登录服务器
"550 Error" "\r\n"
};
struct ftp_cmd_struct { //客户端命令消息结构体
char *cmd_name;
int (*cmd_handler)(int ctrlfd, char *cmd_line); //函数指针
};
struct ftp_cmd_struct ftp_cmds[] = {
{"USER", ftp_user},
{"PASS", ftp_pass},
{"PWD", ftp_pwd},
{"CWD", ftp_cwd},
{"LIST", ftp_list},
{"TYPE", ftp_type},
{"PORT", ftp_port},
{"PASV", ftp_pasv},
{"RETR", ftp_retr},
{"STOR", ftp_stor},
{"QUIT", ftp_quit},
};
struct ftp_user_struct {
char user[128];
char pass[128];
};
struct ftp_user_struct ftp_users[] = {
{"anonymous", ""},
{"user9", "ftp"},
{"movie9","lslslslslsls"}
};
相关文章推荐
- 单例模式及C++实现代码
- SAD算法在opencv上的实现代码(c++)
- C++实现统计代码运行时间计时器的简单实例
- 左神第七讲-代码C++实现(后四道题)
- C++基础代码—20余种数据结构和算法的实现
- 《机器学习》第三章决策树学习 ID3算法 c++实现代码
- 自己动手实现简易代码生成器、采用文本模板文件生成服务层、服务层接口代码的做法参考
- Java代码实现FTP服务器上传文件与下载文件
- 插入排序(正序、倒序)-c++代码实现及运行实例结果
- strstr()函数c++代码实现实例及运行结果
- C++ 图的深度搜索广度搜索和最小生成树代码实现
- 链队列的实现,C++代码实现
- 二叉树用顺序表实现 C++代码实现
- C++ 基数排序的实现实例代码
- vs2010 c++ GUID获取代码实现
- Bezier曲线原理及实现代码(c++)
- 用C/C++实现SMC动态代码加密技术
- C++结合LUA实现代码热更新
- C++实现顺序排序算法简单示例代码
- C++ 直接选择排序的实现实例代码