📄 cuftpd.c.c
字号:
}
return cuftpd_send_resp(ctrlfd, 550);
}
static int cuftpd_do_pasv(int ctrlfd, char *cmdline)
{
struct sockaddr_in pasvaddr;
int len;
unsigned int ip;
unsigned short port;
CUFTPD_CHECK_LOGIN();
if (cuftpd_pasv_fd >= 0) {
close(cuftpd_pasv_fd);
cuftpd_pasv_fd = -1;
}
cuftpd_pasv_fd = socket(AF_INET, SOCK_STREAM, 0);
if (cuftpd_pasv_fd < 0) {
CUFTPD_DEBUG("socket() failed: %s\n", strerror(errno));
return cuftpd_send_resp(ctrlfd, 550);
}
/*
* must bind to the same interface as ctrl connectin came from.
*/
len = sizeof(pasvaddr);
getsockname(ctrlfd, (struct sockaddr*)&pasvaddr, &len);
pasvaddr.sin_port = 0;
if (bind(cuftpd_pasv_fd, (struct sockaddr*)&pasvaddr, sizeof(pasvaddr)) < 0) {
CUFTPD_DEBUG("bind() failed: %s\n", strerror(errno));
close(cuftpd_pasv_fd);
cuftpd_pasv_fd = -1;
return cuftpd_send_resp(ctrlfd, 550);
}
if (listen(cuftpd_pasv_fd, CUFTPD_LISTEN_QU_LEN) < 0) {
CUFTPD_DEBUG("listen() failed: %s\n", strerror(errno));
close(cuftpd_pasv_fd);
cuftpd_pasv_fd = -1;
return cuftpd_send_resp(ctrlfd, 550);
}
len = sizeof(pasvaddr);
getsockname(cuftpd_pasv_fd, (struct sockaddr*)&pasvaddr, &len);
ip = ntohl(pasvaddr.sin_addr.s_addr);
port = ntohs(pasvaddr.sin_port);
CUFTPD_DEBUG("local bind: %s:%d\n", inet_ntoa(pasvaddr.sin_addr), port);
/*
* write local ip/port into response msg
* and send to client.
*/
return cuftpd_send_resp(ctrlfd, 227, (ip>>24)&0xff, (ip>>16)&0xff,
(ip>>8)&0xff, ip&0xff, (port>>8)&0xff, port&0xff);
}
static int cuftpd_do_retr(int ctrlfd, char *cmdline)
{
char buf[BUFSIZ];
char *space = strchr(cmdline, ' ');
struct stat st;
int fd = -1, n;
int connfd;
CUFTPD_CHECK_LOGIN();
if (!space || lstat(space + 1, &st) < 0) {
CUFTPD_DEBUG("RETR cmd err: %s\n", cmdline);
goto err_label;
}
if ((connfd = cuftpd_get_connfd()) < 0) {
CUFTPD_DEBUG("cuftpd_get_connfd() failed%s", "\n");
goto err_label;
}
cuftpd_send_resp(ctrlfd, 150);
/* begin to read file and write it to conn socket */
if ((fd = open(space + 1, O_RDONLY)) < 0) {
CUFTPD_DEBUG("open() failed: %s\n", strerror(errno));
goto err_label;
}
while (1) {
if ((n = read(fd, buf, sizeof(buf))) < 0) {
if (errno == EINTR)
continue;
CUFTPD_DEBUG("read() failed: %s\n", strerror(errno));
goto err_label;
}
if (n == 0)
break;
if (cuftpd_send_msg(connfd, buf, n) != n) {
CUFTPD_DEBUG("cuftpd_send_msg() failed: %s\n", strerror(errno));
goto err_label;
}
}
CUFTPD_DEBUG("RETR(%s) OK\n", space + 1);
if (fd >= 0)
close(fd);
cuftpd_close_all_fd();
return cuftpd_send_resp(ctrlfd, 226);
err_label:
if (fd >= 0)
close(fd);
cuftpd_close_all_fd();
return cuftpd_send_resp(ctrlfd, 550);
}
static int cuftpd_do_stor(int ctrlfd, char *cmdline)
{
char buf[BUFSIZ];
char *space = strchr(cmdline, ' ');
struct stat st;
int fd = -1, n;
int left, off;
int connfd;
CUFTPD_CHECK_LOGIN();
/*
* Should add some permission control mechanism here.
*/
if (!space || lstat(space + 1, &st) == 0) {
CUFTPD_DEBUG("STOR cmd err: %s\n", cmdline);
goto err_label;
}
if ((connfd = cuftpd_get_connfd()) < 0) {
CUFTPD_DEBUG("cuftpd_get_connfd() failed%s", "\n");
goto err_label;
}
cuftpd_send_resp(ctrlfd, 150);
if ((fd = open(space + 1, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
CUFTPD_DEBUG("open() failed: %s\n", strerror(errno));
goto err_label;
}
/* begin to read data from socket and wirte to disk file */
while (1) {
if ((n = cuftpd_recv_msg(connfd, buf, sizeof(buf))) < 0) {
CUFTPD_DEBUG("cuftpd_recv_msg() failed: %s\n", strerror(errno));
goto err_label;
}
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;
CUFTPD_DEBUG("write() failed:%s\n", strerror(errno));
goto err_label;
}
off += nwrite;
left -= nwrite;
}
}
CUFTPD_DEBUG("STOR(%s) OK\n", space+1);
if (fd >= 0)
close(fd);
cuftpd_close_all_fd();
sync();
return cuftpd_send_resp(ctrlfd, 226);
err_label:
if (fd >= 0) {
close(fd);
unlink(space+1);
}
cuftpd_close_all_fd();
return cuftpd_send_resp(ctrlfd, 550);
}
static int cuftpd_do_quit(int ctrlfd, char *cmdline)
{
cuftpd_send_resp(ctrlfd, 221);
cuftpd_quit_flag = 1;
return CUFTPD_OK;
}
static int cuftpd_do_request(int ctrlfd, char buf[])
{
char *end = &buf[strlen(buf) - 1];
char *space = strchr(buf, ' ');
int i;
char save;
int err;
if (*end == '\n' || *end == '\r') {
/*
* this is a valid ftp request.
*/
cuftpd_trim_lineend(buf);
if (!space)
space = &buf[strlen(buf)];
save = *space;
*space = '\0';
for (i = 0; cuftpd_cmds[i].cmd_name; i++) {
if (strcmp(buf, cuftpd_cmds[i].cmd_name) == 0) {
*space = save;
CUFTPD_DEBUG("recved a valid ftp cmd:%s\n", buf);
return cuftpd_cmds[i].cmd_handler(ctrlfd, buf);
}
}
/*
* unrecognized cmd
*/
*space = save;
CUFTPD_DEBUG("recved a unsupported ftp cmd:%s\n", buf);
*space = '\0';
err = cuftpd_send_resp(ctrlfd, 500, buf);
*space = save;
return err;
}
CUFTPD_DEBUG("recved a invalid ftp cmd:%s\n", buf);
/*
* Even if it's a invalid cmd, we should also send
* back a response to prevent client from blocking.
*/
return cuftpd_send_resp(ctrlfd, 550);
}
static int cuftpd_ctrl_conn_handler(int connfd)
{
char buf[BUFSIZ];
int buflen;
int err = CUFTPD_OK;
/*
* Control connection has set up,
* we can send out the first ftp msg.
*/
if (cuftpd_send_resp(connfd, 220) != CUFTPD_OK) {
close(connfd);
CUFTPD_DEBUG("Close the ctrl connection OK%s", "\n");
return CUFTPD_ERR;
}
/*
* Begin to interact with client and one should implement
* a state machine here for full compatibility. But we only
* show a demonstration ftp server and i do my best to
* simplify it. Base on this skeleton, you can write a
* full-funtional ftp server if you like. ;-)
*/
while (1) {
buflen = cuftpd_recv_msg(connfd, buf, sizeof(buf));
if (buflen < 0) {
CUFTPD_DEBUG("cuftpd_recv_msg() failed: %s\n", strerror(errno));
err = CUFTPD_ERR;
break;
}
if (buflen == 0)
/* this means client launch a active close */
break;
buf[buflen] = '\0';
cuftpd_do_request(connfd, buf);
/*
* The negative return value from cuftpd_do_request
* should not cause the breaking of ctrl connection.
* Only when the client send QUIT cmd, we exit and
* launch a active close.
*/
if (cuftpd_quit_flag)
break;
}
close(connfd);
CUFTPD_DEBUG("Close the ctrl connection OK%s", "\n");
return err;
}
static int cuftpd_do_loop(int listenfd)
{
int connfd;
int pid;
while (1) {
CUFTPD_DEBUG("Server ready, wait client's connection...%s", "\n");
connfd = accept(listenfd, NULL, NULL);
if (connfd < 0) {
CUFTPD_DEBUG("accept() failed: %s\n", strerror(errno));
continue;
}
if (cuftpd_debug_on) {
struct sockaddr_in cliaddr;
int len = sizeof(cliaddr);
getpeername(connfd, (struct sockaddr*)&cliaddr, &len);
CUFTPD_DEBUG("accept a conn from %s:%d\n",
inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
}
if ((pid = fork()) < 0) {
CUFTPD_DEBUG("fork() failed: %s\n", strerror(errno));
close(connfd);
continue;
}
if (pid > 0) {
/* parent */
close(connfd);
cuftpd_cur_child_num++;
continue;
}
/* child */
close(listenfd);
signal(SIGCHLD, SIG_IGN);
if (cuftpd_ctrl_conn_handler(connfd) != CUFTPD_OK)
exit(-1);
exit(0);
}
return CUFTPD_OK;
}
int main(int argc, char *argv[])
{
int listenfd;
cuftpd_parse_args(argc, argv);
cuftpd_init();
listenfd = cuftpd_create_srv();
if (listenfd >= 0)
cuftpd_do_loop(listenfd);
exit(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -