From e6760cf665fa55f574fe7d28dff9ab59734c5d2d Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Thu, 10 Dec 2020 22:24:06 +0100 Subject: [PATCH] Process management --- Makefile | 2 +- src/client.c | 26 ++++++------ src/necronda-server.c | 99 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 080c3da..9af2dff 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ packages: compile: @echo "Compiling..." @mkdir -p bin - gcc src/necronda-server.c -o bin/necronda-server -std=c11 + gcc src/necronda-server.c -o bin/necronda-server -std=c11 -D_POSIX_C_SOURCE @echo "Finished compiling!" install: | packages update compile diff --git a/src/client.c b/src/client.c index d14a3a3..6be858d 100644 --- a/src/client.c +++ b/src/client.c @@ -37,32 +37,30 @@ int client_request_handler() { } int client_connection_handler(int client) { - char buf[256]; + char buf1[256]; + char buf2[256]; print("Connection accepted from %s (%s) [%s]", client_addr_str, client_addr_str, "N/A"); - sprintf(buf, "Hello World!\nYour address is: %s\n", client_addr_str); - send(client, buf, strlen(buf), 0); + sprintf(buf1, "Hello World!\nYour address is: %s\n", client_addr_str); + send(client, buf1, strlen(buf1), 0); + int len = recv(client, &buf1, sizeof(buf1), 0); + sprintf(buf2, "Thank you, %.*s!\nGood bye!\n", len, buf1); + send(client, buf2, strlen(buf2), 0); + close(client); print("Connection closed"); return 0; } -int client_handler(int socket, long client_num) { - struct sockaddr_in6 client_addr, *server_addr; +int client_handler(int client, long client_num, struct sockaddr_in6 *client_addr) { + struct sockaddr_in6 *server_addr; struct sockaddr_storage server_addr_storage; - unsigned int client_addr_len = sizeof(client_addr); char *color_table[] = {"\x1B[31m", "\x1B[32m", "\x1B[33m", "\x1B[34m", "\x1B[35m", "\x1B[36m"}; - int client = accept(socket, (struct sockaddr *) &client_addr, &client_addr_len); - if (client == -1) { - fprintf(parent_stderr, ERR_STR "Unable to accept connection: %s" CLR_STR "\n", strerror(errno)); - return -1; - } - client_addr_str_ptr = malloc(INET6_ADDRSTRLEN); - inet_ntop(client_addr.sin6_family, (void *) &client_addr.sin6_addr, client_addr_str_ptr, INET6_ADDRSTRLEN); + inet_ntop(client_addr->sin6_family, (void *) &client_addr->sin6_addr, client_addr_str_ptr, INET6_ADDRSTRLEN); if (strncmp(client_addr_str_ptr, "::ffff:", 7) == 0) { client_addr_str = client_addr_str_ptr + 7; } else { @@ -83,7 +81,7 @@ int client_handler(int socket, long client_num) { log_base_prefix = malloc(256); sprintf(log_base_prefix, "[%24s][%s%4i%s]%s[%*s][%5i]%s ", server_addr_str, R_STR, ntohs(server_addr->sin6_port), CLR_STR, - color_table[client_num % 6], INET_ADDRSTRLEN, client_addr_str, ntohs(client_addr.sin6_port), CLR_STR); + color_table[client_num % 6], INET_ADDRSTRLEN, client_addr_str, ntohs(client_addr->sin6_port), CLR_STR); int ret = client_connection_handler(client); free(client_addr_str_ptr); diff --git a/src/necronda-server.c b/src/necronda-server.c index 4ce0ace..8b3f0c4 100644 --- a/src/necronda-server.c +++ b/src/necronda-server.c @@ -10,16 +10,73 @@ #include #include #include +#include #include #include #include #include +#include #include "utils.c" #include "net/http.c" #include "client.c" +int active = 1; + +void destroy() { + fprintf(stderr, "\n" ERR_STR "Terminating forcefully!" CLR_STR "\n"); + int status = 0; + int ret; + int kills = 0; + for (int i = 0; i < MAX_CHILDREN; i++) { + if (CHILDREN[i] != 0) { + ret = waitpid(CHILDREN[i], &status, WNOHANG); + if (ret < 0) { + fprintf(stderr, ERR_STR "Unable to wait for child process (PID %i): %s" CLR_STR "\n", CHILDREN[i], strerror(errno)); + } else if (ret == CHILDREN[i]) { + CHILDREN[i] = 0; + } else { + kill(CHILDREN[i], SIGKILL); + kills++; + } + } + } + if (kills > 0) { + fprintf(stderr, ERR_STR "Killed %i child process(es)" CLR_STR "\n", kills); + } + exit(2); +} + +void terminate() { + fprintf(stderr, "\nTerminating gracefully...\n"); + active = 0; + + signal(SIGTERM, destroy); + signal(SIGINT, destroy); + + for (int i = 0; i < NUM_SOCKETS; i++) { + shutdown(SOCKETS[i], SHUT_RDWR); + close(SOCKETS[i]); + } + + int status = 0; + int ret; + for (int i = 0; i < MAX_CHILDREN; i++) { + if (CHILDREN[i] != 0) { + ret = waitpid(CHILDREN[i], &status, 0); + if (ret < 0) { + fprintf(stderr, ERR_STR "Unable to wait for child process (PID %i): %s" CLR_STR "\n", CHILDREN[i], strerror(errno)); + } else if (ret == CHILDREN[i]) { + CHILDREN[i] = 0; + } + } + } + + fprintf(stderr, "Goodbye\n"); + exit(0); +} + int main(int argc, const char *argv[]) { const int YES = 1; fd_set socket_fds, read_socket_fds; @@ -27,6 +84,12 @@ int main(int argc, const char *argv[]) { int ready_sockets_num = 0; long client_num = 0; + int client; + struct sockaddr_in6 client_addr; + unsigned int client_addr_len = sizeof(client_addr); + + struct timeval timeout; + parent_stdout = stdout; parent_stderr = stderr; @@ -60,6 +123,9 @@ int main(int argc, const char *argv[]) { return 1; } + signal(SIGINT, terminate); + signal(SIGTERM, terminate); + // TODO implement TLS server side handshake for (int i = 0; i < NUM_SOCKETS; i++) { @@ -77,9 +143,11 @@ int main(int argc, const char *argv[]) { } } - while (1) { + while (active) { + timeout.tv_sec = 1; + timeout.tv_usec = 0; read_socket_fds = socket_fds; - ready_sockets_num = select(max_socket_fd + 1, &read_socket_fds, NULL, NULL, NULL); + ready_sockets_num = select(max_socket_fd + 1, &read_socket_fds, NULL, NULL, &timeout); if (ready_sockets_num == -1) { fprintf(stderr, ERR_STR "Unable to select sockets: %s" CLR_STR "\n", strerror(errno)); return 1; @@ -87,16 +155,26 @@ int main(int argc, const char *argv[]) { for (int i = 0; i < NUM_SOCKETS; i++) { if (FD_ISSET(SOCKETS[i], &read_socket_fds)) { + client = accept(SOCKETS[i], (struct sockaddr *) &client_addr, &client_addr_len); + if (client == -1) { + fprintf(parent_stderr, ERR_STR "Unable to accept connection: %s" CLR_STR "\n", strerror(errno)); + continue; + } + pid_t pid = fork(); if (pid == 0) { // child - return client_handler(SOCKETS[i], client_num); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + return client_handler(client, client_num, &client_addr); } else if (pid > 0) { // parent client_num++; + close(client); for (int j = 0; j < MAX_CHILDREN; j++) { if (CHILDREN[j] == 0) { CHILDREN[j] = pid; + break; } } } else { @@ -104,5 +182,20 @@ int main(int argc, const char *argv[]) { } } } + + int status = 0; + int ret; + for (int i = 0; i < MAX_CHILDREN; i++) { + if (CHILDREN[i] != 0) { + ret = waitpid(CHILDREN[i], &status, WNOHANG); + if (ret < 0) { + fprintf(stderr, ERR_STR "Unable to wait for child process (PID %i): %s" CLR_STR "\n", CHILDREN[i], strerror(errno)); + } else if (ret == CHILDREN[i]) { + CHILDREN[i] = 0; + } + } + } } + + return 0; }