diff options
author | LAN-TW <lantw44@gmail.com> | 2013-10-08 18:20:04 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-10-08 18:20:04 +0800 |
commit | 56ddfdf237610056f16dab036eecf912a1a0f540 (patch) | |
tree | 61f0f372c458ce4d76f703195f7d9452f610902f | |
parent | 8ecda287786e0ebc1d0061c6e6895e694820af45 (diff) | |
download | sp2013-56ddfdf237610056f16dab036eecf912a1a0f540.tar.gz sp2013-56ddfdf237610056f16dab036eecf912a1a0f540.tar.zst sp2013-56ddfdf237610056f16dab036eecf912a1a0f540.zip |
HW1: Refactor imported code
-rw-r--r-- | hw1/Makefile | 42 | ||||
-rw-r--r-- | hw1/common.c | 19 | ||||
-rw-r--r-- | hw1/common.h | 9 | ||||
-rw-r--r-- | hw1/main.c | 42 | ||||
-rw-r--r-- | hw1/proc.h | 9 | ||||
-rw-r--r-- | hw1/proc_r.c | 76 | ||||
-rw-r--r-- | hw1/proc_w.c | 69 | ||||
-rw-r--r-- | hw1/server.c | 243 | ||||
-rw-r--r-- | hw1/server.h | 46 |
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 */ |