diff --git a/src/constants.h b/src/constants.h
index 8b09a01..a99e5bb 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -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 \
diff --git a/src/main.c b/src/main.c
index 2aa1465..75448f3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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"
@@ -45,19 +46,55 @@
#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
500 Internal Server Error
\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,
+ "\n500 Internal Server Error
\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, ¤t_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);
diff --git a/src/signal_handling.c b/src/signal_handling.c
index 3f64586..49988fc 100644
--- a/src/signal_handling.c
+++ b/src/signal_handling.c
@@ -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
diff --git a/src/signal_handling.h b/src/signal_handling.h
index 0237f40..91f8f13 100644
--- a/src/signal_handling.h
+++ b/src/signal_handling.h
@@ -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