summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2014-01-14 04:46:07 +0800
committerLAN-TW <lantw44@gmail.com>2014-01-14 04:48:21 +0800
commit549548a09953851531f5104c5f1334b0f036764d (patch)
treefa6267ff580bf716eeac52901ae1410a5482355b
parent5873050be326f8b645b994d8c5e8b266573a6e40 (diff)
downloadsp2013-549548a09953851531f5104c5f1334b0f036764d.tar
sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.gz
sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.bz2
sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.lz
sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.xz
sp2013-549548a09953851531f5104c5f1334b0f036764d.tar.zst
sp2013-549548a09953851531f5104c5f1334b0f036764d.zip
HW4: 接收通知、結束程式、處理 main thread 的 signal
-rw-r--r--hw4/chttpd/chttpd-server.c168
-rw-r--r--hw4/chttpd/chttpd-server.h10
2 files changed, 173 insertions, 5 deletions
diff --git a/hw4/chttpd/chttpd-server.c b/hw4/chttpd/chttpd-server.c
index d5c0337..611a7a6 100644
--- a/hw4/chttpd/chttpd-server.c
+++ b/hw4/chttpd/chttpd-server.c
@@ -11,13 +11,17 @@
#include <l4str.h>
#include <l4posix.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <locale.h>
#include <netdb.h>
+#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -209,14 +213,148 @@ static LbsListMeta* chttpd_main_init (ChttpdLog* hlog, const char* service) {
return slist;
}
-int chttpd_server_notify;
-pthread_mutex_t chttpd_server_notify_mutex;
+int chttpd_server_notify;
+pthread_mutex_t chttpd_server_notify_mutex;
+ChttpdServer chttpd_server_notify_data;
+
+unsigned long long chttpd_server_count;
+pthread_rwlock_t chttpd_server_count_lock;
+
+static volatile sig_atomic_t server_shutdown;
+static void server_shutdown_setter (int signo) {
+ server_shutdown = 1;
+}
+
+static volatile sig_atomic_t server_notify;
+static void server_notify_setter (int signo) {
+ server_notify = 1;
+}
+
+static void dummy_handler (int signo) { }
static void chttpd_main_loop (ChttpdLog* hlog, LbsListMeta* slist) {
chttpd_server_notify = 1;
+ chttpd_server_notify_data.attr_close = true;
pthread_mutex_init (&chttpd_server_notify_mutex, NULL);
+ chttpd_server_count = 0;
+ pthread_rwlock_init (&chttpd_server_count_lock, NULL);
+
+ sigset_t crit_mask;
+ sigemptyset (&crit_mask);
+ sigaddset (&crit_mask, SIGINT);
+ sigaddset (&crit_mask, SIGTERM);
+ sigaddset (&crit_mask, SIGHUP);
+ sigaddset (&crit_mask, SIGUSR2);
+
+ while (lbs_list_meta_get_len (slist) > 0) {
+ pthread_sigmask (SIG_BLOCK, &crit_mask, NULL);
+
+ /* Check whether we are going to shutdown the server */
+ if (server_shutdown) {
+ pthread_mutex_lock (&chttpd_server_notify_mutex);
+ chttpd_server_notify = 1;
+ pthread_mutex_unlock (&chttpd_server_notify_mutex);
+ for (LbsList* iter = slist->first; iter != NULL; iter = iter->next) {
+ ChttpdServer* server = iter->data;
+ pthread_rwlock_wrlock (&server->lock);
+ server->attr_close = true;
+ pthread_rwlock_unlock (&server->lock);
+ }
+ }
+ /* Check whether there are notifications */
+ pthread_mutex_lock (&chttpd_server_notify_mutex);
+ if (chttpd_server_notify || server_notify) {
+ chttpd_server_notify = 0;
+ server_notify = 0;
+ if (chttpd_server_notify_data.attr_close == false) {
+ /* TODO: Add a server */
+ ChttpdServer* new_server = xmalloc (sizeof (ChttpdServer));
+ *new_server = chttpd_server_notify_data;
+ lbs_list_push_back (slist, new_server, NULL);
+ }
+ pthread_mutex_unlock (&chttpd_server_notify_mutex);
+
+ /* Remove unused servers */
+ LbsList* iter = slist->first;
+ LbsList* next = iter;
+ for (; iter != NULL; iter = next) {
+ ChttpdServer* server = iter->data;
+ next = iter->next;
+ if (pthread_rwlock_trywrlock (&server->lock) == 0) {
+ if (server->attr_close && server->conn->len <= 0) {
+ pthread_rwlock_unlock (&server->lock);
+ lbs_list_remove (slist, iter);
+ } else {
+ pthread_rwlock_unlock (&server->lock);
+ }
+ }
+ }
+
+ /* Rebuild poll list */
+
+ /* Log current server info */
+ chttpd_log_write_str (hlog, "[Server status change notification]");
+
+ unsigned long long count;
+ pthread_rwlock_rdlock (&chttpd_server_count_lock);
+ count = chttpd_server_count;
+ pthread_rwlock_unlock (&chttpd_server_count_lock);
+
+ chttpd_log_write (hlog, "%lld connections has been accepted", count);
+
+ unsigned c = 0;
+ for (iter = slist->first; iter != NULL; iter = iter->next, c++) {
+ ChttpdServer* server = iter->data;
+ struct sockaddr_storage addr;
+ char* type;
+
+ pthread_rwlock_rdlock (&server->lock);
+ addr = server->addr;
+ type = server->attr_admin ? "ADMIN" : "HTTP";
+ pthread_rwlock_unlock (&server->lock);
+
+ char ipstr[INET6_ADDRSTRLEN];
+ switch (addr.ss_family) {
+ case AF_UNIX:
+ CHTTPD_SOCKET_SOCKADDR_UN_SET_NULL (SOCKADDR_UN (&addr));
+ chttpd_log_write (hlog,
+ "Server %u: type %s, UNIX socket, path %s",
+ c, type, SOCKADDR_UN (&addr)->sun_path);
+ break;
+ case AF_INET:
+ if (!inet_ntop (AF_INET, &(SOCKADDR_IN (&addr)->sin_addr),
+ ipstr, INET_ADDRSTRLEN)) {
+ strcpy (ipstr, "unknown");
+ }
+ chttpd_log_write (hlog, "Server %u: type %s, "
+ "IPv4 socket, address %s, port %" PRIu16, c, type,
+ ipstr, ntohs (SOCKADDR_IN (&addr)->sin_port));
+ break;
+ case AF_INET6:
+ if (!inet_ntop (AF_INET6, &(SOCKADDR_IN6 (&addr)->sin6_addr),
+ ipstr, INET6_ADDRSTRLEN)) {
+ strcpy (ipstr, "unknown");
+ }
+ chttpd_log_write (hlog, "Server %u: type %s, "
+ "IPv6 socket, address %s, port %" PRIu16, c, type,
+ ipstr, ntohs (SOCKADDR_IN6 (&addr)->sin6_port));
+ break;
+ default:
+ chttpd_log_write (hlog,
+ "Server %u: type %s, unknown socket", c, type);
+ break;
+ }
+ }
+
+ } else {
+ pthread_mutex_unlock (&chttpd_server_notify_mutex);
+ }
+
+ pthread_sigmask (SIG_UNBLOCK, &crit_mask, NULL);
+ /* */
+ }
}
void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin) {
@@ -237,6 +375,7 @@ void chttpd_server_dtor (void* server_generic) {
close (server->sockfd);
pthread_rwlock_destroy (&server->lock);
lbs_list_meta_free (server->conn);
+ chttpd_log_unref (server->hlog);
free (server);
}
@@ -256,6 +395,31 @@ int main (int argc, char* argv[]) {
return 2;
}
+ struct sigaction sa_pipe, sa_term, sa_usr1, sa_usr2;
+ sa_pipe.sa_handler = SIG_IGN;
+ sa_pipe.sa_flags = 0;
+ sigemptyset (&sa_pipe.sa_mask);
+ sigaction (SIGPIPE, &sa_pipe, NULL); /* Use errno, no SIGPIPE */
+ sa_term.sa_handler = server_shutdown_setter;
+ sa_term.sa_flags = 0;
+ sigemptyset (&sa_term.sa_mask);
+ sigaction (SIGINT, &sa_term, NULL); /* Handled by main thread in loop */
+ sigaction (SIGTERM, &sa_term, NULL); /* Handled by main thread in loop */
+ sa_usr1.sa_handler = dummy_handler;
+ sa_usr1.sa_flags = 0;
+ sigemptyset (&sa_usr1.sa_mask);
+ sigaction (SIGUSR1, &sa_usr1, NULL); /* Handled by connection thread */
+ sa_usr2.sa_handler = server_notify_setter;
+ sa_usr2.sa_flags = 0;
+ sigemptyset (&sa_usr2.sa_mask);
+ sigaction (SIGHUP, &sa_usr2, NULL); /* Handled by main thread to interrupt */
+ sigaction (SIGUSR2, &sa_usr2, NULL); /* Handled by main thread to interrupt */
+
+ sigset_t main_mask;
+ sigemptyset (&main_mask);
+ sigaddset (&main_mask, SIGUSR1);
+ pthread_sigmask (SIG_BLOCK, &main_mask, NULL);
+
LbsListMeta* slist = chttpd_main_init (hlog, argv[1]);
if (lbs_list_meta_get_len (slist) > 0) {
chttpd_main_loop (hlog, slist);
diff --git a/hw4/chttpd/chttpd-server.h b/hw4/chttpd/chttpd-server.h
index 1fd6f7c..e85716b 100644
--- a/hw4/chttpd/chttpd-server.h
+++ b/hw4/chttpd/chttpd-server.h
@@ -12,16 +12,20 @@ typedef struct {
struct sockaddr_storage addr;
socklen_t addrlen;
int attr_admin : 1;
+ ChttpdLog* hlog;
/* read-write and lock */
pthread_rwlock_t lock;
- ChttpdLog* hlog;
LbsListMeta* conn;
int attr_close : 1;
} ChttpdServer;
-extern int chttpd_server_notify;
-extern pthread_mutex_t chttpd_server_notify_mutex;
+extern int chttpd_server_notify;
+extern pthread_mutex_t chttpd_server_notify_mutex;
+extern ChttpdServer chttpd_server_notify_data;
+
+extern unsigned long long chttpd_server_count;
+extern pthread_rwlock_t chttpd_server_count_lock;
void chttpd_server_ctor (void* server_generic, ChttpdLog* hlog, bool is_admin);
void chttpd_server_dtor (void* server_generic);