diff options
author | LAN-TW <lantw44@gmail.com> | 2013-10-13 01:11:41 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-10-13 01:11:41 +0800 |
commit | d2158089e2e38e8b665535799c1c3643d65087ff (patch) | |
tree | a6fbf0d35b400a63b4e91931fbe9ff1fb0538216 | |
parent | ad2f9c452b89a832676f9ffe2026c5758c108060 (diff) | |
download | sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.tar sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.tar.gz sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.tar.bz2 sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.tar.lz sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.tar.xz sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.tar.zst sp2013-d2158089e2e38e8b665535799c1c3643d65087ff.zip |
HW1: write_server 大致完成,通過所有助教提供的測資
-rw-r--r-- | hw1/main.c | 84 | ||||
-rw-r--r-- | hw1/proc.h | 8 | ||||
-rw-r--r-- | hw1/proc_r.c | 22 | ||||
-rw-r--r-- | hw1/proc_w.c | 208 | ||||
-rw-r--r-- | hw1/server.c | 10 | ||||
-rw-r--r-- | hw1/server.h | 5 |
6 files changed, 280 insertions, 57 deletions
@@ -5,8 +5,68 @@ #include <signal.h> #include <stdio.h> #include <string.h> +#include <sys/select.h> +#include <sys/time.h> #include <unistd.h> +volatile sig_atomic_t proc_message_request; +volatile sig_atomic_t proc_quit_request; + +static void proc_message_request_setter (int signo) { + proc_message_request = 1; +} + +static void proc_quit_request_setter (int signo) { + proc_quit_request = 1; +} + +static void message_cb (server* svr, request* req, int maxfd) { + putchar ('\n'); + + printf ( + "Dump server information ...\n" + " Server hostname: %s\n" + " Server port: %hu\n" + " Server is listening on fd %d\n", + svr->hostname, svr->port, svr->listen_fd); + + puts ("Dump request table ..."); + for (int i = 0; i < maxfd; i++) { + if (req[i].active) { + printf ( + " Client %d hostname: %s\n" + " Client %d filename: %s\n" + " Client %d filename done: %s\n" + " Client %d transfer started: %s\n", + i, req[i].host, + i, req[i].filename, + i, req[i].header_done ? "true" : "false", + i, req[i].header_accept ? "true" : "false"); + } + } + + puts ("Dump file table ..."); + for (int i = 0; i < maxfd; i++) { + if (svr->file_table->flist[i].active) { + printf ( + " Entry %d reference count: %d\n" + " Entry %d device: %llu\n" + " Entry %d inode: %llu\n" + " Entry %d file descriptors:", + i, svr->file_table->flist[i].ref_count, + i, (unsigned long long)svr->file_table->flist[i].fdev, + i, (unsigned long long)svr->file_table->flist[i].fino, i); + for (int j = 0; j < maxfd; j++) { + if (FD_ISSET (j, &svr->file_table->flist[i].fset)) + printf (" %d", j); + } + putchar ('\n'); + } + } + + puts ("Type Ctrl-\\ to terminate the server\n"); + proc_message_request = 0; +} int main(int argc, char** argv) { if (argc != 2) { @@ -15,12 +75,16 @@ int main(int argc, char** argv) { } // Setup signal handlers - struct sigaction pipe_action = { + struct sigaction signal_action = { .sa_handler = SIG_IGN, .sa_flags = 0 }; - sigemptyset(&pipe_action.sa_mask); - sigaction(SIGPIPE, &pipe_action, NULL); + sigemptyset (&signal_action.sa_mask); + sigaction (SIGPIPE, &signal_action, NULL); + signal_action.sa_handler = proc_message_request_setter; + sigaction (SIGINT, &signal_action, NULL); + signal_action.sa_handler = proc_quit_request_setter; + sigaction (SIGQUIT, &signal_action, NULL); // Get file descripter table size int maxfd = getdtablesize(); @@ -43,8 +107,20 @@ int main(int argc, char** argv) { printf("\nstarting on %.80s, port %d, fd %d, maxfd %d ...\n", svr.hostname, svr.port, svr.listen_fd, maxfd); - while (procconn(&svr, requestP, maxfd)); + while (procconn(&svr, requestP, maxfd, + (struct timeval) { 1, 0 }, message_cb)); + + printf("\nquitting...\n"); + + for (int i = 0; i < maxfd; i++) { + if (requestP[i].filename != NULL) { + free (requestP[i].filename); + requestP[i].filename = NULL; + } + } free(requestP); + server_free(&svr); + return 0; } @@ -3,7 +3,13 @@ #include "server.h" #include <stdbool.h> +#include <signal.h> -bool procconn(server* svr, request* requestP, int maxfd); +extern volatile sig_atomic_t proc_message_request; +extern volatile sig_atomic_t proc_quit_request; + +typedef void (*svr_msg)(server* svr, request* req, int maxfd); +bool procconn (server* svr, request* req, int maxfd, + struct timeval timeout, svr_msg message_cb); #endif /* SP_HW1_PROC_H */ diff --git a/hw1/proc_r.c b/hw1/proc_r.c index 888a1dc..301f4e2 100644 --- a/hw1/proc_r.c +++ b/hw1/proc_r.c @@ -15,15 +15,26 @@ #include <sys/types.h> #include <unistd.h> -bool procconn(server* svr, request* req, int maxfd){ +bool procconn(server* svr, request* req, int maxfd, + struct timeval timeout, svr_msg message_cb) { + fd_set rset = svr->readfds; fd_set wset = svr->writefds; fd_set eset = svr->exceptfds; - struct timeval timeout = { 1, 0 }; + struct timeval select_timeout = timeout; int rval; - if (select (maxfd, &rset, &wset, &eset, &timeout) < 0) { - perror ("select"); + rval = select (maxfd, &rset, &wset, &eset, &select_timeout); + + if (proc_message_request) + (*message_cb)(svr, req, maxfd); + + if (proc_quit_request) + return false; + + if (rval < 0) { + if (errno != EINTR) + perror ("select"); return true; } @@ -60,7 +71,8 @@ bool procconn(server* svr, request* req, int maxfd){ } else { rval = request_read(&req[i]); if (rval <= 0) { - request_msg (&req[i], "socket read: %s", strerror (errno)); + request_msg (&req[i], "socket read: %s", + rval ? strerror (errno) : "connection closed"); request_free (&req[i], svr); } else { if (req[i].header_done) { diff --git a/hw1/proc_w.c b/hw1/proc_w.c index 6220e67..450981b 100644 --- a/hw1/proc_w.c +++ b/hw1/proc_w.c @@ -12,58 +12,174 @@ #include <sys/types.h> #include <unistd.h> -bool procconn(server* svr, request* requestP, int maxfd){ - int ret; - - struct sockaddr_in cliaddr; // used by accept() - int clilen; - - int conn_fd; // fd for a new connection with client - int file_fd; // fd for file that we open for reading - - // TODO: Add IO multiplexing - // Check new connection - clilen = sizeof(cliaddr); - conn_fd = accept(svr->listen_fd, (struct sockaddr*)&cliaddr, (socklen_t*)&clilen); - if (conn_fd < 0) { - if (errno == EINTR || errno == EAGAIN) - return true; // try again - if (errno == ENFILE) { - (void) fprintf(stderr, "out of file descriptor table ... (maxconn %d)\n", maxfd); - return false; - } - e_err_exit("accept"); - } - requestP[conn_fd].conn_fd = conn_fd; - strcpy(requestP[conn_fd].host, inet_ntoa(cliaddr.sin_addr)); - fprintf(stderr, "getting a new request... fd %d from %s\n", conn_fd, requestP[conn_fd].host); +bool procconn(server* svr, request* req, int maxfd, + struct timeval timeout, svr_msg message_cb) { + + fd_set rset = svr->readfds; + fd_set wset = svr->writefds; + fd_set eset = svr->exceptfds; + struct timeval select_timeout = timeout; + int rval; + + rval = select (maxfd, &rset, &wset, &eset, &select_timeout); + + if (proc_message_request) + (*message_cb)(svr, req, maxfd); - file_fd = -1; + if (proc_quit_request) + return false; - do { - ret = request_read(&requestP[conn_fd]); - if (ret < 0) { - fprintf(stderr, "bad request from %s\n", requestP[conn_fd].host); + if (rval < 0) { + if (errno != EINTR) + perror ("select"); + return true; + } + + for (int i = 0; i < maxfd; i++) { + if (!FD_ISSET (i, &rset)) continue; + + if (i == svr->listen_fd) { + struct sockaddr_in client_addr; + int client_len = sizeof (client_addr); + int conn_fd = accept (i, + (struct sockaddr*)&client_addr, (socklen_t*)&client_len); + if (conn_fd < 0) { + switch (errno) { + case EINTR: + case EAGAIN: + continue; + case EMFILE: + case ENFILE: + fprintf (stderr, "Too many open file ... " + "(maxfd %d)\n", maxfd); + continue; + default: + perror ("accept"); + continue; + } + } else { + req[conn_fd].conn_fd = conn_fd; + req[conn_fd].active = true; + strcpy(req[conn_fd].host, inet_ntoa(client_addr.sin_addr)); + request_msg (&req[conn_fd], "accepted, waiting for filename"); + FD_SET (conn_fd, &(svr->readfds)); + } + } else { + if (!req[i].buf_len) { + rval = request_read(&req[i]); + if (rval <= 0) { + request_msg (&req[i], "socket read: %s", + rval ? strerror (errno) : "connection closed"); + request_free (&req[i], svr); + continue; + } else { + if (!req[i].header_done) { + continue; + } else { + if (!req[i].header_accept) { + FD_CLR (req[i].conn_fd, &(svr->readfds)); + FD_SET (req[i].conn_fd, &(svr->writefds)); + } + } + } + } + if (req[i].header_accept) { + do { + ssize_t this_written = write (req[i].file_fd, + req[i].buf + req[i].buf_set, req[i].buf_len); + if (this_written < 0) { + request_msg (&req[i], "write: %s", strerror (errno)); + request_free (&req[i], svr); + break; + } + req[i].buf_set += this_written; + req[i].buf_len -= this_written; + } while (req[i].buf_len > 0); + req[i].buf_set = 0; + } } - // requestP[conn_fd]->filename is guaranteed to be successfully set. - if (file_fd == -1) { - // open the file here. - fprintf(stderr, "Opening file [%s]\n", requestP[conn_fd].filename); - // TODO: Add lock - // TODO: check if the request should be rejected. - write(requestP[conn_fd].conn_fd, svr->accept_hdr, SVR_ACCEPT_HDR_LEN); - file_fd = open(requestP[conn_fd].filename, O_WRONLY | O_CREAT | O_TRUNC, + } + + for (int i = 0; i < maxfd; i++) { + if (!FD_ISSET (i, &wset)) + continue; + if (i == svr->listen_fd) + continue; + + if (req[i].header_done) { + if (!req[i].header_accept) { + req[i].file_fd = open (req[i].filename, + O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + request_msg (&req[i], "open %s%s", + req[i].file_fd < 0 ? "error: " : "done", + req[i].file_fd < 0 ? strerror(errno) : ""); + if (req[i].file_fd < 0) { + write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); + request_msg (&req[i], "REJECT sent"); + request_free (&req[i], svr); + continue; + } + + struct stat file_stat; + rval = fstat (req[i].file_fd, &file_stat); + request_msg (&req[i], "fstat %s%s", + req[i].file_fd < 0 ? "error: " : "done", + req[i].file_fd < 0 ? strerror(errno) : ""); + if (req[i].file_fd < 0) { + write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); + request_msg (&req[i], "REJECT sent"); + request_free (&req[i], svr); + continue; + } + if (ftab_search ( + svr->file_table, file_stat.st_dev, file_stat.st_ino)) + { + write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); + request_msg (&req[i], "REJECT sent"); + request_free (&req[i], svr); + continue; + } + + req[i].file_info = ftab_insert ( + svr->file_table, + file_stat.st_dev, + file_stat.st_ino, + req[i].file_fd); + + struct flock lock_info = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0 + }; + rval = fcntl (req[i].file_fd, F_SETLK, &lock_info); + request_err (&req[i], "lock", rval); + if (rval < 0) { + write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); + request_msg (&req[i], "REJECT sent"); + request_free (&req[i], svr); + continue; + } + + rval = ftruncate (req[i].file_fd, 0); + request_err (&req[i], "ftruncate", rval); + if (rval < 0) { + write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); + request_msg (&req[i], "REJECT sent"); + request_free (&req[i], svr); + continue; + } + + request_msg (&req[i], "ACCEPT sent"); + write (req[i].conn_fd, svr->accept_hdr, SVR_ACCEPT_HDR_LEN); + req[i].header_accept = true; + FD_CLR (req[i].conn_fd, &(svr->writefds)); + FD_SET (req[i].conn_fd, &(svr->readfds)); + } } - if (ret == 0) break; - write(file_fd, requestP[conn_fd].buf, requestP[conn_fd].buf_len); - } while (ret > 0); - fprintf(stderr, "Done writing file [%s]\n", requestP[conn_fd].filename); - - if (file_fd >= 0) close(file_fd); - close(requestP[conn_fd].conn_fd); - request_free(&requestP[conn_fd], NULL); + } return true; } diff --git a/hw1/server.c b/hw1/server.c index b65bb10..b416153 100644 --- a/hw1/server.c +++ b/hw1/server.c @@ -62,6 +62,10 @@ void server_init(server* svr, unsigned short port, int maxfd) { svr->file_table = ftab_create (maxfd); } +void server_free(server* svr) { + ftab_free (svr->file_table); +} + void request_init(request* reqP) { reqP->conn_fd = -1; reqP->buf_set = 0; @@ -136,3 +140,9 @@ void request_msg (request* reqP, const char* format, ...) { putchar ('\n'); va_end (ap); } + +void request_err (request* reqP, const char* key, int chkrval) { + request_msg (reqP, "%s %s%s", key, + chkrval < 0 ? "error: " : "done", + chkrval < 0 ? strerror(errno) : ""); +} diff --git a/hw1/server.h b/hw1/server.h index d519f4d..5b4d93b 100644 --- a/hw1/server.h +++ b/hw1/server.h @@ -44,6 +44,9 @@ typedef struct { // initailize a server, exit for error void server_init (server* svr, unsigned short port, int maxfd); +// free resources used by a server +void server_free (server* svr); + // initailize a request instance void request_init (request* reqP); @@ -58,6 +61,6 @@ void request_free (request* reqP, server* svr); // -1: client connection error int request_read (request* reqP); void request_msg (request* reqP, const char* format, ...); - +void request_err (request* reqP, const char* key, int chkrval); #endif /* SP_HW1_SERVER_H */ |