summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-10-22 01:08:32 +0800
committerLAN-TW <lantw44@gmail.com>2013-10-22 01:17:50 +0800
commitd2fc67d8dc6095918830d509cd300b7a9d1ed170 (patch)
tree41ad9142aa0ef1603bb70b0d9123517ee9b9e673
parent36e1fc8e2f82a35d0a7e7b44d57bf3da0526e407 (diff)
downloadcn2013-d2fc67d8dc6095918830d509cd300b7a9d1ed170.tar.gz
cn2013-d2fc67d8dc6095918830d509cd300b7a9d1ed170.tar.zst
cn2013-d2fc67d8dc6095918830d509cd300b7a9d1ed170.zip
HW1: 將 RasServer 部份功能移到 RasConn、加入一小部份處理 client 的東西
-rw-r--r--hw1/Makefile.am2
-rw-r--r--hw1/connection.c111
-rw-r--r--hw1/connection.h34
-rw-r--r--hw1/server-main.c68
-rw-r--r--hw1/server.c140
-rw-r--r--hw1/server.h34
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 */