diff options
author | LAN-TW <lantw44@gmail.com> | 2013-10-11 00:48:04 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-10-11 00:48:04 +0800 |
commit | 236872fdce2883ab8ee76a44305134c9980b2af3 (patch) | |
tree | 7c2078226a2d1b077675947c065a489c64623a0c | |
parent | af7cf53111bb9784a04e16440ef1f003a29db8d3 (diff) | |
download | sp2013-236872fdce2883ab8ee76a44305134c9980b2af3.tar.gz sp2013-236872fdce2883ab8ee76a44305134c9980b2af3.tar.zst sp2013-236872fdce2883ab8ee76a44305134c9980b2af3.zip |
HW1: 偵測重複檔案並避免被 SIGPIPE 終止
-rw-r--r-- | hw1/common.c | 85 | ||||
-rw-r--r-- | hw1/common.h | 29 | ||||
-rw-r--r-- | hw1/main.c | 49 | ||||
-rw-r--r-- | hw1/proc_r.c | 18 | ||||
-rw-r--r-- | hw1/proc_w.c | 8 | ||||
-rw-r--r-- | hw1/server.c | 124 | ||||
-rw-r--r-- | hw1/server.h | 21 |
7 files changed, 230 insertions, 104 deletions
diff --git a/hw1/common.c b/hw1/common.c index 461c777..37f71e2 100644 --- a/hw1/common.c +++ b/hw1/common.c @@ -1,19 +1,86 @@ #include "common.h" +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <sys/select.h> -void* e_malloc(size_t size) { - void* ptr; +void* e_malloc (size_t size) { + void* ptr; - ptr = malloc(size); - if (ptr == NULL) - e_err_exit("out of memory"); + ptr = malloc (size); + if (ptr == NULL) + e_err_exit ("out of memory"); - return ptr; + return ptr; } -void e_err_exit(const char* a) { - perror(a); - exit(1); +void e_err_exit (const char* a) { + perror (a); + exit (1); +} + +ftab* ftab_create (int maxfd) { + ftab* ft = e_malloc (sizeof (ftab)); + ft->maxfd = maxfd; + ft->flist = e_malloc (sizeof (fnode) * maxfd); + memset (ft->flist, 0, sizeof (fnode) * maxfd); + return ft; +} + +fnode* ftab_insert (ftab* ft, dev_t fdev, ino_t fino, int fd) { + fnode *search = ftab_search (ft, fdev, fino); + if (search == NULL) { + for (int i = 0; i < ft->maxfd; i++) { + if (!(ft->flist[i].active)) { + ft->flist[i].active = true; + ft->flist[i].ref_count = 0; + ft->flist[i].fdev = fdev; + ft->flist[i].fino = fino; + FD_ZERO (&(ft->flist[i].fset)); + fnode_ref (&(ft->flist[i]), fd); + return &(ft->flist[i]); + } + } + return NULL; + } else { + fnode_ref (search, fd); + return search; + } +} + +fnode* ftab_search (ftab* ft, dev_t fdev, ino_t fino) { + for (int i = 0; i < ft->maxfd; i++) { + if (ft->flist[i].active && + ft->flist[i].fdev == fdev && + ft->flist[i].fino == fino) + { + return &(ft->flist[i]); + } + } + return NULL; +} + +void ftab_free (ftab* ft) { + free (ft->flist); + free (ft); +} + +fnode* fnode_ref (fnode* fn, int fd) { + if (fd >= 0 && !FD_ISSET (fd, &fn->fset)) { + fn->ref_count++; + FD_SET (fd, &fn->fset); + } + return fn; +} + +void fnode_unref (fnode* fn, ftab* ft) { + fn->ref_count--; + if (fn->ref_count <= 0) { + for (int i = 0; i < ft->maxfd; i++) + if (FD_ISSET (i, &fn->fset)) + close (i); + fn->active = false; + } } diff --git a/hw1/common.h b/hw1/common.h index 9db8079..b580098 100644 --- a/hw1/common.h +++ b/hw1/common.h @@ -1,9 +1,34 @@ #ifndef SP_HW1_COMMON_H #define SP_HW1_COMMON_H +#include <stdbool.h> #include <stdlib.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> -void* e_malloc(size_t size); -void e_err_exit(const char* a); +void* e_malloc (size_t size); +void e_err_exit (const char* a); + +typedef struct { + bool active; + int ref_count; + fd_set fset; + dev_t fdev; + ino_t fino; +} fnode; + +typedef struct { + int maxfd; + fnode* flist; +} ftab; + +ftab* ftab_create (int maxfd); +fnode* ftab_insert (ftab* ft, dev_t fdev, ino_t fino, int fd); +fnode* ftab_search (ftab* ft, dev_t fdev, ino_t fino); +void ftab_free (ftab* ft); +fnode* fnode_ref (fnode* fn, int fd); +void fnode_unref (fnode* fn, ftab* ft); #endif /* SP_HW1_COMMON_H */ @@ -2,6 +2,7 @@ #include "server.h" #include "proc.h" +#include <signal.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -10,33 +11,41 @@ request* requestP = NULL; // point to a list of requests int maxfd; // size of open file descriptor table, size of request list int main(int argc, char** argv) { - int i; - // Parse args. - if (argc != 2) { - fprintf(stderr, "usage: %s [port]\n", argv[0]); - exit(1); - } + if (argc != 2) { + fprintf(stderr, "usage: %s [port]\n", argv[0]); + exit(1); + } - // Initialize server - server_init((unsigned short) atoi(argv[1])); + // Setup signal handlers + struct sigaction pipe_action = { + .sa_handler = SIG_IGN, + .sa_flags = 0 + }; + sigemptyset(&pipe_action.sa_mask); + sigaction(SIGPIPE, &pipe_action, NULL); - // Get file descripter table size and initize request table - maxfd = getdtablesize(); - requestP = (request*) e_malloc(sizeof(request) * maxfd); + // Get file descripter table size + maxfd = getdtablesize(); - for (i = 0; i < maxfd; i++) - request_init(&requestP[i]); + // Initialize server + server_init((unsigned short) atoi(argv[1]), maxfd); - requestP[svr.listen_fd].conn_fd = svr.listen_fd; - strcpy(requestP[svr.listen_fd].host, svr.hostname); + // Initialize request table + requestP = (request*) e_malloc(sizeof(request) * maxfd); - // Loop for handling connections - fprintf(stderr, + for (int i = 0; i < maxfd; i++) + request_init(&requestP[i]); + + requestP[svr.listen_fd].conn_fd = svr.listen_fd; + strcpy(requestP[svr.listen_fd].host, svr.hostname); + + // Loop for handling connections + fprintf(stderr, "\nstarting on %.80s, port %d, fd %d, maxconn %d...\n", svr.hostname, svr.port, svr.listen_fd, maxfd); - while (procconn(&svr, requestP, maxfd)); + while (procconn(&svr, requestP, maxfd)); - free(requestP); - return 0; + free(requestP); + return 0; } diff --git a/hw1/proc_r.c b/hw1/proc_r.c index 82b6822..19dce78 100644 --- a/hw1/proc_r.c +++ b/hw1/proc_r.c @@ -10,6 +10,7 @@ #include <string.h> #include <sys/select.h> #include <sys/socket.h> +#include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> @@ -93,6 +94,23 @@ bool procconn(server* svr, request* req, int maxfd){ continue; } + struct stat file_stat; + rval = fstat (req[i].file_fd, &file_stat); + fprintf (stderr, "fd %d from %s: fstat %s %s%s\n", + i, req[i].host, req[i].filename, + 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_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_RDLCK, .l_whence = SEEK_SET, diff --git a/hw1/proc_w.c b/hw1/proc_w.c index 394a177..6220e67 100644 --- a/hw1/proc_w.c +++ b/hw1/proc_w.c @@ -15,11 +15,11 @@ bool procconn(server* svr, request* requestP, int maxfd){ int ret; - struct sockaddr_in cliaddr; // used by accept() - int clilen; + 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 + 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 diff --git a/hw1/server.c b/hw1/server.c index 9c3178b..b8392ba 100644 --- a/hw1/server.c +++ b/hw1/server.c @@ -21,28 +21,28 @@ server svr; // server // You don't need to know how the following codes are working -void server_init(unsigned short port) { - struct sockaddr_in servaddr; - int val, flags; +void server_init(unsigned short port, int maxfd) { + struct sockaddr_in servaddr; + int val, flags; - gethostname(svr.hostname, sizeof(svr.hostname)); - svr.port = port; + gethostname(svr.hostname, sizeof(svr.hostname)); + svr.port = port; - svr.listen_fd = socket(AF_INET, SOCK_STREAM, 0); - if (svr.listen_fd < 0) + svr.listen_fd = socket(AF_INET, SOCK_STREAM, 0); + if (svr.listen_fd < 0) e_err_exit("socket"); - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(port); - val = 1; - if (setsockopt(svr.listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) - e_err_exit("setsockopt"); - if (bind(svr.listen_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) - e_err_exit("bind"); - if (listen(svr.listen_fd, 1024) < 0) - e_err_exit("listen"); + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(port); + val = 1; + if (setsockopt(svr.listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) + e_err_exit("setsockopt"); + if (bind(svr.listen_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) + e_err_exit("bind"); + if (listen(svr.listen_fd, 1024) < 0) + e_err_exit("listen"); strcpy(svr.accept_hdr, "ACCEPT\n"); strcpy(svr.reject_hdr, "REJECT\n"); @@ -58,65 +58,71 @@ void server_init(unsigned short port) { return; } fcntl(svr.listen_fd, F_SETFL, flags | O_NONBLOCK); + + svr.file_table = ftab_create (maxfd); } void request_init(request* reqP) { - reqP->conn_fd = -1; + reqP->conn_fd = -1; reqP->buf_set = 0; - reqP->buf_len = 0; - reqP->filename = NULL; - reqP->file_fd = -1; - reqP->file_dev = 0; - reqP->file_ino = 0; + reqP->buf_len = 0; + reqP->filename = NULL; + reqP->file_fd = -1; + reqP->file_info = NULL; reqP->active = false; - reqP->header_done = false; + reqP->header_done = false; reqP->header_accept = false; } void request_free(request* reqP, server* svr) { - if (reqP->filename != NULL) { - free(reqP->filename); - reqP->filename = NULL; - } + if (reqP->filename != NULL) { + free(reqP->filename); + reqP->filename = NULL; + } + + shutdown (reqP->conn_fd, SHUT_RDWR); close (reqP->conn_fd); - close (reqP->file_fd); + + if (reqP->file_info != NULL) + fnode_unref (reqP->file_info, svr->file_table); + if (svr != NULL) { FD_CLR (reqP->conn_fd, &(svr->readfds)); FD_CLR (reqP->conn_fd, &(svr->writefds)); FD_CLR (reqP->conn_fd, &(svr->exceptfds)); } - request_init(reqP); + request_init(reqP); } int request_read(request* reqP) { - int r; - char buf[SVR_BUFFER_SIZE]; - - // Read in request from client - r = read(reqP->conn_fd, buf, sizeof(buf)); - if (r < 0) return -1; - if (r == 0) return 0; - if (!reqP->header_done) { - char* p1 = strstr(buf, "\r\n"); - int newline_len = 2; - // be careful that in Windows, line ends with \r\n - if (p1 == NULL) { - p1 = strchr(buf, '\n'); - newline_len = 1; + int r; + char buf[SVR_BUFFER_SIZE]; + + // Read in request from client + r = read(reqP->conn_fd, buf, sizeof(buf)); + if (r < 0) return -1; + if (r == 0) return 0; + if (!reqP->header_done) { + char* p1 = strstr(buf, "\r\n"); + int newline_len = 2; + // be careful that in Windows, line ends with \r\n + if (p1 == NULL) { + p1 = strchr(buf, '\n'); + newline_len = 1; assert (p1 != NULL); - } - size_t len = p1 - buf + 1; - reqP->filename = (char*)e_malloc(len); - memmove(reqP->filename, buf, len - 1); - reqP->filename[len - 1] = '\0'; - p1 += newline_len; - reqP->buf_len = r - (p1 - buf); - memmove(reqP->buf, p1, reqP->buf_len); - reqP->header_done = true; - } else { - reqP->buf_len = r; - memmove(reqP->buf, buf, r); - } - return 1; + } + size_t len = p1 - buf + 1; + reqP->filename = (char*)e_malloc(len); + memmove(reqP->filename, buf, len - 1); + reqP->filename[len - 1] = '\0'; + p1 += newline_len; + reqP->buf_len = r - (p1 - buf); + memmove(reqP->buf, p1, reqP->buf_len); + reqP->header_done = true; + } else { + reqP->buf_len = r; + memmove(reqP->buf, buf, r); + } + return 1; } diff --git a/hw1/server.h b/hw1/server.h index 7720b5c..0819dea 100644 --- a/hw1/server.h +++ b/hw1/server.h @@ -1,9 +1,10 @@ #ifndef SP_HW1_SERVER_H #define SP_HW1_SERVER_H +#include "common.h" + #include <stdlib.h> #include <sys/select.h> -#include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> @@ -11,18 +12,19 @@ #define SVR_ACCEPT_HDR_LEN 8 #define SVR_REJECT_HDR_LEN 8 -#define SVR_HOSTNAME_MAX 512 -#define SVR_BUFFER_SIZE 512 +#define SVR_HOSTNAME_MAX 512 +#define SVR_BUFFER_SIZE 512 typedef struct { - char hostname[SVR_HOSTNAME_MAX]; // server's hostname - unsigned short port; // port to listen - int listen_fd; // fd to wait for a new connection + char hostname[SVR_HOSTNAME_MAX]; // server's hostname + unsigned short port; // port to listen + int listen_fd; // fd to wait for a new connection char accept_hdr[SVR_ACCEPT_HDR_LEN + 1]; char reject_hdr[SVR_REJECT_HDR_LEN + 1]; fd_set readfds; fd_set writefds; fd_set exceptfds; + ftab* file_table; } server; typedef struct { @@ -32,9 +34,8 @@ typedef struct { size_t buf_set; size_t buf_len; // bytes used by buf char* filename; // filename set in header, end with '\0'. - int file_fd; // fd to read or write local file - dev_t file_dev; - ino_t file_ino; + int file_fd; // fd to read or write local file + fnode* file_info; int active : 1; // whether this conn_fd is active int header_done : 1; // used by request_read to know if the header is done int header_accept : 1; // used by procconn to know if ACCEPT/REJECT is sent @@ -43,7 +44,7 @@ typedef struct { extern server svr; // server // initailize a server, exit for error -void server_init(unsigned short port); +void server_init(unsigned short port, int maxfd); // initailize a request instance void request_init(request* reqP); |