static char *program_name = "sp8-server"; static pthread_once_t create_thread_once = PTHREAD_ONCE_INIT; static pthread_attr_t attr; void create_thread_init(void) { int err; err = pthread_attr_init(&attr); if (err != 0) logutil_fatal("pthread_attr_init: %d", err); err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (err != 0) logutil_fatal("PTHREAD_CREATE_DETACHED: %d", err); } int create_detached_thread(void *(*thread_main)(void *), void *arg) { pthread_t thread_id; pthread_once(&create_thread_once, create_thread_init); return (pthread_create(&thread_id, &attr, thread_main, arg)); } int protocol_switch(struct peer *peer) { char request; ssize_t sz; int err; sz = read(peer_fd(peer), &request, sizeof(request)); if (sz == 0) { /* eof */ logutil_info("disconnected"); peer_protocol_error(peer); return (0); } else if (sz < 0) { err = errno; logutil_error("read error: %d", err); peer_protocol_error(peer); return (err); /* finish on error */ } assert(sz == sizeof(request)); switch (request) { case 'P': err = server_put(peer); break; case 'G': err = server_get(peer); break; default: logutil_warning("unknown request: %d", request); err = EPROTO; } return (err); } void * protocol_main(void *arg) { struct peer *peer = arg; int err; /* authorize peer */ if ((err = peer_authorize(peer)) != 0) { logutil_error("peer_authorize: %d", err); goto peer_free; } while (!peer_is_protocol_error(peer)) { err = protocol_switch(peer); /* continue until protocol error happens */ } peer_free: peer_free(peer); /* this return value won't be used, because this thread is detached */ return (NULL); } void main_loop(int accepting_socket) { int err, client_socket; struct sockaddr_in client_addr; socklen_t client_addr_size; struct peer *peer; /* XXX FIXME too many threads. Consider to use a thread pool. */ for (;;) { client_addr_size = sizeof(client_addr); client_socket = accept(accepting_socket, (struct sockaddr *)&client_addr, &client_addr_size); if (client_socket < 0) { if (errno != EINTR) logutil_error("accept error: %d", errno); } else if ((err = peer_alloc(client_socket, &peer)) != 0) { logutil_warning("peer_alloc: %d", err); close(client_socket); } else if ((err = create_detached_thread(protocol_main, peer)) != 0) { logutil_warning("create_detached_thread: %d", err); peer_free(peer); sleep(1); } } } int open_accepting_socket(int port) { struct sockaddr_in self_addr; socklen_t self_addr_size; int sock, sockopt; memset(&self_addr, 0, sizeof(self_addr)); self_addr.sin_family = AF_INET; self_addr.sin_addr.s_addr = INADDR_ANY; self_addr.sin_port = htons(port); self_addr_size = sizeof(self_addr); sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) logutil_fatal("accepting socket: %d", errno); sockopt = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) == -1) logutil_warning("SO_REUSEADDR: %d", errno); if (bind(sock, (struct sockaddr *)&self_addr, self_addr_size) < 0) logutil_fatal("bind accepting socket: %d", errno); if (listen(sock, SOMAXCONN) < 0) logutil_fatal("listen: %d", errno); return (sock); } void * termsigs_handler(void *p) { sigset_t *termsigs = p; int sig; if (sigwait(termsigs, &sig) == -1) logutil_warning("termsigs_handler: %d", errno); logutil_info("signal %d received: terminating...", sig); logutil_info("bye"); exit(0); } int main(int argc, char **argv) { char *port_number = NULL; int err, ch, sock, server_port = DEFAULT_SERVER_PORT; int debug_mode = 0; sigset_t termsigs; if (argc >= 1) program_name = basename(argv[0]); while ((ch = getopt(argc, argv, "dp:")) != -1) { switch (ch) { case 'd': debug_mode = 1; break; case 'p': port_number = optarg; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (port_number != NULL) server_port = strtol(port_number, NULL, 0); sock = open_accepting_socket(server_port); if (!debug_mode) { logutil_syslog_open(program_name, LOG_PID, LOG_LOCAL0); daemon(0, 0); } /* * We don't want SIGPIPE, but want EPIPE on write(2)/close(2). */ signal(SIGPIPE, SIG_IGN); /* * block SIGINT and SIGTERM, and create a "signal handler" * thread, termsigs_handler, for them. */ sigemptyset(&termsigs); sigaddset(&termsigs, SIGINT); sigaddset(&termsigs, SIGTERM); pthread_sigmask(SIG_BLOCK, &termsigs, NULL); err = create_detached_thread(termsigs_handler, &termsigs); if (err != 0) logutil_fatal("create_thread(termsigs_handler): %d", err); main_loop(sock); /*NOTREACHED*/ return (0); /* to shut up warning */ } |
% autoreconf --installを実行すると ./configure に必要なファイルが生成される.
% ./configure --prefix=<install_directory> % make % make install--prefixで,インストールしたいディレクトリを指定する. --prefixを指定しないと /usr/local が利用される.
提出締切は 11/18(水) 20:00とする. 作成したプログラムだけでは無く,考察および実行結果も含めること. サブジェクトを SP8 学籍番号 とし,tatebe _at_ cs までメールすること. 本文には授業の感想を含めること.