summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-10-13 01:11:41 +0800
committerLAN-TW <lantw44@gmail.com>2013-10-13 01:11:41 +0800
commitd2158089e2e38e8b665535799c1c3643d65087ff (patch)
treea6fbf0d35b400a63b4e91931fbe9ff1fb0538216
parentad2f9c452b89a832676f9ffe2026c5758c108060 (diff)
downloadsp2013-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.c84
-rw-r--r--hw1/proc.h8
-rw-r--r--hw1/proc_r.c22
-rw-r--r--hw1/proc_w.c208
-rw-r--r--hw1/server.c10
-rw-r--r--hw1/server.h5
6 files changed, 280 insertions, 57 deletions
diff --git a/hw1/main.c b/hw1/main.c
index 6aad0c2..fb152c5 100644
--- a/hw1/main.c
+++ b/hw1/main.c
@@ -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;
}
diff --git a/hw1/proc.h b/hw1/proc.h
index 49f58e1..35654a3 100644
--- a/hw1/proc.h
+++ b/hw1/proc.h
@@ -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 */