summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-10-08 18:20:04 +0800
committerLAN-TW <lantw44@gmail.com>2013-10-08 18:20:04 +0800
commit56ddfdf237610056f16dab036eecf912a1a0f540 (patch)
tree61f0f372c458ce4d76f703195f7d9452f610902f
parent8ecda287786e0ebc1d0061c6e6895e694820af45 (diff)
downloadsp2013-56ddfdf237610056f16dab036eecf912a1a0f540.tar.gz
sp2013-56ddfdf237610056f16dab036eecf912a1a0f540.tar.zst
sp2013-56ddfdf237610056f16dab036eecf912a1a0f540.zip
HW1: Refactor imported code
-rw-r--r--hw1/Makefile42
-rw-r--r--hw1/common.c19
-rw-r--r--hw1/common.h9
-rw-r--r--hw1/main.c42
-rw-r--r--hw1/proc.h9
-rw-r--r--hw1/proc_r.c76
-rw-r--r--hw1/proc_w.c69
-rw-r--r--hw1/server.c243
-rw-r--r--hw1/server.h46
9 files changed, 350 insertions, 205 deletions
diff --git a/hw1/Makefile b/hw1/Makefile
index d3180e5..fd93a70 100644
--- a/hw1/Makefile
+++ b/hw1/Makefile
@@ -1,6 +1,40 @@
-all: server.c
- gcc server.c -o write_server
- gcc server.c -D READ_SERVER -o read_server
+# Programs
+CC= c99
+RM= rm -f
+# Internal flags
+SP_CFLAGS= -Wall -pipe -O2 -D_POSIX_C_SOURCE=200809L $(CFLAGS)
+SP_LIBS= $(LDFLAGS)
+
+# Let user to override these variables
+CFLAGS=
+LDFLAGS=
+
+# Build dependencies
+all_tasks= read_server write_server
+read_server_objs= common.o server.o main.o proc_r.o
+write_server_objs= common.o server.o main.o proc_w.o
+
+# Phony target
+.PHONY: all clean auto
+all: $(all_tasks)
+auto: configure
clean:
- rm -f read_server write_server
+ $(RM) $(all_tasks) $(read_server_objs) $(write_server_objs)
+
+# Suffix rules
+.SUFFIXES: .c.o
+.c.o:
+ $(CC) $(SP_CFLAGS) -c $< -o $@
+
+# Real rules
+configure: configure.ac Makefile.am
+ autoreconf -i
+ @echo "The `configure' script is created, and you can run it now."
+ @echo "WARNING: this Makefile will be overwritten by the configure script."
+
+read_server: $(read_server_objs)
+ $(CC) $(SP_CFLAGS) $(read_server_objs) -o $@ $(SP_LDFLAGS)
+
+write_server: $(write_server_objs)
+ $(CC) $(SP_CFLAGS) $(write_server_objs) -o $@ $(SP_LDFLAGS)
diff --git a/hw1/common.c b/hw1/common.c
new file mode 100644
index 0000000..461c777
--- /dev/null
+++ b/hw1/common.c
@@ -0,0 +1,19 @@
+#include "common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void* e_malloc(size_t size) {
+ void* ptr;
+
+ ptr = malloc(size);
+ if (ptr == NULL)
+ e_err_exit("out of memory");
+
+ return ptr;
+}
+
+void e_err_exit(const char* a) {
+ perror(a);
+ exit(1);
+}
diff --git a/hw1/common.h b/hw1/common.h
new file mode 100644
index 0000000..9db8079
--- /dev/null
+++ b/hw1/common.h
@@ -0,0 +1,9 @@
+#ifndef SP_HW1_COMMON_H
+#define SP_HW1_COMMON_H
+
+#include <stdlib.h>
+
+void* e_malloc(size_t size);
+void e_err_exit(const char* a);
+
+#endif /* SP_HW1_COMMON_H */
diff --git a/hw1/main.c b/hw1/main.c
new file mode 100644
index 0000000..95bc5c7
--- /dev/null
+++ b/hw1/main.c
@@ -0,0 +1,42 @@
+#include "common.h"
+#include "server.h"
+#include "proc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+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);
+ }
+
+ // Initialize server
+ server_init((unsigned short) atoi(argv[1]));
+
+ // Get file descripter table size and initize request table
+ maxfd = getdtablesize();
+ requestP = (request*) e_malloc(sizeof(request) * maxfd);
+
+ for (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));
+
+ free(requestP);
+ return 0;
+}
diff --git a/hw1/proc.h b/hw1/proc.h
new file mode 100644
index 0000000..49f58e1
--- /dev/null
+++ b/hw1/proc.h
@@ -0,0 +1,9 @@
+#ifndef SP_HW1_PROC_H
+#define SP_HW1_PROC_H
+
+#include "server.h"
+#include <stdbool.h>
+
+bool procconn(server* svr, request* requestP, int maxfd);
+
+#endif /* SP_HW1_PROC_H */
diff --git a/hw1/proc_r.c b/hw1/proc_r.c
new file mode 100644
index 0000000..cdecb79
--- /dev/null
+++ b/hw1/proc_r.c
@@ -0,0 +1,76 @@
+#include "common.h"
+#include "proc.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#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
+ char buf[512];
+ int buf_len;
+
+ // 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 true;
+ }
+ 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);
+
+ file_fd = -1;
+
+ ret = request_read(&requestP[conn_fd]);
+ if (ret < 0) {
+ fprintf(stderr, "bad request from %s\n", requestP[conn_fd].host);
+ return true;
+ }
+ // 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_RDONLY, 0);
+ }
+
+ while (1) {
+ ret = read(file_fd, buf, sizeof(buf));
+ if (ret < 0) {
+ fprintf(stderr, "Error when reading file %s\n", requestP[conn_fd].filename);
+ break;
+ } else if (ret == 0) break;
+ write(requestP[conn_fd].conn_fd, buf, ret);
+ }
+ fprintf(stderr, "Done reading 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]);
+
+ return true;
+}
+
diff --git a/hw1/proc_w.c b/hw1/proc_w.c
new file mode 100644
index 0000000..7b13ed2
--- /dev/null
+++ b/hw1/proc_w.c
@@ -0,0 +1,69 @@
+#include "common.h"
+#include "proc.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#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);
+
+ file_fd = -1;
+
+ do {
+ ret = request_read(&requestP[conn_fd]);
+ if (ret < 0) {
+ fprintf(stderr, "bad request from %s\n", requestP[conn_fd].host);
+ continue;
+ }
+ // 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,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ }
+ 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]);
+
+ return true;
+}
diff --git a/hw1/server.c b/hw1/server.c
index d72e0ad..c503585 100644
--- a/hw1/server.c
+++ b/hw1/server.c
@@ -1,190 +1,66 @@
-#include <unistd.h>
+#include "server.h"
+#include "common.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <sys/socket.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#define ERR_EXIT(a) { perror(a); exit(1); }
-
-typedef struct {
- char hostname[512]; // server's hostname
- unsigned short port; // port to listen
- int listen_fd; // fd to wait for a new connection
-} server;
-
-typedef struct {
- char host[512]; // client's host
- int conn_fd; // fd to talk with client
- char buf[512]; // data sent by/to client
- size_t buf_len; // bytes used by buf
- // you don't need to change this.
- char* filename; // filename set in header, end with '\0'.
- int header_done; // used by handle_read to know if the header is read or not.
-} request;
+#include <sys/types.h>
+#include <unistd.h>
server svr; // server
-request* requestP = NULL; // point to a list of requests
-int maxfd; // size of open file descriptor table, size of request list
-
-const char* accept_header = "ACCEPT\n";
-const char* reject_header = "REJECT\n";
-
-// Forwards
-
-static void init_server(unsigned short port);
-// initailize a server, exit for error
-
-static void init_request(request* reqP);
-// initailize a request instance
-static void free_request(request* reqP);
-// free resources used by a request instance
-
-static int handle_read(request* reqP);
-// return 0: socket ended, request done.
-// return 1: success, message (without header) got this time is in reqP->buf with reqP->buf_len bytes. read more until got <= 0.
-// It's guaranteed that the header would be correctly set after the first read.
-// error code:
-// -1: client connection error
-
-int main(int argc, char** argv) {
- int i, 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
- char buf[512];
- int buf_len;
-
- // Parse args.
- if (argc != 2) {
- fprintf(stderr, "usage: %s [port]\n", argv[0]);
- exit(1);
- }
-
- // Initialize server
- init_server((unsigned short) atoi(argv[1]));
-
- // Get file descripter table size and initize request table
- maxfd = getdtablesize();
- requestP = (request*) malloc(sizeof(request) * maxfd);
- if (requestP == NULL) {
- ERR_EXIT("out of memory allocating all requests");
- }
- for (i = 0; i < maxfd; i++) {
- init_request(&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 (1) {
- // 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) continue; // try again
- if (errno == ENFILE) {
- (void) fprintf(stderr, "out of file descriptor table ... (maxconn %d)\n", maxfd);
- continue;
- }
- 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);
+// ======================================================================================================
+// You don't need to know how the following codes are working
- file_fd = -1;
- // We don't need a loop here in read server.
-#ifndef READ_SERVER
- do {
-#endif
- ret = handle_read(&requestP[conn_fd]);
- if (ret < 0) {
- fprintf(stderr, "bad request from %s\n", requestP[conn_fd].host);
- continue;
- }
- // 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, accept_header, sizeof(accept_header));
-#ifdef READ_SERVER
- file_fd = open(requestP[conn_fd].filename, O_RDONLY, 0);
-#else
- file_fd = open(requestP[conn_fd].filename, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
-#endif
- }
- if (ret == 0) break;
-#ifndef READ_SERVER
- 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);
-#endif
+void server_init(unsigned short port) {
+ struct sockaddr_in servaddr;
+ int tmp;
-#ifdef READ_SERVER
- while (1) {
- ret = read(file_fd, buf, sizeof(buf));
- if (ret < 0) {
- fprintf(stderr, "Error when reading file %s\n", requestP[conn_fd].filename);
- break;
- } else if (ret == 0) break;
- write(requestP[conn_fd].conn_fd, buf, ret);
- }
- fprintf(stderr, "Done reading file [%s]\n", requestP[conn_fd].filename);
-#endif
+ gethostname(svr.hostname, sizeof(svr.hostname));
+ svr.port = port;
- if (file_fd >= 0) close(file_fd);
- close(requestP[conn_fd].conn_fd);
- free_request(&requestP[conn_fd]);
- }
+ svr.listen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (svr.listen_fd < 0)
+ e_err_exit("socket");
- free(requestP);
- return 0;
+ memset(&servaddr, 0, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(port);
+ tmp = 1;
+ if (setsockopt(svr.listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&tmp, sizeof(tmp)) < 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");
}
-
-// ======================================================================================================
-// You don't need to know how the following codes are working
-#include <fcntl.h>
-
-static void* e_malloc(size_t size);
-
-
-static void init_request(request* reqP) {
+void request_init(request* reqP) {
reqP->conn_fd = -1;
reqP->buf_len = 0;
reqP->filename = NULL;
reqP->header_done = 0;
}
-static void free_request(request* reqP) {
+void request_free(request* reqP) {
if (reqP->filename != NULL) {
free(reqP->filename);
reqP->filename = NULL;
}
- init_request(reqP);
+ request_init(reqP);
}
-// return 0: socket ended, request done.
-// return 1: success, message (without header) got this time is in reqP->buf with reqP->buf_len bytes. read more until got <= 0.
-// It's guaranteed that the header would be correctly set after the first read.
-// error code:
-// -1: client connection error
-static int handle_read(request* reqP) {
+int request_read(request* reqP) {
int r;
char buf[512];
@@ -193,14 +69,14 @@ static int handle_read(request* reqP) {
if (r < 0) return -1;
if (r == 0) return 0;
if (reqP->header_done == 0) {
- char* p1 = strstr(buf, "\015\012");
+ char* p1 = strstr(buf, "\r\n");
int newline_len = 2;
- // be careful that in Windows, line ends with \015\012
+ // be careful that in Windows, line ends with \r\n
if (p1 == NULL) {
- p1 = strstr(buf, "\012");
+ p1 = strstr(buf, "\n");
newline_len = 1;
if (p1 == NULL) {
- ERR_EXIT("this really should not happen...");
+ e_err_exit("this really should not happen...");
}
}
size_t len = p1 - buf + 1;
@@ -217,38 +93,3 @@ static int handle_read(request* reqP) {
}
return 1;
}
-
-static void init_server(unsigned short port) {
- struct sockaddr_in servaddr;
- int tmp;
-
- gethostname(svr.hostname, sizeof(svr.hostname));
- svr.port = port;
-
- svr.listen_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (svr.listen_fd < 0) ERR_EXIT("socket");
-
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(port);
- tmp = 1;
- if (setsockopt(svr.listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&tmp, sizeof(tmp)) < 0) {
- ERR_EXIT("setsockopt");
- }
- if (bind(svr.listen_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
- ERR_EXIT("bind");
- }
- if (listen(svr.listen_fd, 1024) < 0) {
- ERR_EXIT("listen");
- }
-}
-
-static void* e_malloc(size_t size) {
- void* ptr;
-
- ptr = malloc(size);
- if (ptr == NULL) ERR_EXIT("out of memory");
- return ptr;
-}
-
diff --git a/hw1/server.h b/hw1/server.h
new file mode 100644
index 0000000..9cab01e
--- /dev/null
+++ b/hw1/server.h
@@ -0,0 +1,46 @@
+#ifndef SP_HW1_SERVER_H
+#define SP_HW1_SERVER_H
+
+#include <stdlib.h>
+
+#define SVR_ACCEPT_HDR_LEN 8
+#define SVR_REJECT_HDR_LEN 8
+
+typedef struct {
+ char hostname[512]; // 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];
+} server;
+
+typedef struct {
+ char host[512]; // client's host
+ int conn_fd; // fd to talk with client
+ char buf[512]; // data sent by/to client
+ size_t buf_len; // bytes used by buf
+ // you don't need to change this.
+ char* filename; // filename set in header, end with '\0'.
+ int header_done; // used by handle_read to know if the header is read or not.
+} request;
+
+extern server svr; // server
+
+// initailize a server, exit for error
+void server_init(unsigned short port);
+
+// initailize a request instance
+void request_init(request* reqP);
+
+// free resources used by a request instance
+void request_free(request* reqP);
+
+// return 0: socket ended, request done.
+// return 1: success, message (without header) got this time is in reqP->buf with reqP->buf_len bytes. read more until got <= 0.
+// It's guaranteed that the header would be correctly set after the first read.
+// error code:
+// -1: client connection error
+int request_read(request* reqP);
+
+
+#endif /* SP_HW1_SERVER_H */