From eec117404702b5c613dcfadbb30e2c4181b4c8ed Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Fri, 21 Nov 2025 23:02:18 +0100 Subject: [PATCH] Fix issues that caused the server to hang --- Makefile | 2 +- chttp.c | 163 ++++++++++++++++++++++++++++++++----------------- chttp.h | 28 ++++++--- main.c | 47 ++++++++++++++ src/includes.h | 2 +- src/server.c | 144 ++++++++++++++++++++++++++++--------------- src/server.h | 20 ++++-- src/socket.c | 22 ++++--- src/socket.h | 6 +- 9 files changed, 308 insertions(+), 126 deletions(-) diff --git a/Makefile b/Makefile index 3b7ecc9..9955ee5 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ chttp.c chttp.h: $(wildcard src/*.c src/*.h) misc/amalg.py Makefile python misc/amalg.py example: main.c chttp.c chttp.h - gcc main.c chttp.c -o example -Wfatal-errors -lws2_32 + gcc main.c chttp.c -o example -ggdb clean: rm chttp.c chttp.h diff --git a/chttp.c b/chttp.c index 9c0f04a..3cdee62 100644 --- a/chttp.c +++ b/chttp.c @@ -1879,13 +1879,12 @@ void socket_manager_free(SocketManager *sm) } int socket_manager_listen_tcp(SocketManager *sm, - HTTP_String addr, Port port) + HTTP_String addr, Port port, int backlog, + bool reuse_addr) { if (sm->plain_sock != NATIVE_SOCKET_INVALID) return -1; - bool reuse_addr = false; - int backlog = 32; sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog); if (sm->plain_sock == NATIVE_SOCKET_INVALID) return -1; @@ -1894,14 +1893,13 @@ int socket_manager_listen_tcp(SocketManager *sm, } int socket_manager_listen_tls(SocketManager *sm, - HTTP_String addr, Port port, HTTP_String cert_file, + HTTP_String addr, Port port, int backlog, + bool reuse_addr, HTTP_String cert_file, HTTP_String key_file) { if (sm->secure_sock != NATIVE_SOCKET_INVALID) return -1; - bool reuse_addr = false; - int backlog = 32; sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog); if (sm->secure_sock == NATIVE_SOCKET_INVALID) return -1; @@ -2374,6 +2372,12 @@ static int socket_manager_register_events_nolock( continue; j++; + // TODO: comment + if (s->state == SOCKET_STATE_DIED || s->state == SOCKET_STATE_ESTABLISHED_READY) { + reg->num_polled = 0; + return 0; + } + if (s->events) { reg->polled[reg->num_polled].fd = s->sock; reg->polled[reg->num_polled].events = s->events; @@ -2423,6 +2427,9 @@ static int socket_manager_translate_events_nolock( int num_events = 0; for (int i = 0; i < reg->num_polled; i++) { + if (!reg->polled[i].revents) + continue; + if (reg->polled[i].fd == sm->plain_sock || reg->polled[i].fd == sm->secure_sock) { @@ -3849,6 +3856,10 @@ int http_server_init(HTTP_Server *server) server->input_buffer_limit = 1<<20; server->output_buffer_limit = 1<<20; + server->trace_bytes = false; + server->reuse_addr = false; + server->backlog = 32; + server->num_conns = 0; for (int i = 0; i < HTTP_SERVER_CAPACITY; i++) { server->conns[i].state = HTTP_SERVER_CONN_FREE; @@ -3888,10 +3899,26 @@ void http_server_set_output_limit(HTTP_Server *server, uint32_t limit) server->output_buffer_limit = limit; } +void http_server_set_trace_bytes(HTTP_Server *server, bool value) +{ + server->trace_bytes = value; +} + +void http_server_set_reuse_addr(HTTP_Server *server, bool reuse) +{ + server->reuse_addr = reuse; +} + +void http_server_set_backlog(HTTP_Server *server, int backlog) +{ + server->backlog = backlog; +} + int http_server_listen_tcp(HTTP_Server *server, HTTP_String addr, Port port) { - if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0) + if (socket_manager_listen_tcp(&server->sockets, addr, + port, server->backlog, server->reuse_addr) < 0) return -1; return 0; } @@ -3901,7 +3928,8 @@ int http_server_listen_tls(HTTP_Server *server, HTTP_String key_file_name) { if (socket_manager_listen_tls(&server->sockets, addr, - port, cert_file_name, key_file_name) < 0) + port, server->backlog, server->reuse_addr, + cert_file_name, key_file_name) < 0) return -1; return 0; } @@ -3961,7 +3989,7 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn) } else { // Ready - assert(ret == 1); + assert(ret > 0); conn->state = HTTP_SERVER_CONN_WAIT_STATUS; conn->request_len = ret; @@ -3975,6 +4003,67 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn) } } +static void +http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn) +{ + if (conn->state == HTTP_SERVER_CONN_FLUSHING) { + + ByteView src = byte_queue_read_buf(&conn->output); + + int num = 0; + if (src.len) + num = socket_send(&server->sockets, conn->handle, src.ptr, src.len); + + if (server->trace_bytes) + print_bytes(HTTP_STR("<< "), (HTTP_String) { src.ptr, num }); + + byte_queue_read_ack(&conn->output, num); + + if (byte_queue_error(&conn->output)) { + socket_close(&server->sockets, conn->handle); + return; + } + + if (byte_queue_empty(&conn->output)) { + // We finished sending the response. Now we can + // either close the connection or process a new + // buffered request. + if (conn->closing) { + socket_close(&server->sockets, conn->handle); + return; + } + conn->state = HTTP_SERVER_CONN_BUFFERING; + } + } + + if (conn->state == HTTP_SERVER_CONN_BUFFERING) { + + int min_recv = 1<<10; + byte_queue_write_setmincap(&conn->input, min_recv); + + // Note that it's extra important that we don't + // buffer while the user is building the response. + // If we did that, a resize would invalidate all + // pointers on the parsed request structure. + ByteView dst = byte_queue_write_buf(&conn->input); + + int num = 0; + if (dst.len) + num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len); + + if (server->trace_bytes) + print_bytes(HTTP_STR(">> "), (HTTP_String) { dst.ptr, num }); + + byte_queue_write_ack(&conn->input, num); + + if (byte_queue_error(&conn->output)) { + socket_close(&server->sockets, conn->handle); + } else { + check_request_buffer(server, conn); + } + } +} + int http_server_process_events(HTTP_Server *server, EventRegister *reg) { @@ -4001,13 +4090,13 @@ int http_server_process_events(HTTP_Server *server, continue; } - int i = 0; - while (server->conns[i].state != HTTP_SERVER_CONN_FREE) { - i++; + int j = 0; + while (server->conns[j].state != HTTP_SERVER_CONN_FREE) { + j++; assert(i < HTTP_SERVER_CAPACITY); } - conn = &server->conns[i]; + conn = &server->conns[j]; http_server_conn_init(conn, events[i].handle, server->input_buffer_limit, @@ -4017,45 +4106,7 @@ int http_server_process_events(HTTP_Server *server, socket_set_user(&server->sockets, events[i].handle, conn); } - if (conn->state == HTTP_SERVER_CONN_BUFFERING) { - - int min_recv = 1<<10; - byte_queue_write_setmincap(&conn->input, min_recv); - - // Note that it's extra important that we don't - // buffer while the user is building the response. - // If we did that, a resize would invalidate all - // pointers on the parsed request structure. - int num = 0; - ByteView dst = byte_queue_write_buf(&conn->input); - if (dst.len) num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len); - byte_queue_write_ack(&conn->input, num); - - if (byte_queue_error(&conn->output)) - socket_close(&server->sockets, conn->handle); - else - check_request_buffer(server, conn); - - } else if (conn->state == HTTP_SERVER_CONN_FLUSHING) { - - int num = 0; - ByteView src = byte_queue_read_buf(&conn->output); - if (src.len) num = socket_send(&server->sockets, conn->handle, src.ptr, src.len); - byte_queue_read_ack(&conn->output, num); - - if (byte_queue_error(&conn->output)) - socket_close(&server->sockets, conn->handle); - else if (byte_queue_empty(&conn->output)) { - // We finished sending the response. Now we can - // either close the connection or process a new - // buffered request. - if (conn->closing) { - socket_close(&server->sockets, conn->handle); - } else { - check_request_buffer(server, conn); - } - } - } + http_server_conn_process_events(server, conn); } } @@ -4225,10 +4276,10 @@ static void append_special_headers(HTTP_ServerConn *conn) HTTP_String s; if (conn->closing) { - s = HTTP_STR("Connection: Close"); + s = HTTP_STR("Connection: Close\r\n"); byte_queue_write(&conn->output, s.ptr, s.len); } else { - s = HTTP_STR("Connection: Keep-Alive"); + s = HTTP_STR("Connection: Keep-Alive\r\n"); byte_queue_write(&conn->output, s.ptr, s.len); } @@ -4275,7 +4326,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str) byte_queue_write(&conn->output, str.ptr, str.len); } -void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str) +void http_response_builder_send(HTTP_ResponseBuilder builder) { HTTP_ServerConn *conn = builder_to_conn(builder); if (conn == NULL) @@ -4299,6 +4350,8 @@ void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str) conn->state = HTTP_SERVER_CONN_FLUSHING; conn->gen++; + + http_server_conn_process_events(builder.server, conn); } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/chttp.h b/chttp.h index fecc7e5..5792972 100644 --- a/chttp.h +++ b/chttp.h @@ -26,7 +26,7 @@ #include #include #include -#include - +#include #include #include #include @@ -493,7 +493,8 @@ void socket_manager_free(SocketManager *sm); // can only be used once per manager. // Returns 0 on success, -1 on error. int socket_manager_listen_tcp(SocketManager *sm, - HTTP_String addr, Port port); + HTTP_String addr, Port port, int backlog, + bool reuse_addr); // Same as the previous function, but incoming // connections will be interpreted as TLS. You @@ -503,7 +504,8 @@ int socket_manager_listen_tcp(SocketManager *sm, // and secure connections. // Returns 0 on success, -1 on error. int socket_manager_listen_tls(SocketManager *sm, - HTTP_String addr, Port port, HTTP_String cert_file, + HTTP_String addr, Port port, int backlog, + bool reuse_addr, HTTP_String cert_file, HTTP_String key_file); // If the socket manager was configures to accept @@ -1012,6 +1014,10 @@ typedef struct { uint32_t input_buffer_limit; uint32_t output_buffer_limit; + bool trace_bytes; + bool reuse_addr; + int backlog; + // Array of connections. The counter contains the // number of structs such that state=FREE. int num_conns; @@ -1054,6 +1060,15 @@ void http_server_free(HTTP_Server *server); void http_server_set_input_limit(HTTP_Server *server, uint32_t limit); void http_server_set_output_limit(HTTP_Server *server, uint32_t limit); +// TODO: Comment +void http_server_set_trace_bytes(HTTP_Server *server, bool value); + +// TODO: Comment +void http_server_set_reuse_addr(HTTP_Server *server, bool reuse); + +// TODO: comment +void http_server_set_backlog(HTTP_Server *server, int backlog); + // Enable listening for plain HTTP requests at the // specified interface. int http_server_listen_tcp(HTTP_Server *server, @@ -1062,9 +1077,8 @@ int http_server_listen_tcp(HTTP_Server *server, // Enable listening for HTTPS requests at the specified // interfact, using the specified certificate and key // to verify the connection. -int http_server_listen_tls(HTTP_Server *server, - HTTP_String addr, Port port, HTTP_String cert_file_name, - HTTP_String key_file_name); +int http_server_listen_tls(HTTP_Server *server, HTTP_String addr, Port port, + HTTP_String cert_file_name, HTTP_String key_file_name); // Add the certificate for an additional domain when // the server is listening for HTTPS requests. @@ -1120,7 +1134,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str); // Mark the response as complete. This will invalidate // the response builder handle. -void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str); +void http_response_builder_send(HTTP_ResponseBuilder builder); //////////////////////////////////////////////////////////////////////////////////////// // Copyright 2025 Francesco Cozzuto diff --git a/main.c b/main.c index 2992206..9864620 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,52 @@ +#include "chttp.h" + +#ifdef _WIN32 +#define POLL WSAPoll +#else +#define POLL poll +#endif int main(void) { + HTTP_Server server; + if (http_server_init(&server) < 0) + return -1; + + http_server_set_reuse_addr(&server, true); + http_server_set_trace_bytes(&server, true); + + if (http_server_listen_tcp(&server, HTTP_STR("127.0.0.1"), 8080) < 0) + return -1; + + for (;;) { + + void *ptrs[HTTP_SERVER_CAPACITY+3]; + struct pollfd polled[HTTP_SERVER_CAPACITY+3]; + + EventRegister reg = { + .ptrs=ptrs, + .polled=polled, + .max_polled=HTTP_SERVER_CAPACITY+3, + .num_polled=0, + }; + + if (http_server_register_events(&server, ®) < 0) + return -1; + + if (reg.num_polled > 0) + POLL(reg.polled, reg.num_polled, -1); + + if (http_server_process_events(&server, ®) < 0) + return -1; + + HTTP_Request *request; + HTTP_ResponseBuilder builder; + if (http_server_next_request(&server, &request, &builder)) { + http_response_builder_status(builder, 200); + http_response_builder_send(builder); + } + } + + http_server_free(&server); return 0; } diff --git a/src/includes.h b/src/includes.h index 6bf0bbd..bb88b07 100644 --- a/src/includes.h +++ b/src/includes.h @@ -18,7 +18,7 @@ #include #include #include -#include - +#include #include #include #include diff --git a/src/server.c b/src/server.c index d01984a..605d75b 100644 --- a/src/server.c +++ b/src/server.c @@ -21,6 +21,10 @@ int http_server_init(HTTP_Server *server) server->input_buffer_limit = 1<<20; server->output_buffer_limit = 1<<20; + server->trace_bytes = false; + server->reuse_addr = false; + server->backlog = 32; + server->num_conns = 0; for (int i = 0; i < HTTP_SERVER_CAPACITY; i++) { server->conns[i].state = HTTP_SERVER_CONN_FREE; @@ -60,10 +64,26 @@ void http_server_set_output_limit(HTTP_Server *server, uint32_t limit) server->output_buffer_limit = limit; } +void http_server_set_trace_bytes(HTTP_Server *server, bool value) +{ + server->trace_bytes = value; +} + +void http_server_set_reuse_addr(HTTP_Server *server, bool reuse) +{ + server->reuse_addr = reuse; +} + +void http_server_set_backlog(HTTP_Server *server, int backlog) +{ + server->backlog = backlog; +} + int http_server_listen_tcp(HTTP_Server *server, HTTP_String addr, Port port) { - if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0) + if (socket_manager_listen_tcp(&server->sockets, addr, + port, server->backlog, server->reuse_addr) < 0) return -1; return 0; } @@ -73,7 +93,8 @@ int http_server_listen_tls(HTTP_Server *server, HTTP_String key_file_name) { if (socket_manager_listen_tls(&server->sockets, addr, - port, cert_file_name, key_file_name) < 0) + port, server->backlog, server->reuse_addr, + cert_file_name, key_file_name) < 0) return -1; return 0; } @@ -133,7 +154,7 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn) } else { // Ready - assert(ret == 1); + assert(ret > 0); conn->state = HTTP_SERVER_CONN_WAIT_STATUS; conn->request_len = ret; @@ -147,6 +168,67 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn) } } +static void +http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn) +{ + if (conn->state == HTTP_SERVER_CONN_FLUSHING) { + + ByteView src = byte_queue_read_buf(&conn->output); + + int num = 0; + if (src.len) + num = socket_send(&server->sockets, conn->handle, src.ptr, src.len); + + if (server->trace_bytes) + print_bytes(HTTP_STR("<< "), (HTTP_String) { src.ptr, num }); + + byte_queue_read_ack(&conn->output, num); + + if (byte_queue_error(&conn->output)) { + socket_close(&server->sockets, conn->handle); + return; + } + + if (byte_queue_empty(&conn->output)) { + // We finished sending the response. Now we can + // either close the connection or process a new + // buffered request. + if (conn->closing) { + socket_close(&server->sockets, conn->handle); + return; + } + conn->state = HTTP_SERVER_CONN_BUFFERING; + } + } + + if (conn->state == HTTP_SERVER_CONN_BUFFERING) { + + int min_recv = 1<<10; + byte_queue_write_setmincap(&conn->input, min_recv); + + // Note that it's extra important that we don't + // buffer while the user is building the response. + // If we did that, a resize would invalidate all + // pointers on the parsed request structure. + ByteView dst = byte_queue_write_buf(&conn->input); + + int num = 0; + if (dst.len) + num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len); + + if (server->trace_bytes) + print_bytes(HTTP_STR(">> "), (HTTP_String) { dst.ptr, num }); + + byte_queue_write_ack(&conn->input, num); + + if (byte_queue_error(&conn->output)) { + socket_close(&server->sockets, conn->handle); + } else { + check_request_buffer(server, conn); + } + } +} + int http_server_process_events(HTTP_Server *server, EventRegister *reg) { @@ -173,13 +255,13 @@ int http_server_process_events(HTTP_Server *server, continue; } - int i = 0; - while (server->conns[i].state != HTTP_SERVER_CONN_FREE) { - i++; + int j = 0; + while (server->conns[j].state != HTTP_SERVER_CONN_FREE) { + j++; assert(i < HTTP_SERVER_CAPACITY); } - conn = &server->conns[i]; + conn = &server->conns[j]; http_server_conn_init(conn, events[i].handle, server->input_buffer_limit, @@ -189,45 +271,7 @@ int http_server_process_events(HTTP_Server *server, socket_set_user(&server->sockets, events[i].handle, conn); } - if (conn->state == HTTP_SERVER_CONN_BUFFERING) { - - int min_recv = 1<<10; - byte_queue_write_setmincap(&conn->input, min_recv); - - // Note that it's extra important that we don't - // buffer while the user is building the response. - // If we did that, a resize would invalidate all - // pointers on the parsed request structure. - int num = 0; - ByteView dst = byte_queue_write_buf(&conn->input); - if (dst.len) num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len); - byte_queue_write_ack(&conn->input, num); - - if (byte_queue_error(&conn->output)) - socket_close(&server->sockets, conn->handle); - else - check_request_buffer(server, conn); - - } else if (conn->state == HTTP_SERVER_CONN_FLUSHING) { - - int num = 0; - ByteView src = byte_queue_read_buf(&conn->output); - if (src.len) num = socket_send(&server->sockets, conn->handle, src.ptr, src.len); - byte_queue_read_ack(&conn->output, num); - - if (byte_queue_error(&conn->output)) - socket_close(&server->sockets, conn->handle); - else if (byte_queue_empty(&conn->output)) { - // We finished sending the response. Now we can - // either close the connection or process a new - // buffered request. - if (conn->closing) { - socket_close(&server->sockets, conn->handle); - } else { - check_request_buffer(server, conn); - } - } - } + http_server_conn_process_events(server, conn); } } @@ -397,10 +441,10 @@ static void append_special_headers(HTTP_ServerConn *conn) HTTP_String s; if (conn->closing) { - s = HTTP_STR("Connection: Close"); + s = HTTP_STR("Connection: Close\r\n"); byte_queue_write(&conn->output, s.ptr, s.len); } else { - s = HTTP_STR("Connection: Keep-Alive"); + s = HTTP_STR("Connection: Keep-Alive\r\n"); byte_queue_write(&conn->output, s.ptr, s.len); } @@ -447,7 +491,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str) byte_queue_write(&conn->output, str.ptr, str.len); } -void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str) +void http_response_builder_send(HTTP_ResponseBuilder builder) { HTTP_ServerConn *conn = builder_to_conn(builder); if (conn == NULL) @@ -471,4 +515,6 @@ void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str) conn->state = HTTP_SERVER_CONN_FLUSHING; conn->gen++; + + http_server_conn_process_events(builder.server, conn); } diff --git a/src/server.h b/src/server.h index 3a86099..80bb1df 100644 --- a/src/server.h +++ b/src/server.h @@ -97,6 +97,10 @@ typedef struct { uint32_t input_buffer_limit; uint32_t output_buffer_limit; + bool trace_bytes; + bool reuse_addr; + int backlog; + // Array of connections. The counter contains the // number of structs such that state=FREE. int num_conns; @@ -139,6 +143,15 @@ void http_server_free(HTTP_Server *server); void http_server_set_input_limit(HTTP_Server *server, uint32_t limit); void http_server_set_output_limit(HTTP_Server *server, uint32_t limit); +// TODO: Comment +void http_server_set_trace_bytes(HTTP_Server *server, bool value); + +// TODO: Comment +void http_server_set_reuse_addr(HTTP_Server *server, bool reuse); + +// TODO: comment +void http_server_set_backlog(HTTP_Server *server, int backlog); + // Enable listening for plain HTTP requests at the // specified interface. int http_server_listen_tcp(HTTP_Server *server, @@ -147,9 +160,8 @@ int http_server_listen_tcp(HTTP_Server *server, // Enable listening for HTTPS requests at the specified // interfact, using the specified certificate and key // to verify the connection. -int http_server_listen_tls(HTTP_Server *server, - HTTP_String addr, Port port, HTTP_String cert_file_name, - HTTP_String key_file_name); +int http_server_listen_tls(HTTP_Server *server, HTTP_String addr, Port port, + HTTP_String cert_file_name, HTTP_String key_file_name); // Add the certificate for an additional domain when // the server is listening for HTTPS requests. @@ -205,4 +217,4 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str); // Mark the response as complete. This will invalidate // the response builder handle. -void http_response_builder_send(HTTP_ResponseBuilder builder, HTTP_String str); +void http_response_builder_send(HTTP_ResponseBuilder builder); diff --git a/src/socket.c b/src/socket.c index 12587f4..ea45081 100644 --- a/src/socket.c +++ b/src/socket.c @@ -177,13 +177,12 @@ void socket_manager_free(SocketManager *sm) } int socket_manager_listen_tcp(SocketManager *sm, - HTTP_String addr, Port port) + HTTP_String addr, Port port, int backlog, + bool reuse_addr) { if (sm->plain_sock != NATIVE_SOCKET_INVALID) return -1; - bool reuse_addr = false; - int backlog = 32; sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog); if (sm->plain_sock == NATIVE_SOCKET_INVALID) return -1; @@ -192,14 +191,13 @@ int socket_manager_listen_tcp(SocketManager *sm, } int socket_manager_listen_tls(SocketManager *sm, - HTTP_String addr, Port port, HTTP_String cert_file, + HTTP_String addr, Port port, int backlog, + bool reuse_addr, HTTP_String cert_file, HTTP_String key_file) { if (sm->secure_sock != NATIVE_SOCKET_INVALID) return -1; - bool reuse_addr = false; - int backlog = 32; sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog); if (sm->secure_sock == NATIVE_SOCKET_INVALID) return -1; @@ -365,7 +363,7 @@ static void socket_update(Socket *s) struct sockaddr_in6 buf; buf.sin6_family = AF_INET6; buf.sin6_port = htons(addr.port); - memcpy(&buf.sin6_addr, &addr.ipv6, sizeof(IPv6)); + memcpy(&buf.sin6_addr, &addr.ipv6, sizeof(HTTP_IPv6)); ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf)); } @@ -672,6 +670,13 @@ static int socket_manager_register_events_nolock( continue; j++; + // If at least one socket can be processed, return an + // empty list. + if (s->state == SOCKET_STATE_DIED || s->state == SOCKET_STATE_ESTABLISHED_READY) { + reg->num_polled = 0; + return 0; + } + if (s->events) { reg->polled[reg->num_polled].fd = s->sock; reg->polled[reg->num_polled].events = s->events; @@ -721,6 +726,9 @@ static int socket_manager_translate_events_nolock( int num_events = 0; for (int i = 0; i < reg->num_polled; i++) { + if (!reg->polled[i].revents) + continue; + if (reg->polled[i].fd == sm->plain_sock || reg->polled[i].fd == sm->secure_sock) { diff --git a/src/socket.h b/src/socket.h index 46d5344..a502a41 100644 --- a/src/socket.h +++ b/src/socket.h @@ -236,7 +236,8 @@ void socket_manager_free(SocketManager *sm); // can only be used once per manager. // Returns 0 on success, -1 on error. int socket_manager_listen_tcp(SocketManager *sm, - HTTP_String addr, Port port); + HTTP_String addr, Port port, int backlog, + bool reuse_addr); // Same as the previous function, but incoming // connections will be interpreted as TLS. You @@ -246,7 +247,8 @@ int socket_manager_listen_tcp(SocketManager *sm, // and secure connections. // Returns 0 on success, -1 on error. int socket_manager_listen_tls(SocketManager *sm, - HTTP_String addr, Port port, HTTP_String cert_file, + HTTP_String addr, Port port, int backlog, + bool reuse_addr, HTTP_String cert_file, HTTP_String key_file); // If the socket manager was configures to accept