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 <stdio.h>
 #include <sys/socket.h>
 #include <signal.h>
+#include <unistd.h>
 #include <sys/select.h>
 #include <string.h>
 #include <errno.h>
 #include <arpa/inet.h>
+#include <wait.h>
 
 #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;
 }