diff options
author | LAN-TW <lantw44@gmail.com> | 2013-10-22 01:08:32 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-10-22 01:17:50 +0800 |
commit | d2fc67d8dc6095918830d509cd300b7a9d1ed170 (patch) | |
tree | 41ad9142aa0ef1603bb70b0d9123517ee9b9e673 | |
parent | 36e1fc8e2f82a35d0a7e7b44d57bf3da0526e407 (diff) | |
download | cn2013-d2fc67d8dc6095918830d509cd300b7a9d1ed170.tar.gz cn2013-d2fc67d8dc6095918830d509cd300b7a9d1ed170.tar.zst cn2013-d2fc67d8dc6095918830d509cd300b7a9d1ed170.zip |
HW1: 將 RasServer 部份功能移到 RasConn、加入一小部份處理 client 的東西
-rw-r--r-- | hw1/Makefile.am | 2 | ||||
-rw-r--r-- | hw1/connection.c | 111 | ||||
-rw-r--r-- | hw1/connection.h | 34 | ||||
-rw-r--r-- | hw1/server-main.c | 68 | ||||
-rw-r--r-- | hw1/server.c | 140 | ||||
-rw-r--r-- | hw1/server.h | 34 |
6 files changed, 240 insertions, 149 deletions
diff --git a/hw1/Makefile.am b/hw1/Makefile.am index 3f5c03a..341913d 100644 --- a/hw1/Makefile.am +++ b/hw1/Makefile.am @@ -2,6 +2,6 @@ EXTRA_DIST = autogen.sh bin_PROGRAMS = ras-server noinst_LIBRARIES = libbasic.a libras.a libbasic_a_SOURCES = xwrap.c xwrap.h basic-list.c basic-list.h -libras_a_SOURCES = socktool.c socktool.h +libras_a_SOURCES = socktool.c socktool.h connection.c connection.h ras_server_SOURCES = server-main.c server.c server.h ras_server_LDADD = $(top_builddir)/libbasic.a $(top_builddir)/libras.a diff --git a/hw1/connection.c b/hw1/connection.c new file mode 100644 index 0000000..4a1fd1f --- /dev/null +++ b/hw1/connection.c @@ -0,0 +1,111 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "connection.h" + +#include "xwrap.h" + +#include <fcntl.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +int ras_conn_init ( + RasConn* conn, RasConnPerm perm, int domain, + const char* name, const char* log_file, int* id) { + + if (log_file == NULL || strcmp (log_file, "stderr") == 0) { + conn->log = stderr; + conn->log_fd = STDERR_FILENO; + conn->log_file = NULL; + conn->log_is_set = false; + } else if (strcmp (log_file, "stdout") == 0) { + conn->log = stdout; + conn->log_fd = STDOUT_FILENO; + conn->log_file = NULL; + conn->log_is_set = false; + } else { + int fd = open (log_file, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); + if (fd < 0) { + return -1; + } + FILE* fp = fdopen (fd, "ab"); + if (fp == NULL) { + return -1; + } + setvbuf (fp, NULL, _IONBF, 0); + conn->log = fp; + conn->log_fd = fd; + conn->log_file = xstrdup (log_file); + conn->log_is_set = true; + } + + char* dir_sep_loc = strrchr (name, '/'); + if (dir_sep_loc != NULL) { + name = dir_sep_loc + 1; + } + + conn->domain = domain; + conn->perm = perm; + conn->id = (*id)++; + conn->pid = getpid (); + conn->name = xstrcat (name, "-", + domain == AF_LOCAL ? "unix" : + domain == AF_INET ? "ipv4" : + domain == AF_INET6 ? "ipv6" : "unknown", "-", + perm == RAS_CONN_PERM_RESTRICTED ? "restricted" : + perm == RAS_CONN_PERM_REGULAR ? "regular" : + perm == RAS_CONN_PERM_ADMIN ? "admin" : "unknown", NULL); + conn->fd_is_set = false; + + return 0; +} + +void ras_conn_destroy (RasConn* conn) { + if (conn->fd_is_set) { + shutdown (conn->fd, SHUT_RDWR); + close (conn->fd); + } + if (conn->log_is_set) { + fclose (conn->log); + } + free (conn->log_file); + free (conn->name); +} + +void ras_conn_log (RasConn* conn, const char* format, ...) { + va_list ap; + time_t t; + struct tm tmd; + + va_start (ap, format); + time (&t); + localtime_r (&t, &tmd); + + struct flock lock_info = { + .l_type = F_WRLCK, + .l_whence = SEEK_END, + .l_start = 0, + .l_len = 0 + }; + fcntl (conn->log_fd, F_SETLKW, &lock_info); + + fprintf (conn->log, + "%04d-%02d-%02d %02d:%02d:%02d %s[%u]: ", + tmd.tm_year + 1900, tmd.tm_mon + 1, tmd.tm_mday, + tmd.tm_hour, tmd.tm_min, tmd.tm_sec, + conn->name, conn->pid); + vfprintf (conn->log, format, ap); + putc ('\n', conn->log); + + lock_info.l_type = F_UNLCK; + fcntl (conn->log_fd, F_SETLK, &lock_info); + + va_end (ap); +} diff --git a/hw1/connection.h b/hw1/connection.h new file mode 100644 index 0000000..9a4cfe7 --- /dev/null +++ b/hw1/connection.h @@ -0,0 +1,34 @@ +#ifndef RAS_CONNECTION_H +#define RAS_CONNECTION_H + +#include <stdio.h> +#include <sys/types.h> + +typedef enum { + RAS_CONN_PERM_RESTRICTED, + RAS_CONN_PERM_REGULAR, + RAS_CONN_PERM_ADMIN +} RasConnPerm; + +#define RAS_CONN(x) ((RasConn*)(x)) + +typedef struct { + RasConnPerm perm; + int domain; + int id; + int fd; + int fd_is_set : 1; + pid_t pid; + char* name; + FILE* log; + char* log_file; + int log_fd; + int log_is_set : 1; +} RasConn; + +int ras_conn_init (RasConn* conn, RasConnPerm perm, int domain, + const char* name, const char* log_file, int* id); +void ras_conn_destroy (RasConn* conn); +void ras_conn_log (RasConn* conn, const char* format, ...); + +#endif /* RAS_CONNECTION_H */ diff --git a/hw1/server-main.c b/hw1/server-main.c index e6d5f5a..dbb08bd 100644 --- a/hw1/server-main.c +++ b/hw1/server-main.c @@ -6,6 +6,7 @@ #include "socktool.h" #include "basic-list.h" +#include <errno.h> #include <locale.h> #include <time.h> #include <signal.h> @@ -16,20 +17,27 @@ #include <sys/types.h> #include <sys/select.h> #include <sys/socket.h> +#include <sys/wait.h> +#include <unistd.h> static volatile sig_atomic_t quit_request = false; static void quit_request_setter (int signo) { quit_request = true; } +static void cleanup_child (int signo) { + while (waitpid (-1, NULL, WUNTRACED | WNOHANG) > 0); +} + static void svrlist_fill_rset (List* svrlist, fd_set* rset, int* maxfd) { ListNode* iter; for (iter = list_node_front (svrlist); iter != NULL; iter = list_next (iter)) { RasServer* server = RAS_SERVER (list_data (iter)); - if (server->fd_is_set) { - FD_SET (server->fd, rset); - *maxfd = xmax (*maxfd, server->fd) + 1; + RasConn* conn = RAS_CONN (server); + if (conn->fd_is_set) { + FD_SET (conn->fd, rset); + *maxfd = xmax (*maxfd, conn->fd) + 1; } } } @@ -39,7 +47,8 @@ static RasServer* svrlist_find_server (List* svrlist, int fd) { for (iter = list_node_front (svrlist); iter != NULL; iter = list_next (iter)) { RasServer* server = RAS_SERVER (list_data (iter)); - if (server->fd_is_set && server->fd == fd) { + RasConn* conn = RAS_CONN (server); + if (conn->fd_is_set && conn->fd == fd) { return server; } } @@ -67,29 +76,28 @@ int main (int argc, char* argv[]) { sigaction (SIGINT, &action, NULL); sigaction (SIGQUIT, &action, NULL); sigaction (SIGTERM, &action, NULL); + action.sa_handler = cleanup_child; + sigaction (SIGCHLD, &action, NULL); List* svrlist = list_create (); + int sid = 0, cid = 0; RasServer svr; - int sid; - ras_server_init (&svr, - AF_LOCAL, RAS_SERVER_PERM_ADMIN, argv[0], NULL, &sid); - if (ras_server_listen (&svr, "/tmp/ras-server.sock", 0) < 0) { + ras_server_init (&svr, RAS_CONN_PERM_ADMIN, AF_LOCAL, NULL, &sid); + if (ras_server_listen (&svr, "/tmp/ras-server.sock", 0600) < 0) { return 1; } else { list_pushback (svrlist, &svr, sizeof (RasServer)); } - ras_server_init (&svr, - AF_INET, RAS_SERVER_PERM_RESTRICTED, argv[0], NULL, &sid); + ras_server_init (&svr, RAS_CONN_PERM_RESTRICTED, AF_INET, NULL, &sid); if (ras_server_listen (&svr, NULL, atoi (argv[1])) < 0) { return 1; } else { list_pushback (svrlist, &svr, sizeof (RasServer)); } - ras_server_init (&svr, - AF_INET6, RAS_SERVER_PERM_RESTRICTED, argv[0], NULL, &sid); + ras_server_init (&svr, RAS_CONN_PERM_RESTRICTED, AF_INET6, NULL, &sid); if (ras_server_listen (&svr, NULL, atoi (argv[1])) < 0) { return 1; } else { @@ -119,11 +127,39 @@ int main (int argc, char* argv[]) { continue; } - int session_fd = accept (i, NULL, NULL); - char* peername = ras_socktool_get_peername (session_fd); - ras_server_log (server, "client X from %s is accepted", peername); + int session_fd; + char* peername; + pid_t cpid; + + session_fd = accept (i, NULL, NULL); + if (session_fd < 0) { + continue; + } + + peername = ras_socktool_get_peername (session_fd); + cid++; + ras_server_log (server, + "client %d from %s is accepted", cid, peername); free (peername); + cpid = fork (); + if (cpid < 0) { + ras_server_log (server, + "client %d cannot continue: fork error: %s", + cid, strerror (errno)); + shutdown (session_fd, SHUT_RDWR); + close (session_fd); + ras_server_log (server, + "client %d connection closed", cid); + continue; + } else if (cpid > 0) { + /* parent process */ + ras_server_log (server, + "client %d is handled by process %u now", cid, cpid); + } else { + /* child process */ + exit (0); + } } } @@ -135,7 +171,7 @@ int main (int argc, char* argv[]) { for (ListNode* iter = list_node_front (svrlist); iter != NULL; iter = list_next (iter)) { - ras_server_close (RAS_SERVER (list_data (iter))); + ras_server_destroy (RAS_SERVER (list_data (iter))); } list_free (svrlist); diff --git a/hw1/server.c b/hw1/server.c index 118fd31..983e49e 100644 --- a/hw1/server.c +++ b/hw1/server.c @@ -3,110 +3,64 @@ #endif #include "server.h" -#include "xwrap.h" + #include "socktool.h" +#include "connection.h" #include <arpa/inet.h> -#include <fcntl.h> #include <errno.h> -#include <inttypes.h> #include <netinet/in.h> -#include <stdarg.h> #include <stdbool.h> #include <stddef.h> -#include <stdio.h> -#include <string.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/un.h> -#include <time.h> #include <unistd.h> int ras_server_init ( - RasServer* server, int domain, RasServerPerm perm, - const char* name, const char* log_file, int* id) { - - memset (server, 0, sizeof (RasServer)); - - if (log_file == NULL || strcmp (log_file, "stderr") == 0) { - server->log = stderr; - server->log_fd = STDERR_FILENO; - server->log_file = NULL; - server->log_is_set = false; - } else if (strcmp (log_file, "stdout") == 0) { - server->log = stdout; - server->log_fd = STDOUT_FILENO; - server->log_file = NULL; - server->log_is_set = false; - } else { - int fd = open (log_file, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); - if (fd < 0) { - return -1; - } - FILE* fp = fdopen (fd, "ab"); - if (fp == NULL) { - return -1; - } - setvbuf (fp, NULL, _IONBF, 0); - server->log = fp; - server->log_fd = fd; - server->log_file = xstrdup (log_file); - server->log_is_set = true; + RasServer* server, RasConnPerm perm, int domain, + const char* log_file, int* id) { + + /* chain up to parent constructor */ + int rval = + ras_conn_init (RAS_CONN (server), perm, domain, "ras-server", log_file, id); + if (rval < 0) { + return rval; } - char* dir_sep_loc = strrchr (name, '/'); - if (dir_sep_loc != NULL) { - name = dir_sep_loc + 1; - } - - server->domain = domain; - server->perm = perm; - server->id = (*id)++; - server->pid = getpid (); - server->name = xstrcat (name, "-", - domain == AF_LOCAL ? "unix" : - domain == AF_INET ? "ipv4" : - domain == AF_INET6 ? "ipv6" : "unknown", "-", - perm == RAS_SERVER_PERM_RESTRICTED ? "restricted" : - perm == RAS_SERVER_PERM_REGULAR ? "regular" : - perm == RAS_SERVER_PERM_ADMIN ? "admin" : "unknown", NULL); - return 0; } -void ras_server_close (RasServer* server) { - if (server->fd_is_set) { - shutdown (server->fd, SHUT_RDWR); - close (server->fd); - if (server->domain == AF_LOCAL) { - unlink (SOCKADDR_UN (&server->addr)->sun_path); - } +void ras_server_destroy (RasServer* server) { + if (RAS_CONN (server)->domain == AF_LOCAL) { + unlink (SOCKADDR_UN (&server->addr)->sun_path); } - if (server->log_is_set) { - fclose (server->log); - } - free (server->log_file); - free (server->name); + + /* chain up to parent destructor */ + ras_conn_destroy (RAS_CONN (server)); } -int ras_server_listen (RasServer* server, const char* addr, uint16_t port) { +int ras_server_listen (RasServer* server, const char* addr, int arg) { + /* domain == AC_LOCAL => arg == mode + * domain == AC_INET => arg == port + * domain == AC_INET6 => arg == port */ int len, fd; struct sockaddr_storage sock; socklen_t socklen; memset (&sock, 0, sizeof (sock)); - switch (server->domain) { + switch (RAS_CONN (server)->domain) { case AF_LOCAL: socklen = sizeof (struct sockaddr_un); len = socklen - offsetof (struct sockaddr_un, sun_path) - 1; SOCKADDR_UN (&sock)->sun_family = AF_LOCAL; strncpy (SOCKADDR_UN (&sock)->sun_path, addr, len); - ras_server_log (server, "addr = %s", addr); + ras_server_log (server, "addr = %s, mode = %o", addr, arg); break; case AF_INET: socklen = sizeof (struct sockaddr_in); SOCKADDR_IN (&sock)->sin_family = AF_INET; - SOCKADDR_IN (&sock)->sin_port = htons (port); + SOCKADDR_IN (&sock)->sin_port = htons (arg); if (addr == NULL) { SOCKADDR_IN (&sock)->sin_addr.s_addr = htonl (INADDR_ANY); addr = "any"; @@ -116,12 +70,12 @@ int ras_server_listen (RasServer* server, const char* addr, uint16_t port) { return -1; } } - ras_server_log (server, "addr = %s, port = %" PRIu16, addr, port); + ras_server_log (server, "addr = %s, port = %d", addr, arg); break; case AF_INET6: socklen = sizeof (struct sockaddr_in6); SOCKADDR_IN6 (&sock)->sin6_family = AF_INET6; - SOCKADDR_IN6 (&sock)->sin6_port = htons (port); + SOCKADDR_IN6 (&sock)->sin6_port = htons (arg); if (addr == NULL) { SOCKADDR_IN6 (&sock)->sin6_addr = in6addr_any; addr = "any"; @@ -131,21 +85,24 @@ int ras_server_listen (RasServer* server, const char* addr, uint16_t port) { return -1; } } - ras_server_log (server, "addr = %s, port = %" PRIu16, addr, port); + ras_server_log (server, "addr = %s, port = %d", addr, arg); break; default: return -1; } - fd = socket (server->domain, SOCK_STREAM, 0); + fd = socket (RAS_CONN (server)->domain, SOCK_STREAM, 0); if (fd < 0) { ras_server_log (server, "socket: %s", strerror (errno)); goto fd_opened; } - if (server->domain == AF_INET6) { + if (RAS_CONN (server)->domain == AF_INET6) { int yes = 1; setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof (yes)); } + if (RAS_CONN (server)->domain == AF_LOCAL) { + fchmod (fd, arg); + } if (bind (fd, SOCKADDR (&sock), socklen)) { ras_server_log (server, "bind: %s", strerror (errno)); @@ -157,8 +114,8 @@ int ras_server_listen (RasServer* server, const char* addr, uint16_t port) { goto fd_opened; } - server->fd = fd; - server->fd_is_set = true; + RAS_CONN (server)->fd = fd; + RAS_CONN (server)->fd_is_set = true; server->addr = sock; server->addrlen = socklen; @@ -169,34 +126,3 @@ fd_opened: return -1; } - -void ras_server_log (RasServer* server, const char* format, ...) { - va_list ap; - time_t t; - struct tm tmd; - - va_start (ap, format); - time (&t); - localtime_r (&t, &tmd); - - struct flock lock_info = { - .l_type = F_WRLCK, - .l_whence = SEEK_END, - .l_start = 0, - .l_len = 0 - }; - fcntl (server->log_fd, F_SETLKW, &lock_info); - - fprintf (server->log, - "%04d-%02d-%02d %02d:%02d:%02d %s[%u]: ", - tmd.tm_year + 1900, tmd.tm_mon + 1, tmd.tm_mday, - tmd.tm_hour, tmd.tm_min, tmd.tm_sec, - server->name, server->pid); - vfprintf (server->log, format, ap); - putc ('\n', server->log); - - lock_info.l_type = F_UNLCK; - fcntl (server->log_fd, F_SETLK, &lock_info); - - va_end (ap); -} diff --git a/hw1/server.h b/hw1/server.h index 359b384..cdbcf6e 100644 --- a/hw1/server.h +++ b/hw1/server.h @@ -1,40 +1,24 @@ #ifndef RAS_SERVER_H #define RAS_SERVER_H -#include <stdio.h> -#include <stdint.h> -#include <sys/socket.h> +#include "connection.h" -typedef enum { - RAS_SERVER_PERM_RESTRICTED, - RAS_SERVER_PERM_REGULAR, - RAS_SERVER_PERM_ADMIN -} RasServerPerm; +#include <sys/socket.h> #define RAS_SERVER(x) ((RasServer*)(x)) typedef struct { - RasServerPerm perm; - int id; - int fd; - pid_t pid; - char* name; - FILE* log; - char* log_file; - int log_fd; - int domain; + RasConn conn; struct sockaddr_storage addr; socklen_t addrlen; - int log_is_set : 1; - int fd_is_set : 1; } RasServer; -int ras_server_init ( - RasServer* server, int domain, RasServerPerm perm, - const char* name, const char* log_file, int* id); -void ras_server_close (RasServer* server); +int ras_server_init (RasServer* server, RasConnPerm perm, int domain, + const char* log_file, int* id); +void ras_server_destroy (RasServer* server); +int ras_server_listen (RasServer* server, const char* addr, int arg); -int ras_server_listen (RasServer* server, const char* addr, uint16_t port); -void ras_server_log (RasServer* server, const char* format, ...); +/* Access parent methods */ +#define ras_server_log(server, ...) ras_conn_log(RAS_CONN(server), __VA_ARGS__) #endif /* RAS_SERVER_H */ |