⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cuftpd.c.c

📁 A very simple ftp server s source code for demonstration. * It supports PASV/PORT modes and followi
💻 C
📖 第 1 页 / 共 3 页
字号:
        }
        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 + -