ftp linux实现,linux下的简单的ftp实现

支持功能:LIST,RETR,STOR,PORT

待完善:用户验证

#include "ftp_server.h"

#include

#include

#include

#include

#include

static int servfd;

static int connlen = 0;

static struct serv_cntl_conn *cntl_head = NULL;

static int dataquene_sem;

in_addr_t localaddr;

in_port_t localcntlport;

in_port_t localdataport;

char homedir[PATH_MAX+1];

static char cntlsendbuf[LINELEN+1];

struct serv_cntl_conn *accept_new_client(int servfd);

int do_server_cmd_port(struct serv_cntl_conn *cntl, char *params);

void do_server_cmd_transfer(struct serv_data_conn *dconnp);

static void transfer_over(struct serv_cntl_conn *cntl)

{

struct serv_data_conn *dconnp = cntl->dataconn;

printf("close data sock: %d\\n", dconnp->sockfd);

/* 先shutdown是为了让客户端受到连接关闭的通知 */

shutdown(dconnp->sockfd, SHUT_RDWR);

close(dconnp->sockfd);

cntl->status = CS_WAIT_CMD;

dconnp->sockfd = -1;

dconnp->pid = -1;

}

void sig_child(int sig)

{

pid_t pid = wait(NULL);

struct serv_cntl_conn *cntl;

for (cntl = cntl_head; cntl; cntl = cntl->next) {

struct serv_data_conn *dconnp = cntl->dataconn;

if (dconnp && dconnp->pid == pid) {

transfer_over(cntl);

break;

}

}

if (signal(SIGCHLD, sig_child) == SIG_ERR) {

fprintf(stderr, "signal error\\n");

}

printf("sig child handled. pid=%d\\n", pid);

}

/*

init socket ,bind, listen

*/

static void init_server()

{

struct addrinfo hints;

struct addrinfo *result, *rp;

int s, val;

char hostname[HOST_NAME_MAX+1];

gethostname(hostname, HOST_NAME_MAX+1);

localdataport = htons(SERVER_DATA_PORT);

memset(&hints, 0, sizeof(struct addrinfo));

hints.ai_family = AF_INET;

hints.ai_socktype = SOCK_STREAM;

hints.ai_flags = AI_PASSIVE;

s = getaddrinfo(hostname, "ftp", &hints, &result);

if(s != 0) {

fprintf(stderr, "getaddinfo: %s\\n", gai_strerror(s));

exit(EXIT_FAILURE);

}

for (rp = result; rp != NULL; rp = rp->ai_next) {

servfd = initserver(SOCK_STREAM, rp->ai_addr, rp->ai_addrlen, MAX_CONN);

if (servfd >= 0){

char addr[INET_ADDRSTRLEN];

struct sockaddr_in * sa_in = (struct sockaddr_in*)rp->ai_addr;

in_addr_t in_addr = sa_in->sin_addr.s_addr;

inet_ntop(AF_INET, &in_addr, addr, INET_ADDRSTRLEN);

fprintf(stdout, "bind on address %s:%u\\n",

addr, ntohs(sa_in->sin_port));

localaddr = in_addr;

localcntlport = sa_in->sin_port;

break;

}

}

if (rp == NULL) {

fprintf(stderr, "Counld not bind\\n");

exit(EXIT_FAILURE);

}

freeaddrinfo(result);

}

static void reset_cntl(struct serv_cntl_conn *cntl)

{

if (cntl == NULL)

return;

cntl->lineused = 0;

cntl->status = CS_WAIT_CMD;

}

int checkpasswd(char *user, char *passwd)

{

//TODO: check password

return 0;

}

static int handle_line_request(struct serv_cntl_conn *cntl, char *linerecvd)

{

struct serv_data_conn *dconnp;

int sockfd, n, bufsize, retval;

char *params;

enum FTP_CMD cmd;

struct sembuf sems[] = {{0,1,0}};

if (!cntl || !linerecvd)

goto errout;

puts("handle_line_request");

retval = pharsecmdline(linerecvd, &cmd, &params);

if (retval < 0) {

fprintf(stderr, "wrong command: %s\\n", linerecvd);

goto errout;

}

fprintf(stdout, "line left --> [%d] %s\\n", cntl->lineused, cntl->line);

cntl->lastcmd = cmd;

if (cntl->lastparams)

free(cntl->lastparams);

cntl->lastparams = params;

switch(cmd) {

case CMD_ABOR: break;

case CMD_LIST: goto trans;

case CMD_PASS:

if (cntl->user) {

if (checkpasswd(cntl->user, params) == 0) {

snprintf(cntlsendbuf, LINELEN, "230 User logged in, proceed.\\n");

cntl->logon = 1;

}

else

snprintf(cntlsendbuf, LINELEN, "530 Not logged in.\\n");

} else {

snprintf(cntlsendbuf, LINELEN, "332 Need account for login.\\n");

}

write(cntl->sockfd,cntlsendbuf,strlen(cntlsendbuf));

puts(cntlsendbuf);

break;

case CMD_PORT:

if (cntl->status == CS_WAIT_CMD) {

if (do_server_cmd_port(cntl, params) == 0) {

/* ready for transfer, send response for PORT command */

snprintf(cntlsendbuf, LINELEN,

"225 Data connection open; no transfer in progress.\\n");

write(cntl->sockfd,cntlsendbuf,strlen(cntlsendbuf));

puts(cntlsendbuf);

return 0;

} else {

goto errout;

}

} else {

printf("receive PORT while status not CS_WAIT_CMD.\\n");

goto errout;

}

break;

case CMD_QUIT: break;

case CMD_RETR: goto trans;

case CMD_STOR: goto trans;

case CMD_SYST: break;

case CMD_TYPE: break;

case CMD_USER:

if (!params)

break;

if (cntl->user)

free(cntl->user);

cntl->user = strdup(params);

cntl->logon = 0;

snprintf(cntlsendbuf, LINELEN, "331 User name okay, need password.\\n");

write(cntl->sockfd,cntlsendbuf,strlen(cntlsendbuf));

puts(cntlsendbuf);

break;

default: goto errout;

}

/* 忽略的命令直接进入 */

defaultout:

cntl->lastcmd = cmd;

cntl->status = CS_WAIT_CMD;

return 0;

trans:

if (cntl->status == CS_PORT_RECVD && cntl->dataconn &&

cntl->dataconn->status == DS_READY) {

pid_t pid;

struct serv_data_conn *dconnp = cntl->dataconn;

dconnp->cmd = cmd;

dconnp->filename = params ? strdup(params):NULL;

snprintf(cntlsendbuf, LINELEN,

"125 Data connection already open; transfer starting.\\n");

write(cntl->sockfd, cntlsendbuf, strlen(cntlsendbuf));

printf("%s", cntlsendbuf);

do_server_cmd_transfer(dconnp);

//transfer_over(cntl);

//cntl->status = CS_WAIT_CMD;

cntl->status = CS_WAIT_TRANS;

dconnp->status = DS_TRANSING;

// puts("data conn closed.");

return 0;

} else {

goto errout;

}

errout:

cntl->status = CS_WAIT_CMD;

return -1;

}

static int handle_request(struct serv_cntl_conn *cntl)

{

int n;

char *linerecvd = NULL;

if (!cntl)

return -1;

puts("handle_request");

do {

if (!linerecvd)

free(linerecvd);

n = readline(cntl->sockfd, cntl->line, LINELEN,

&cntl->lineused, &linerecvd);

if (n == 0) { // connection closed

close(cntl->sockfd);

fprintf(stdout, "LOG: close socket %d\\n", cntl->sockfd);

cntl->sockfd = -1;

cntl->status = CS_FINISHED;

return 0;

} else if (n < 0) { /* error receive */

if (errno == EAGAIN || errno == EWOULDBLOCK) /* no data */

break;

else {

fprintf(stderr, "error receive data : %s\\n", strerror(errno));

reset_cntl(cntl);

// exit(EXIT_FAILURE);

return -1;

}

}

if (linerecvd) {

fprintf(stdout, "LOG: received line --> %s\\n", linerecvd);

handle_line_request(cntl, linerecvd);

}

} while (n > 0 && linerecvd != NULL);

return 0;

}

/*

1) select one fd

2) accept to get connection, add the connection to pool

3) read request, dispatch

*/

static void server()

{

fd_set rfds;

int retval, flags, maxfd = 0;

struct serv_cntl_conn *curcntl, *lastcntl;

/* set NONBLOCK */

// fcntl(servfd, F_SETOWN, getpid());

flags = fcntl(servfd, F_GETFL);

fcntl(servfd, F_SETFL, flags|O_NONBLOCK);

fprintf(stdout,"server for loop\\n");

connlen = 0;

cntl_head = NULL;

for (;;) {

FD_ZERO(&rfds);

FD_SET(servfd, &rfds);

maxfd = servfd;

lastcntl = NULL;

for (curcntl = cntl_head; curcntl; ) {

/* 删除已经关闭的客户端 */

if (curcntl->status == CS_FINISHED) {

struct serv_cntl_conn *next = curcntl->next;

if (lastcntl) {

lastcntl->next = next;

} else {

cntl_head = next;

}

if (curcntl->lastparams)

free(curcntl->lastparams);

if (curcntl->cwd)

free(curcntl->cwd);

free(curcntl);

curcntl = next;

connlen --;

continue;

}

int fd = curcntl->sockfd;

FD_SET(fd, &rfds);

maxfd = maxfd < fd ? fd : maxfd;

lastcntl = curcntl;

curcntl = curcntl->next;

}

while (select(maxfd+1, &rfds, NULL, NULL, NULL) == -1) {

if (errno == EINTR) {

continue;

} else {

fprintf(stderr,"select(): %s\\n", strerror(errno));

exit(EXIT_FAILURE);

}

}

for (curcntl = cntl_head; curcntl; curcntl = curcntl->next) {

int fd = curcntl->sockfd;

if (FD_ISSET(fd, &rfds)) {

fprintf(stdout,"fd %d is set\\n", fd);

handle_request(curcntl);

printf("hand fd %d ok\\n",fd);

}

}

if (FD_ISSET(servfd, &rfds)) { /*new connect*/

struct serv_cntl_conn *servconn;

servconn = accept_new_client(servfd);

if (servconn != NULL) {

if (connlen < MAX_CONN) {

servconn->next = cntl_head;

cntl_head = servconn;

connlen ++;

fprintf(stdout, "accepted, fd = %d, connlen = %d\\n",

servconn->sockfd,connlen);

} else {

fprintf(stderr, "reach max connection size\\n");

shutdown(servconn->sockfd, SHUT_RDWR);

close(servconn->sockfd);

free(servconn);

}

}

}

}

}

int main(int argc, const char* argv[])

{

int err;

pthread_t tid;

strcpy(homedir, "/home/kuangf/ftptmp/");

init_server();

#if 1

if (signal(SIGCHLD, sig_child) == SIG_ERR) {

fprintf(stderr, "signal error\\n");

}

#endif

server();

fprintf(stdout, "server out\\n");

return 0;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值