实现ftpserver

本文根据在网上已有的ftpserver实现,但是根据那个源代码无法运行成功,因此,这里是基于那个代码的基础上,修改的(网址忘记了)。增加了一些命令,以及界面交互和bug. 目的在于熟悉ftp的协议以及通信。

环境:Ubuntu

1. ftpserver源码实现:


/*
	@brief: ftp server
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
struct data {
    char ip[100];
    short port;
    char user[100];
    char pass[100];
    char url[100];
    int sock;
    pthread_t pid;
    FILE *fp;
};
 
void server_init(struct data *data);
void server_set(struct data *data, const char *addr, short port, const char *user, const char *pass, const char *rooturl);
int server_start(struct data *data);
void server_stop(struct data *data);

#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/wait.h>
 
struct ftp_server {
    int ofs;
    int port_ip;
    short port_port;
    int c_sock;
    int d_sock;
    int data_sock;
    int c_addr;
    short c_port;
    int d_addr;
    short d_port;
    int islogin;
    char rename[256];
    char send_buf[256];
    char user[100];
    char pass[100];
    void *data;
};
 
static pid_t pid_arr[256];
 
static void sig_fun(int sig)
{
    int status, i;
    pid_t pid = wait(&status);
    for (i = 0; i < sizeof(pid_arr) / sizeof(pid_arr[0]); i++) {
        if (pid_arr[i] == pid) {
			printf("pid=%d child exit\n", pid);
            pid_arr[i] = 0;
        }
    }
}
 
static void close_tenor(void)
{
    int i;
    for (i = 0; i < sizeof(pid_arr) / sizeof(pid_arr[0]); i++) {
        if (pid_arr[i]) {
            kill(pid_arr[i], SIGINT);
            pid_arr[i] = 0;
        }
    }
}
 
static char *my_split(char *src, const char *key, int *len, char **data)
{
    char *pos, *p;
    if (src) *data = src;
    pos = strstr(*data, key);
    if (!pos) {
        *len = 0;
        return *data;
    } else {
        *len = pos - *data;
        p = *data;
        while (!memcmp(pos, key, strlen(key))) {
            pos += strlen(key);
        }
        *data = pos;
        return p;
    }
}
 
 
 
static int ftp_server_user(struct ftp_server *server, const char *cmd)
{
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
    if (!strcmp(server->user, start)) {
        sprintf(server->send_buf, "331 Password required\r\n");
        server->islogin = 1;
    } else {
        sprintf(server->send_buf, "332 notfound user\r\n");
        server->islogin = 0;
    }
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_pass(struct ftp_server *server, const char *cmd)
{
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    if (!strcmp(server->pass, start)) {
        sprintf(server->send_buf, "230 User logged in..\r\n");
        if (server->islogin == 1)
            server->islogin = 2;
        else
            server->islogin = 0;
    } else {
        sprintf(server->send_buf, "331 Need password login\r\n");
        server->islogin = 0;
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_syst(struct ftp_server *server, const char *cmd)
{
	char* buf = "215 UNIX ftpserver emulated \r\n";
    printf("%s", buf);
    send(server->c_sock, buf, strlen(buf), 0);
    return 0;
}
 
static int ftp_server_pwd(struct ftp_server *server, const char *cmd)
{
    char buf[128] = {};
    getcwd(buf, sizeof(buf) - 1);
    sprintf(server->send_buf, "257 \"%s\" is current directory.\r\n", buf);
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_type(struct ftp_server *server, const char *cmd)
{
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
    if (!strncmp(start, "I", 1)) {
        sprintf(server->send_buf, "200 Type set to I.\r\n");
    } else {
        sprintf(server->send_buf, "500 : command not understood.\r\n");
    }
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_pasv(struct ftp_server *server, const char *cmd)
{
    int ret;
    struct sockaddr_in addr;
 
    server->port_ip = 0;
    server->d_sock = socket(AF_INET, SOCK_STREAM , 0);
    if (server->d_sock == -1) {
        return -1;
    }
    struct timeval timeout = {6, 0};
    setsockopt(server->d_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
    //设置接收超时
    setsockopt(server->d_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
 
    addr.sin_addr.s_addr = server->d_addr;
    addr.sin_port = 0;
    addr.sin_family = AF_INET;
 
    int opt=SO_REUSEADDR;
    setsockopt(server->d_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 
    ret = bind(server->d_sock, (struct sockaddr *)&addr, sizeof(addr));
    if (ret != 0) {
        return -1;
    }
 
    struct sockaddr_in localaddr;
    socklen_t locallen = sizeof(localaddr);
    getsockname(server->d_sock, (struct sockaddr *)&localaddr, & locallen);
    ret = listen(server->d_sock, 10);
    if (ret == -1) {
        close(server->d_sock);
        return -1;
    }
 
    short port =  localaddr.sin_port;
    sprintf(server->send_buf, "227 Entering Passive Mode (%s,%d,%d)\r\n", inet_ntoa(localaddr.sin_addr),
            0xff & (port),
            0xff & (port >> 8));
    int i;
    for (i = 0; i < strlen(server->send_buf); i++) {
        if (server->send_buf[i] == '.')
            server->send_buf[i] = ',';
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_port(struct ftp_server *server, const char *cmd)
{
    char *start;
	struct in_addr add;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    char *pos, *end;
    pos = start;
    int i;
    for (i = 0, end = pos; i < 4; i++) {
        end = strstr(end, ",");
        if (end) *end = '.';
    }
    *end = 0;
 
    server->port_ip = inet_addr(pos);
	add.s_addr = server->port_ip;
    pos = ++end;
    end = strstr(pos, ",");
        if (end) *end = 0;
    server->port_port = atoi(pos);
    server->port_port <<= 8;
    server->port_port |= atoi(end + 1);
    server->port_port = htons(server->port_port);
 
    printf("%s",  "200 Port command successful.\r\n");
	printf("ip=%s,port=%d\n", inet_ntoa(add), ntohs(server->port_port));
    send(server->c_sock, "200 Port command successful.\r\n",
         strlen("200 Port command successful.\r\n"), 0);
 
    return 0;
}
 
static int ftp_server_get_dsock(struct ftp_server *server)
{
    struct sockaddr_in inaddr;

    socklen_t socklen = sizeof(inaddr);
    if (server->port_ip == 0) {
        server->data_sock = accept(server->d_sock, (struct sockaddr *)&inaddr, &socklen);
        if (server->data_sock == -1) return -1;
    } else {
        server->data_sock = socket(AF_INET, SOCK_STREAM, 0);
        if (server->data_sock == -1) return -1;
        inaddr.sin_addr.s_addr = server->port_ip;
        inaddr.sin_port = server->port_port;
        inaddr.sin_family = AF_INET;

		//in server, bind port=20
		struct sockaddr_in serv_addr;
		serv_addr.sin_addr.s_addr = server->d_addr;
    	serv_addr.sin_port = 20;
    	serv_addr.sin_family = AF_INET;
		int opt=SO_REUSEADDR;
    	setsockopt(server->data_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        int bind_ret = bind(server->data_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
		if (bind_ret == -1) 
        {
        	perror("bind");
        	printf("failed\n");
        	return -1;
    	}
		
        struct timeval timeout = {30, 0};
        setsockopt(server->data_sock , SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
        int ret = connect(server->data_sock, (struct sockaddr *)&inaddr, socklen);
        if (ret == -1) {
            close(server->data_sock);
            server->data_sock = -1;
            return -1;
        }
    }
    return 0;
}
 
static void stat_test(const char *name, char *out)
{
    struct stat s = {};
    char buf[100] = {};
    int res = stat(name, &s);
 
    if (-1 == res) {
        return;
    }
    if (S_ISDIR(s.st_mode)) {
        out[0] = 'd';
    } else {
        out[0] = '-';
    }
    out[1] = 0;
    int i;
    int num = s.st_mode & 07777;
    strcat(out, "rwxrwxrwx");
    for (i = 0; i < 9; i++) {
        if (!(num & (0x100 >> i))) {
            out[i + 1] = '-';
        }
    }
    strcat(out, " ");
    sprintf(buf, "%3d", s.st_nlink);
    strcat(out, buf);
    strcat(out, " root root ");
    sprintf(buf, "%6d", (int)s.st_size);
    strcat(out, buf);
    strcat(out, " ");
    time_t t = time(NULL);
    int year = gmtime(&t)->tm_year;
    int year2 = gmtime(&s.st_mtime)->tm_year;
    if (year == year2) {
        strftime(buf, sizeof(buf), "%h %d %R", gmtime(&s.st_mtime));
    } else {
        strftime(buf, sizeof(buf), "%h %d %G", gmtime(&s.st_mtime));
    }
    strcat(out, buf);
    strcat(out, " ");
    strcat(out, name);
    strcat(out, "\r\n");
}
 
 
 
static int ftp_server_list(struct ftp_server *server, const char *cmd)
{
    if (server->d_sock == -1) return -1;
    printf("%s", "150 Opening BINARY mode data connection for /bin/ls.\r\n");
    send(server->c_sock, "150 Opening BINARY mode data connection for /bin/ls.\r\n",
         strlen("150 Opening BINARY mode data connection for /bin/ls.\r\n"), 0);
 
 
    DIR *dir = NULL;
    struct dirent *ent = NULL;
    char buf[256] = {};
    dir  = opendir(".");
    if (!dir) {
        return -1;
    }
 
    if (-1 == ftp_server_get_dsock(server)) {
        return -1;
    }
    while ((ent = readdir(dir))) {
        if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
        stat_test(ent->d_name, buf);
        //printf("%s", buf);
        send(server->data_sock, buf, strlen(buf), 0);
    }
    closedir(dir);
 
    close(server->data_sock);
    if (server->d_sock != -1) close(server->d_sock);
 
    printf("%s",  "226 Transfer complete.\r\n");
    send(server->c_sock, "226 Transfer complete.\r\n",
         strlen("226 Transfer complete.\r\n"), 0);
    return 0;
}
 
static int ftp_server_stor(struct ftp_server *server, const char *cmd)
{
    if (server->d_sock == -1) return -1;
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    sprintf(server->send_buf, "150 Opening BINARY mode data connection.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    int fd;
    int len;
    char buf[256] = {};
 
    if (-1 == ftp_server_get_dsock(server)) {
        sprintf(server->send_buf, "553 net err\r\n");
        printf("%s", server->send_buf);
        send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
        if (server->d_sock != -1) close(server->d_sock);
        return -1;
    }
 
 
    fd = open(start, O_CREAT  | O_TRUNC | O_WRONLY, 0664);
    if (fd == -1) {
        sprintf(server->send_buf, "553 : Permission denied\r\n");
    } else {
        while ((len = recv(server->data_sock, buf, sizeof(buf), 0)) > 0) {
            write(fd, buf, len);
        }
        close(fd);
    }
 
    close(server->data_sock);
    if (server->d_sock != -1) close(server->d_sock);
 
    sprintf(server->send_buf, "226 Transfer complete.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_rest(struct ftp_server *server, const char *cmd)
{
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
    server->ofs = atoi(start);
    printf("%s",  "200 complete.\r\n");
    send(server->c_sock, "200 complete.\r\n",
         strlen("200 complete.\r\n"), 0);
    return 0;
}
 
static int ftp_server_appe(struct ftp_server *server, const char *cmd)
{
    if (server->d_sock == -1) return -1;
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    sprintf(server->send_buf, "150 Opening BINARY mode data connection.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    int fd;
    int len;
    char buf[256] = {};
 
    if (-1 == ftp_server_get_dsock(server)) {
        sprintf(server->send_buf, "553 net err\r\n");
        printf("%s", server->send_buf);
        send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
        if (server->d_sock != -1) close(server->d_sock);
        return -1;
    }
 
 
    fd = open(start,   O_APPEND | O_WRONLY);
    if (fd == -1) {
        sprintf(server->send_buf, "553 : Permission denied\r\n");
    } else {
        while ((len = recv(server->data_sock, buf, sizeof(buf), 0)) > 0) {
            write(fd, buf, len);
        }
        close(fd);
    }
 
    close(server->data_sock);
    if (server->d_sock != -1) close(server->d_sock);
 
    sprintf(server->send_buf, "226 Transfer complete.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_retr(struct ftp_server *server, const char *cmd)
{
    if (server->d_sock == -1) return -1;
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    sprintf(server->send_buf, "150 Opening BINARY mode data connection for.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    int fd;
    int len, ret;
    char buf[256] = {};
 
    if (-1 == ftp_server_get_dsock(server)) {
        sprintf(server->send_buf, "553 net err\r\n");
        printf("%s", server->send_buf);
        send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
        if (server->d_sock != -1) close(server->d_sock);
        return -1;
    }
 
 
    fd = open(start, O_RDONLY);
    if (fd == -1) {
        sprintf(server->send_buf, "553 : Permission denied\r\n");
    } else {
        lseek(fd, server->ofs, SEEK_SET);
        while ((len = read(fd, buf, sizeof(buf))) > 0) {
            ret = send(server->data_sock, buf, len, 0);
            if (ret < 0)
                break;
        }
        server->ofs = 0;
        close(fd);
    }
 
    close(server->data_sock);
    if (server->d_sock != -1) close(server->d_sock);
 
    sprintf(server->send_buf, "226 Transfer complete.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_size(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    struct stat info;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
    ret = stat(start, &info);
    if (ret) {
        sprintf(server->send_buf, "550 : not a plain file.\r\n");
    } else {
        sprintf(server->send_buf, "213 %u\r\n", (unsigned int)info.st_size);
    }
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_cwd(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
    ret = chdir(start);
    if (ret == -1) {
        sprintf(server->send_buf, "550 : No such file or directory.\r\n");
    } else {
        sprintf(server->send_buf, "250 CWD command successful.\r\n");
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_cdup(struct ftp_server *server, const char *cmd)
{
    int ret;
    ret = chdir("..");
    if (ret == -1) {
        sprintf(server->send_buf, "550 CDUP No such file or directory.\r\n");
    } else {
        sprintf(server->send_buf, "250 CDUP command successful.\r\n");
    }
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_mkd(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    ret = access(start, F_OK);
    if (!ret) {
        sprintf(server->send_buf, "550 : File exists.\r\n");
    } else {
        ret = mkdir(start, 0775);
        if (ret == -1) {
            sprintf(server->send_buf, "550 : Permission denied.\r\n");
        } else {
            sprintf(server->send_buf, "257 MKD command successful.\r\n");
        }
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_rmd(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    ret = access(start, F_OK);
    if (ret) {
        sprintf(server->send_buf, "550 : No such file or directory.\r\n");
    } else {
 
        ret = rmdir(start);
        if (ret == -1) {
            sprintf(server->send_buf, "550 : Permission denied.\r\n");
        } else {
            sprintf(server->send_buf, "250 RMD command successful.\r\n");
        }
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_dele(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    ret = access(start, F_OK);
    if (ret) {
        sprintf(server->send_buf, "550 : No such file or directory.\r\n");
    } else {
 
        ret = remove(start);
        if (ret == -1) {
            sprintf(server->send_buf, "550 : Permission denied.\r\n");
        } else {
            sprintf(server->send_buf, "250 DELE command successful.\r\n");
        }
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_utf8(struct ftp_server *server, const char *cmd)
{
    sprintf(server->send_buf, "200  No such file or directory.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_feat(struct ftp_server *server, const char *cmd)
{
    sprintf(server->send_buf, "211-Features\r\n SIZE \r\n UTF8\r\n211 End\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_site_chmod(struct ftp_server *server, const char *cmd)
{
    char name[256] = {};
    mode_t mode;
    char *start;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start = strstr(++start, " ");
    if (!start) return -1;
    start++;
 
    printf("%s\n", start);
    sscanf(start, "%o%s", (int *)&mode, name);
    printf("%d %s\n", (int)mode, name);
 
    chmod(name, mode);
 
    sprintf(server->send_buf, "200 ok.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_rnfr(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
 
    ret = access(start, F_OK);
    if (ret) {
        sprintf(server->send_buf, "550 : No such file or directory.\r\n");
    } else {
        strcpy(server->rename, start);
        sprintf(server->send_buf, "200 command successful.\r\n");
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
static int ftp_server_rnto(struct ftp_server *server, const char *cmd)
{
    char *start;
    int ret;
    start = strstr(cmd, " ");
    if (!start) return -1;
    start++;
    ret = rename(server->rename, start);
    if (ret) {
        sprintf(server->send_buf, "550 : rename err.\r\n");
    } else {
        sprintf(server->send_buf, "200 command successful.\r\n");
    }
 
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
static int ftp_server_quit(struct ftp_server *server, const char *cmd)
{
	char buf[100] = {}; 
	struct sockaddr_in peeraddr;
	socklen_t peer_len = 0;
	peer_len = sizeof(peeraddr);
	getpeername(server->c_sock, (struct sockaddr*)&peeraddr, &peer_len);
	snprintf(buf, sizeof(buf), "client %s %d close.\r\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
	printf("%s",buf);
    send(server->c_sock, buf, strlen(buf),0);
	close(server->c_sock);
	return 0;
}


static int ftp_server_nocmd(struct ftp_server *server, const char *cmd)
{
    sprintf(server->send_buf, "500 : command not understood.\r\n");
    printf("%s", server->send_buf);
    send(server->c_sock, server->send_buf, strlen(server->send_buf), 0);
    return 0;
}
 
 
struct cmd_t {
    const char *cmd;
    int (*func)(struct ftp_server *ftp, const char *cmd);
};
 
static struct cmd_t cmd_table[] = {
    [0] = {
        .cmd = "not found cmd",
        .func = ftp_server_nocmd
    },
    [1] = {
        .cmd = "PASS",
        .func = ftp_server_pass
    },
    [2] = {
        .cmd = "SYST",
        .func = ftp_server_syst
    },
    [3] = {
        .cmd = "USER",
        .func = ftp_server_user
    },
    [4] = {
        .cmd = "PWD",
        .func = ftp_server_pwd
    },
    [5] = {
        .cmd = "TYPE",
        .func = ftp_server_type
    },
    [6] = {
        .cmd = "PASV",
        .func = ftp_server_pasv
    },
    [7] = {
        .cmd = "LIST",
        .func = ftp_server_list
    },
    [8] = {
        .cmd = "CWD",
        .func = ftp_server_cwd
    },
    [9] = {
        .cmd = "CDUP",
        .func = ftp_server_cdup
    },
    [10] = {
        .cmd = "MKD",
        .func = ftp_server_mkd
    },
    [11] = {
        .cmd = "RMD",
        .func = ftp_server_rmd
    },
    [12] = {
        .cmd = "DELE",
        .func = ftp_server_dele
    },
    [13] = {
        .cmd = "STOR",
        .func = ftp_server_stor
    },
    [14] = {
        .cmd = "RETR",
        .func = ftp_server_retr
    },
    [15] = {
        .cmd = "SIZE",
        .func = ftp_server_size
    },
    [16] = {
        .cmd = "UTF8",
        .func = ftp_server_utf8
    },
    [17] = {
        .cmd = "FEAT",
        .func = ftp_server_feat
    },
    [18] = {
        .cmd = "SITE CHMOD",
        .func = ftp_server_site_chmod
    },
    [19] = {
        .cmd = "RNTO",
        .func = ftp_server_rnto
 
    },
    [20] = {
        .cmd = "RNFR",
        .func = ftp_server_rnfr
    },
    [21] = {
        .cmd = "APPE",
        .func = ftp_server_appe
    },
    [22] = {
        .cmd = "REST",
        .func = ftp_server_rest
    },
    [23] = {
        .cmd = "PORT",
        .func = ftp_server_port
    },
    [24] = {
        .cmd = "QUIT",
        .func = ftp_server_quit
    }
	
};
 
 
 
struct cmd_t *find_cmd(char *cmd)
{
    int i, len;
    char *end, *pos = NULL, *p;
    end = strstr(cmd, "\r\n");
    if (!end)
        end = strstr(cmd, "\n");
    if (!end) return NULL;
    *end = 0;
    p = my_split(cmd, " ", &len, &pos);
 
    for (i = 0; i < sizeof(cmd_table) / sizeof(cmd_table[0]); i++) {
        if (!strncmp(cmd_table[i].cmd, p, strlen(cmd_table[i].cmd))) {
            return cmd_table + i;
        }
    }
    return cmd_table;
};
 
static void *pthread_func(void *data)
{
    int ret;
    char buf[256] = {};
    struct cmd_t *cmd;
    struct ftp_server *server = data;
    send(server->c_sock, "220 ftp\r\n", strlen("220 ftp\r\n"), 0);
    while (1) {
        ret = recv(server->c_sock, buf, sizeof(buf) - 1, 0);
        printf("%s", buf);
        if (ret <= 0)
            break;
        cmd = find_cmd(buf);
        if (cmd != cmd_table + 1 && cmd != cmd_table + 3) {
            if (server->islogin != 2)
                continue;
        }
        if (cmd)
        {
        	printf("CMD:%s, buf=%s\n", cmd->cmd, buf);
        	cmd->func(server, buf);
        }
        memset(buf, 0, sizeof(buf));
    }

	printf("%s exit\n", __func__);
    close(server->c_sock);
    free(server);
    return NULL;
}
 
 
int ftp_start(int sock, const char *local_addr, const char *user, const char *pass)
{
    struct ftp_server *server = malloc(sizeof(struct ftp_server));
    memset(server, 0, sizeof(struct ftp_server));
    strcpy(server->user, user);
    strcpy(server->pass, pass);
    server->c_sock = sock;
    server->d_addr = inet_addr(local_addr);
    struct timeval timeout = {300, 0};
    setsockopt(sock , SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
    setsockopt(sock , SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
    //pthread_create(&pid, NULL, pthread_func, (void *)server);
    pthread_func((void *)server);
    return 0;
}
 
static void thread_exit_handler(int sig)
{
    printf("this signal is %d \n", sig);
    pthread_exit(0);
}
 
void *server_pthread(void *data)
{
    struct data  *p = data;
    int lis_sock = p->sock;
    int client;
    struct sockaddr_in cli_addr;
    socklen_t len;
    len = sizeof(cli_addr);
 
 	printf("enter server_pthread\n");
    //pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
    while (1) {
        client = accept(lis_sock, (struct sockaddr *)&cli_addr, &len);
        if (client == -1)
            break;
 
 
        int i;
        for (i = 0; i < sizeof(pid_arr) / sizeof(pid_arr[0]); i++) {
            if (!pid_arr[i]) {
                pid_arr[i] = fork();
                break;
            }
        }
 
        if (i == sizeof(pid_arr) / sizeof(pid_arr[0])) {
            close(client);
            continue;
        }
 
        if (pid_arr[i] < 0) {
            close(client);
            pid_arr[i] = 0;
            continue;
        } else if (pid_arr[i] == 0) {
			printf("i=%d, connect client,cli_addr.port=%d,addr=%s\n",i, ntohs(cli_addr.sin_port), inet_ntoa(cli_addr.sin_addr));
            ftp_start(client, p->ip, p->user, p->pass);
            close(lis_sock);
            exit(0);
        } else if (pid_arr[i] > 0) {
            close(client);
        }
    }
    close(lis_sock);
    return NULL;
}
 
void server_init(struct data *data)
{
    memset(data, 0, sizeof(struct data));
    data->fp = fopen("./ftp.dat", "rb+");
    if (!data->fp) {
        data->fp = fopen("./ftp.dat", "wb+");
        if (data->fp) {
            fprintf(data->fp, "%hd %s %s %s\n", 2121, "ftp", "1234", "/");
        }
        //data->port = 2121;
        data->port = 2121;
        strcpy(data->user, "ftp");
        strcpy(data->pass, "1234");
        strcpy(data->url, "/");
        return;
    }
    fscanf(data->fp, "%d %s %s %s", (int*)(&data->port), data->user, data->pass, data->url);
}
 
void server_set(struct data *data, const char *addr, short port, const char *user, const char *pass, const char *rooturl)
{
    //strcpy(data->ip, addr);
    //strcpy(data->user, user);
    //strcpy(data->pass, pass);
    //strcpy(data->url, rooturl);
    memcpy(data->ip, addr, strlen(addr));
	memcpy(data->user, user, strlen(user));
	memcpy(data->pass, pass, strlen(pass));
	memcpy(data->url, rooturl, strlen(rooturl));
    data->port = port;

	printf("server ip=%s, port=%hd,user=%s,pass=%s,url=%s\n", data->ip, data->port, data->user, data->pass,data->url);
}
 
int server_start(struct data *data)
{
    int lis_sock, ret;
    struct sockaddr_in lis_addr;
 
    if (chroot(data->url) == -1) {
        ret = chdir(data->url);
    } else {
        ret = chdir("/");
    }
    if (ret == -1)
        return ret;
 
    lis_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (lis_sock == -1) {
        perror("socket");
        return -1;
    }
 
    lis_addr.sin_addr.s_addr = inet_addr(data->ip);
    lis_addr.sin_port = htons(data->port);
    lis_addr.sin_family = AF_INET;
 	printf("lis_addr.sin_port=%d,%hd, ip=%s\n", lis_addr.sin_port, data->port, inet_ntoa(lis_addr.sin_addr));
    int opt=SO_REUSEADDR;
    setsockopt(lis_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    ret = bind(lis_sock, (struct sockaddr*)&lis_addr, sizeof(lis_addr));
    if (ret == -1) {
        perror("bind");
        printf("failed\n");
        return -1;
    }
    printf("started\n");
    listen(lis_sock, 10);
	//printf("=======1\n");
    data->sock = lis_sock;
    //printf("=======1\n");
    signal(SIGCHLD, sig_fun);
	//printf("=======2\n");
    signal(SIGQUIT, thread_exit_handler);
	//printf("=======1\n");
    pthread_create(&data->pid, NULL, server_pthread, (void *)data);
 
    if (data->fp) {
        fseek(data->fp, 0, 0);
        fprintf(data->fp, "%hd %s %s %s\n", data->port, data->user, data->pass, data->url);
    }
	pthread_join(data->pid,NULL);
 	printf("====rerurn 0\n");
    return 0;
}
 
void server_stop(struct data *data)
{
    if (data->fp) {
        fclose(data->fp);
        data->fp = NULL;
    }
 
    close_tenor();
 
    if (data->pid) {
        //pthread_cancel(data->pid);
        pthread_kill(data->pid, SIGQUIT);
        shutdown(data->sock,  SHUT_RDWR);
        close(data->sock);
        data->sock = 0;
        data->pid = 0;
    }
}

void default_server_init(struct data *data)
{
	char buf[100]= {"127.0.0.1"};
	server_init(data);
	memcpy(data->ip, buf, sizeof(buf));
	printf("default server ip=%s, port=%hd,user=%s,pass=%s,url=%s\n", data->ip, data->port, data->user, data->pass,data->url);
	return;
}

int main(int argc, char **argv)
{	
	struct data ser_data;
	char buf[100]= {"127.0.0.1"};
	printf("use: ./ftpserver [ip] [port] [user] [pass]\r\n");
	printf("argc = %d\n",argc);
	memset(&ser_data, 0, sizeof(ser_data));
	if(2 == argc)
		server_set(&ser_data, argv[1], 21, "ftp", "1234", ".");
	else if(3 == argc)
		server_set(&ser_data, argv[1], atoi(argv[2]), "ftp", "1234", ".");
	else if(5 == argc)
		server_set(&ser_data, argv[1], atoi(argv[2]), argv[3], argv[4] , ".");
	else
		default_server_init(&ser_data);
	
	server_start(&ser_data);
	return 1;
}


2. Makefile

all:
    gcc -o ftpserver ftp_server.c -lpthread

3. 运行

打开一个控制台作为服务器
./ftpserver
(默认127.0.0.1 21)

打开另一个控制台作为客户端(如果客户端软件没有安装,可apt-get install 安装,网上可以查到,同时,如果系统有ftpserver,请关闭):

主动模式:
ftp 127.0.0.1 21

被动模式
ftp -p 127.0.0.1 21

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值