]> git.seodisparate.com - c_simple_http/commitdiff
Handle multiple connections simultaneously
authorStephen Seo <seo.disparate@gmail.com>
Mon, 4 Nov 2024 06:22:58 +0000 (15:22 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 4 Nov 2024 06:25:27 +0000 (15:25 +0900)
This commit changes the implementationt to store connected clients
file-descriptors and to iterate through them all periodically to handle
requests and to time-out stale connections. This means that even if one
connection is in progress, the program can still handle new connections
from other clients.

Note this does this not by threads but by taking advantage of
non-blocking io to handle each connection.

Fixes https://git.seodisparate.com/stephenseo/c_simple_http/issues/8 .

src/constants.h
src/main.c
src/signal_handling.c
src/signal_handling.h

index 8b09a0108b994663fec58c25b34707fac69bb3fc..a99e5bbffa5a42a6253f5ac0733bd261ef76ae59 100644 (file)
@@ -19,6 +19,7 @@
 
 #define C_SIMPLE_HTTP_SLEEP_NANOS 1000000
 #define C_SIMPLE_HTTP_NONBLOCK_SLEEP_NANOS 1000000
+#define C_SIMPLE_HTTP_CONNECTION_TIMEOUT_SECONDS 3
 #define C_SIMPLE_HTTP_MAX_NONBLOCK_WAIT_NANOS 3500000000
 #define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_NANOS 4000000000
 #define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_TICKS \
index 2aa14655226e6fe730a3a84539dbf5ad0e954c7b..75448f3b1c3816a2581030042c90082b999f694c 100644 (file)
@@ -37,6 +37,7 @@
 // Local includes.
 #include "arg_parse.h"
 #include "big_endian.h"
+#include "config.h"
 #include "tcp_socket.h"
 #include "signal_handling.h"
 #include "globals.h"
 #include "helpers.h"
 #include "static.h"
 
-#define CHECK_ERROR_WRITE(write_expr) \
+#define CHECK_ERROR_WRITE(connection_fd, write_expr) \
   if (write_expr < 0) { \
     close(connection_fd); \
     fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
     return 1; \
   }
 
-#define CHECK_ERROR_WRITE_CONTINUE(write_expr) \
-  if (write_expr < 0) { \
-    close(connection_fd); \
-    fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
-    continue; \
+void c_simple_http_print_ipv6_addr(FILE *out, const struct in6_addr *addr) {
+  for (uint32_t idx = 0; idx < 16; ++idx) {
+    if (idx % 2 == 0 && idx > 0) {
+      fprintf(out, ":");
+    }
+    fprintf(out, "%02x", addr->s6_addr[idx]);
   }
+}
+
+typedef struct ConnectionItem {
+  int fd;
+  struct timespec time_point;
+  struct in6_addr peer_addr;
+} ConnectionItem;
+
+typedef struct ConnectionContext {
+  char *buf;
+  const Args *args;
+  C_SIMPLE_HTTP_ParsedConfig *parsed;
+} ConnectionContext;
+
+void c_simple_http_cleanup_connection_item(void *data) {
+  ConnectionItem *citem = data;
+  if (citem) {
+#ifndef NDEBUG
+    fprintf(stderr, "Closed connection to peer ");
+    c_simple_http_print_ipv6_addr(stderr, &citem->peer_addr);
+#endif
+    if (citem->fd >= 0) {
+      close(citem->fd);
+#ifndef NDEBUG
+      fprintf(stderr, ", fd %d\n", citem->fd);
+#endif
+      citem->fd = -1;
+    } else {
+#ifndef NDEBUG
+      fprintf(stderr, "\n");
+#endif
+    }
+    free(citem);
+  }
+}
 
 int c_simple_http_headers_check_print(void *data, void *ud) {
   SDArchiverHashMap *headers_map = ud;
@@ -92,22 +129,204 @@ int c_simple_http_on_error(
   size_t response_size;
   if (response) {
     response_size = strlen(response);
-    CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
+    CHECK_ERROR_WRITE(connection_fd,
+                      write(connection_fd, response, response_size));
   } else {
-    CHECK_ERROR_WRITE(write(
+    CHECK_ERROR_WRITE(connection_fd, write(
       connection_fd, "HTTP/1.1 500 Internal Server Error\n", 35));
-    CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
-    CHECK_ERROR_WRITE(write(connection_fd, "Connection: close\n", 18));
-    CHECK_ERROR_WRITE(write(
-      connection_fd, "Content-Type: text/html\n", 24));
-    CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 35\n", 19));
-    CHECK_ERROR_WRITE(write(
-      connection_fd, "\n<h1>500 Internal Server Error</h1>\n", 36));
+    CHECK_ERROR_WRITE(connection_fd, write(connection_fd, "Allow: GET\n", 11));
+    CHECK_ERROR_WRITE(connection_fd,
+                      write(connection_fd, "Connection: close\n", 18));
+    CHECK_ERROR_WRITE(connection_fd,
+                      write(connection_fd, "Content-Type: text/html\n", 24));
+    CHECK_ERROR_WRITE(connection_fd,
+                      write(connection_fd, "Content-Length: 35\n", 19));
+    CHECK_ERROR_WRITE(connection_fd,
+                      write(connection_fd,
+                            "\n<h1>500 Internal Server Error</h1>\n",
+                            36));
   }
 
   return 0;
 }
 
+int c_simple_http_manage_connections(void *data, void *ud) {
+  ConnectionItem *citem = data;
+  ConnectionContext *ctx = ud;
+  char *recv_buf = ctx->buf;
+  const Args *args = ctx->args;
+  C_SIMPLE_HTTP_ParsedConfig *parsed = ctx->parsed;
+
+  struct timespec current_monotonic;
+  clock_gettime(CLOCK_MONOTONIC, &current_monotonic);
+  if (current_monotonic.tv_sec - citem->time_point.tv_sec
+      >= C_SIMPLE_HTTP_CONNECTION_TIMEOUT_SECONDS) {
+    fprintf(stderr, "Peer ");
+    c_simple_http_print_ipv6_addr(stderr, &citem->peer_addr);
+    fprintf(stderr, " timed out.\n");
+    return 1;
+  }
+
+  ssize_t read_ret = read(citem->fd, recv_buf, C_SIMPLE_HTTP_RECV_BUF_SIZE);
+  if (read_ret < 0) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+      return 0;
+    } else {
+      fprintf(stderr, "Peer ");
+      c_simple_http_print_ipv6_addr(stderr, &citem->peer_addr);
+      fprintf(stderr, " error.\n");
+      return 1;
+    }
+  }
+
+#ifndef NDEBUG
+  // DEBUG print received buf.
+  for (uint32_t idx = 0;
+      idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
+      ++idx) {
+    if ((recv_buf[idx] >= 0x20 && recv_buf[idx] <= 0x7E)
+        || recv_buf[idx] == '\n' || recv_buf[idx] == '\r') {
+      printf("%c", recv_buf[idx]);
+    } else {
+      break;
+    }
+  }
+  puts("");
+#endif
+  {
+    SDArchiverHashMap *headers_map = c_simple_http_request_to_headers_map(
+      (const char*)recv_buf,
+      (size_t)read_ret);
+    simple_archiver_list_get(
+      args->list_of_headers_to_log,
+      c_simple_http_headers_check_print,
+      headers_map);
+    simple_archiver_hash_map_free(&headers_map);
+  }
+
+  size_t response_size = 0;
+  enum C_SIMPLE_HTTP_ResponseCode response_code;
+  __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+  char *request_path = NULL;
+  __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+  char *response = c_simple_http_request_response(
+    (const char*)recv_buf,
+    (uint32_t)read_ret,
+    parsed,
+    &response_size,
+    &response_code,
+    args,
+    &request_path);
+  if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
+    CHECK_ERROR_WRITE(citem->fd, write(
+      citem->fd, "HTTP/1.1 200 OK\n", 16));
+    CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "Allow: GET\n", 11));
+    CHECK_ERROR_WRITE(citem->fd, write(
+      citem->fd, "Connection: close\n", 18));
+    CHECK_ERROR_WRITE(citem->fd, write(
+      citem->fd, "Content-Type: text/html\n", 24));
+    char content_length_buf[128];
+    size_t content_length_buf_size = 0;
+    memcpy(content_length_buf, "Content-Length: ", 16);
+    content_length_buf_size = 16;
+    int32_t written = 0;
+    snprintf(
+      content_length_buf + content_length_buf_size,
+      127 - content_length_buf_size,
+      "%lu\n%n",
+      response_size,
+      &written);
+    if (written <= 0) {
+      close(citem->fd);
+      fprintf(
+        stderr,
+        "WARNING Failed to write in response, closing connection...\n");
+      return 1;
+    }
+    content_length_buf_size += (size_t)written;
+    CHECK_ERROR_WRITE(citem->fd, write(
+      citem->fd, content_length_buf, content_length_buf_size));
+    CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "\n", 1));
+    CHECK_ERROR_WRITE(citem->fd, write(
+      citem->fd, response, response_size));
+  } else if (
+      response_code == C_SIMPLE_HTTP_Response_404_Not_Found
+      && args->static_dir) {
+    __attribute__((cleanup(c_simple_http_cleanup_static_file_info)))
+    C_SIMPLE_HTTP_StaticFileInfo file_info =
+      c_simple_http_get_file(args->static_dir, request_path, 0);
+    if (file_info.result == STATIC_FILE_RESULT_NoXDGMimeAvailable) {
+      file_info = c_simple_http_get_file(args->static_dir, request_path, 1);
+    }
+
+    if (file_info.result != STATIC_FILE_RESULT_OK
+        || !file_info.buf
+        || file_info.buf_size == 0
+        || !file_info.mime_type) {
+      if (file_info.result == STATIC_FILE_RESULT_FileError
+          || file_info.result == STATIC_FILE_RESULT_InternalError) {
+        response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
+      } else if (file_info.result == STATIC_FILE_RESULT_InvalidParameter) {
+        response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+      } else if (file_info.result == STATIC_FILE_RESULT_404NotFound) {
+        response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
+      } else if (file_info.result == STATIC_FILE_RESULT_InvalidPath) {
+        response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+      } else {
+        response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
+      }
+
+      c_simple_http_on_error(response_code, citem->fd);
+      return 1;
+    } else {
+      CHECK_ERROR_WRITE(citem->fd, write(
+        citem->fd, "HTTP/1.1 200 OK\n", 16));
+      CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "Allow: GET\n", 11));
+      CHECK_ERROR_WRITE(citem->fd, write(
+        citem->fd, "Connection: close\n", 18));
+      uint64_t mime_length = strlen(file_info.mime_type);
+      __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+      char *mime_type_buf = malloc(mime_length + 1 + 14 + 1);
+      snprintf(
+        mime_type_buf,
+        mime_length + 1 + 14 + 1,
+        "Content-Type: %s\n",
+        file_info.mime_type);
+      CHECK_ERROR_WRITE(citem->fd, write(
+        citem->fd, mime_type_buf, mime_length + 1 + 14));
+      uint64_t content_str_len = 0;
+      for(uint64_t buf_size_temp = file_info.buf_size;
+          buf_size_temp > 0;
+          buf_size_temp /= 10) {
+        ++content_str_len;
+      }
+      if (content_str_len == 0) {
+        content_str_len = 1;
+      }
+      __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+      char *content_length_buf = malloc(content_str_len + 1 + 16 + 1);
+      snprintf(
+        content_length_buf,
+        content_str_len + 1 + 16 + 1,
+        "Content-Length: %lu\n",
+        file_info.buf_size);
+      CHECK_ERROR_WRITE(citem->fd, write(
+        citem->fd, content_length_buf, content_str_len + 1 + 16));
+      CHECK_ERROR_WRITE(citem->fd, write(citem->fd, "\n", 1));
+      CHECK_ERROR_WRITE(citem->fd, write(
+        citem->fd, file_info.buf, file_info.buf_size));
+      fprintf(stderr,
+              "NOTICE Found static file for path \"%s\"\n",
+              request_path);
+    }
+  } else {
+    c_simple_http_on_error(response_code, citem->fd);
+    return 1;
+  }
+
+  return 1;
+}
+
 int main(int argc, char **argv) {
   __attribute__((cleanup(c_simple_http_free_args)))
   Args args = parse_args(argc, argv);
@@ -186,10 +405,19 @@ int main(int argc, char **argv) {
   memset(&peer_info, 0, sizeof(struct sockaddr_in6));
   peer_info.sin6_family = AF_INET6;
 
+  __attribute__((cleanup(simple_archiver_list_free)))
+  SDArchiverLinkedList *connections = simple_archiver_list_init();
+
+  char recv_buf[C_SIMPLE_HTTP_RECV_BUF_SIZE];
+
+  ConnectionContext connection_context;
+  connection_context.buf = recv_buf;
+  connection_context.args = &args;
+  connection_context.parsed = &parsed_config;
+
   signal(SIGINT, C_SIMPLE_HTTP_handle_sigint);
   signal(SIGUSR1, C_SIMPLE_HTTP_handle_sigusr1);
-
-  unsigned char recv_buf[C_SIMPLE_HTTP_RECV_BUF_SIZE];
+  signal(SIGPIPE, C_SIMPLE_HTTP_handle_sigpipe);
 
   int ret;
   ssize_t read_ret;
@@ -342,13 +570,8 @@ int main(int argc, char **argv) {
       // Received connection, handle it.
       if ((args.flags & 1) == 0) {
         printf("Peer connected: addr is ");
-        for (uint32_t idx = 0; idx < 16; ++idx) {
-          if (idx % 2 == 0 && idx > 0) {
-            printf(":");
-          }
-          printf("%02x", peer_info.sin6_addr.s6_addr[idx]);
-        }
-        puts("");
+        c_simple_http_print_ipv6_addr(stdout, &peer_info.sin6_addr);
+        printf(", fd is %d\n", ret);
       } else {
         printf("Peer connected.\n");
       }
@@ -362,191 +585,21 @@ int main(int argc, char **argv) {
         continue;
       }
 
-      {
-        const struct timespec non_block_wait_time =
-          (struct timespec){.tv_sec = 0,
-                            .tv_nsec = C_SIMPLE_HTTP_NONBLOCK_SLEEP_NANOS};
-        uint64_t nanoseconds_waited = 0;
-        int_fast8_t continue_after = 0;
-        while (1) {
-          read_ret = read(connection_fd, recv_buf, C_SIMPLE_HTTP_RECV_BUF_SIZE);
-          if (read_ret < 0) {
-            if (errno == EAGAIN || errno == EWOULDBLOCK) {
-              nanosleep(&non_block_wait_time, NULL);
-              nanoseconds_waited += (uint64_t)non_block_wait_time.tv_nsec;
-              if (nanoseconds_waited >= C_SIMPLE_HTTP_MAX_NONBLOCK_WAIT_NANOS) {
-                fprintf(stderr, "WARNING Connection timed out!\n");
-                close(connection_fd);
-                continue_after = 1;
-                break;
-              }
-              continue;
-            }
-            close(connection_fd);
-            fprintf(
-              stderr,
-              "WARNING Failed to read from new connection, closing...\n");
-            continue_after = 1;
-            break;
-          } else {
-            break;
-          }
-        }
-        if (continue_after) {
-          continue;
-        }
-      }
-#ifndef NDEBUG
-      // DEBUG print received buf.
-      for (uint32_t idx = 0;
-          idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
-          ++idx) {
-        if ((recv_buf[idx] >= 0x20 && recv_buf[idx] <= 0x7E)
-            || recv_buf[idx] == '\n' || recv_buf[idx] == '\r') {
-          printf("%c", recv_buf[idx]);
-        } else {
-          break;
-        }
-      }
-      puts("");
-#endif
-      {
-        SDArchiverHashMap *headers_map = c_simple_http_request_to_headers_map(
-          (const char*)recv_buf,
-          (size_t)read_ret);
-        simple_archiver_list_get(
-          args.list_of_headers_to_log,
-          c_simple_http_headers_check_print,
-          headers_map);
-        simple_archiver_hash_map_free(&headers_map);
-      }
-
-      size_t response_size = 0;
-      enum C_SIMPLE_HTTP_ResponseCode response_code;
-      __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
-      char *request_path = NULL;
-      const char *response = c_simple_http_request_response(
-        (const char*)recv_buf,
-        (uint32_t)read_ret,
-        &parsed_config,
-        &response_size,
-        &response_code,
-        &args,
-        &request_path);
-      if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
-        CHECK_ERROR_WRITE_CONTINUE(write(
-          connection_fd, "HTTP/1.1 200 OK\n", 16));
-        CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "Allow: GET\n", 11));
-        CHECK_ERROR_WRITE_CONTINUE(write(
-          connection_fd, "Connection: close\n", 18));
-        CHECK_ERROR_WRITE_CONTINUE(write(
-          connection_fd, "Content-Type: text/html\n", 24));
-        char content_length_buf[128];
-        size_t content_length_buf_size = 0;
-        memcpy(content_length_buf, "Content-Length: ", 16);
-        content_length_buf_size = 16;
-        int32_t written = 0;
-        snprintf(
-          content_length_buf + content_length_buf_size,
-          127 - content_length_buf_size,
-          "%lu\n%n",
-          response_size,
-          &written);
-        if (written <= 0) {
-          close(connection_fd);
-          fprintf(
-            stderr,
-            "WARNING Failed to write in response, closing connection...\n");
-          continue;
-        }
-        content_length_buf_size += (size_t)written;
-        CHECK_ERROR_WRITE_CONTINUE(write(
-          connection_fd, content_length_buf, content_length_buf_size));
-        CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "\n", 1));
-        CHECK_ERROR_WRITE_CONTINUE(write(
-          connection_fd, response, response_size));
-
-        free((void*)response);
-      } else if (
-          response_code == C_SIMPLE_HTTP_Response_404_Not_Found
-          && args.static_dir) {
-        __attribute__((cleanup(c_simple_http_cleanup_static_file_info)))
-        C_SIMPLE_HTTP_StaticFileInfo file_info =
-          c_simple_http_get_file(args.static_dir, request_path, 0);
-        if (file_info.result == STATIC_FILE_RESULT_NoXDGMimeAvailable) {
-          file_info = c_simple_http_get_file(args.static_dir, request_path, 1);
-        }
-
-        if (file_info.result != STATIC_FILE_RESULT_OK
-            || !file_info.buf
-            || file_info.buf_size == 0
-            || !file_info.mime_type) {
-          if (file_info.result == STATIC_FILE_RESULT_FileError
-              || file_info.result == STATIC_FILE_RESULT_InternalError) {
-            response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
-          } else if (file_info.result == STATIC_FILE_RESULT_InvalidParameter) {
-            response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
-          } else if (file_info.result == STATIC_FILE_RESULT_404NotFound) {
-            response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
-          } else if (file_info.result == STATIC_FILE_RESULT_InvalidPath) {
-            response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
-          } else {
-            response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
-          }
-
-          if (c_simple_http_on_error(response_code, connection_fd)) {
-            continue;
-          }
-        } else {
-          CHECK_ERROR_WRITE_CONTINUE(write(
-            connection_fd, "HTTP/1.1 200 OK\n", 16));
-          CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "Allow: GET\n", 11));
-          CHECK_ERROR_WRITE_CONTINUE(write(
-            connection_fd, "Connection: close\n", 18));
-          uint64_t mime_length = strlen(file_info.mime_type);
-          __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
-          char *mime_type_buf = malloc(mime_length + 1 + 14 + 1);
-          snprintf(
-            mime_type_buf,
-            mime_length + 1 + 14 + 1,
-            "Content-Type: %s\n",
-            file_info.mime_type);
-          CHECK_ERROR_WRITE_CONTINUE(write(
-            connection_fd, mime_type_buf, mime_length + 1 + 14));
-          uint64_t content_str_len = 0;
-          for(uint64_t buf_size_temp = file_info.buf_size;
-              buf_size_temp > 0;
-              buf_size_temp /= 10) {
-            ++content_str_len;
-          }
-          if (content_str_len == 0) {
-            content_str_len = 1;
-          }
-          __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
-          char *content_length_buf = malloc(content_str_len + 1 + 16 + 1);
-          snprintf(
-            content_length_buf,
-            content_str_len + 1 + 16 + 1,
-            "Content-Length: %lu\n",
-            file_info.buf_size);
-          CHECK_ERROR_WRITE_CONTINUE(write(
-            connection_fd, content_length_buf, content_str_len + 1 + 16));
-          CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "\n", 1));
-          CHECK_ERROR_WRITE_CONTINUE(write(
-            connection_fd, file_info.buf, file_info.buf_size));
-          fprintf(stderr,
-                  "NOTICE Found static file for path \"%s\"\n",
-                  request_path);
-        }
-      } else {
-        if (c_simple_http_on_error(response_code, connection_fd)) {
-          continue;
-        }
-      }
-      close(connection_fd);
+      ConnectionItem *citem = malloc(sizeof(ConnectionItem));
+      memset(citem, 0, sizeof(ConnectionItem));
+      citem->fd = connection_fd;
+      ret = clock_gettime(CLOCK_MONOTONIC, &citem->time_point);
+      citem->peer_addr = peer_info.sin6_addr;
+      simple_archiver_list_add(connections,
+                               citem,
+                               c_simple_http_cleanup_connection_item);
     } else {
       printf("WARNING: accept: Unknown invalid state!\n");
     }
+
+    simple_archiver_list_remove(connections,
+                                c_simple_http_manage_connections,
+                                &connection_context);
 #ifndef NDEBUG
     //printf(".");
     //fflush(stdout);
index 3f64586ab7f1df50b7355c8e14ebcb3a32969291..49988fc58a410b9b8498d89c2ba3504dd37bdc8f 100644 (file)
@@ -43,4 +43,12 @@ void C_SIMPLE_HTTP_handle_sigusr1(int signal) {
   }
 }
 
+void C_SIMPLE_HTTP_handle_sigpipe(int signal) {
+  if (signal == SIGPIPE) {
+#ifndef NDEBUG
+    fprintf(stderr, "WARNING Recieved SIGPIPE\n");
+#endif
+  }
+}
+
 // vim: et ts=2 sts=2 sw=2
index 0237f40c05e00822faa33fda56c85096c1190e0f..91f8f13a92ea0fe36a5f49944671bebe70861345 100644 (file)
@@ -19,6 +19,7 @@
 
 void C_SIMPLE_HTTP_handle_sigint(int signal);
 void C_SIMPLE_HTTP_handle_sigusr1(int signal);
+void C_SIMPLE_HTTP_handle_sigpipe(int signal);
 
 #endif