summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-10-11 00:48:04 +0800
committerLAN-TW <lantw44@gmail.com>2013-10-11 00:48:04 +0800
commit236872fdce2883ab8ee76a44305134c9980b2af3 (patch)
tree7c2078226a2d1b077675947c065a489c64623a0c
parentaf7cf53111bb9784a04e16440ef1f003a29db8d3 (diff)
downloadsp2013-236872fdce2883ab8ee76a44305134c9980b2af3.tar.gz
sp2013-236872fdce2883ab8ee76a44305134c9980b2af3.tar.zst
sp2013-236872fdce2883ab8ee76a44305134c9980b2af3.zip
HW1: 偵測重複檔案並避免被 SIGPIPE 終止
-rw-r--r--hw1/common.c85
-rw-r--r--hw1/common.h29
-rw-r--r--hw1/main.c49
-rw-r--r--hw1/proc_r.c18
-rw-r--r--hw1/proc_w.c8
-rw-r--r--hw1/server.c124
-rw-r--r--hw1/server.h21
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 */
diff --git a/hw1/main.c b/hw1/main.c
index 95bc5c7..80298ac 100644
--- a/hw1/main.c
+++ b/hw1/main.c
@@ -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);