/* B01902062 èĉşç */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "server.h" #include "common.h" #include <assert.h> #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> #include <netdb.h> #include <netinet/in.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> // You don't need to know how the following codes are working void server_init(server* svr, unsigned short port, int maxfd) { struct sockaddr_in servaddr; int val, flags; gethostname(svr->hostname, sizeof(svr->hostname)); svr->port = port; 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"); strcpy(svr->accept_hdr, "ACCEPT\n"); strcpy(svr->reject_hdr, "REJECT\n"); FD_ZERO(&svr->readfds); FD_ZERO(&svr->writefds); FD_ZERO(&svr->exceptfds); FD_SET(svr->listen_fd, &svr->readfds); flags = fcntl(svr->listen_fd, F_GETFL); if(flags < 0){ perror("Warning: F_GETFL"); return; } fcntl(svr->listen_fd, F_SETFL, flags | O_NONBLOCK); 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; reqP->buf_len = 0; reqP->filename = NULL; reqP->file_fd = -1; reqP->file_info = NULL; reqP->active = 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; } shutdown (reqP->conn_fd, SHUT_RDWR); close (reqP->conn_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); } 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; if (p1 == NULL) { char* pfn = e_malloc (sizeof (char) * (r + 1)); memmove (pfn, buf, r); pfn[r] = '\0'; if (reqP->filename == NULL) { reqP->filename = pfn; } else { char* newpfn = e_strcat (reqP->filename, pfn); free (reqP->filename); reqP->filename = newpfn; free (pfn); } return 1; } } size_t len = p1 - buf + 1; char* fn = (char*)e_malloc(len); memmove(fn, buf, len - 1); fn[len - 1] = '\0'; if (reqP->filename == NULL) { reqP->filename = fn; } else { char* newfn = e_strcat (reqP->filename, fn); free (reqP->filename); reqP->filename = newfn; free (fn); } 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; } void request_msg (request* reqP, const char* format, ...) { va_list ap; va_start (ap, format); printf ("client %d from %s: %s: ", reqP->conn_fd, reqP->host, reqP->filename ? reqP->filename : "(no filename)"); vprintf (format, ap); 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) : ""); }