From cbf4b60df6c6c8c7208dc29708677d24b2724deb Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Fri, 30 Oct 2026 13:17:39 +0100 Subject: Enforce the invariant that each socket is only ever expected to be read from or written to, never both --- opentracker.c | 9 ++++----- ot_http.c | 27 ++++++++++----------------- ot_http.h | 5 ++--- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/opentracker.c b/opentracker.c index b54327a..27b2570 100644 --- a/opentracker.c +++ b/opentracker.c @@ -180,12 +180,11 @@ static void handle_write(const int64_t sock) { /* In a chunked transfer, wait for the next piece once everything queued has gone out */ if (chunked) - http_interest_drop(sock, cookie, EVENT_OUT); + http_interest_set(sock, cookie, 0); else if (keep_alive) { - /* The reply is out and the client asked to keep the connection, so stop - waiting to write and go back to waiting for the next request */ - http_interest_drop(sock, cookie, EVENT_OUT); - http_interest_add(sock, cookie, EVENT_IN); + /* The reply is out and the client asked to keep the connection, so go + back to waiting for the next request */ + http_interest_set(sock, cookie, EVENT_IN); fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT)); } else http_close(sock); diff --git a/ot_http.c b/ot_http.c index e8ba3da..66f0102 100644 --- a/ot_http.c +++ b/ot_http.c @@ -118,11 +118,9 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) { batch_add(cookie->batch, outbuf, ws->reply_size - written_size); /* writeable short data sockets just have a tcp timeout */ - if (!ws->keep_alive) { + if (!ws->keep_alive) fdstate_set_expiry(sock, 0); - http_interest_drop(sock, cookie, EVENT_IN); - } - http_interest_add(sock, cookie, EVENT_OUT); + http_interest_set(sock, cookie, EVENT_OUT); } } @@ -135,21 +133,16 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) { #define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) #define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) #define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) -static void http_interest(const int64_t sock, struct http_data *cookie, int what) { +/* A connection is either being read or being written, never both, so what it + waits for is set outright rather than added to and taken away again. The + event layer only hears about it when the answer changes. */ +void http_interest_set(const int64_t sock, struct http_data *cookie, int what) { if (cookie->interest == what) return; cookie->interest = what; event_modify((int)sock, what, fdstate_generation((int)sock)); } -void http_interest_add(const int64_t sock, struct http_data *cookie, int what) { - http_interest(sock, cookie, cookie->interest | what); -} - -void http_interest_drop(const int64_t sock, struct http_data *cookie, int what) { - http_interest(sock, cookie, cookie->interest & ~what); -} - ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) { const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; @@ -194,7 +187,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t /* If we came here, wait for the answer is over */ if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { - http_interest_drop(sock, cookie, EVENT_IN); + http_interest_set(sock, cookie, 0); cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; } @@ -245,7 +238,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t } fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT_SEND)); - http_interest_add(sock, cookie, EVENT_OUT); + http_interest_set(sock, cookie, EVENT_OUT); return 0; } @@ -340,7 +333,7 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c /* Clients waiting for us should not easily timeout */ fdstate_set_expiry(sock, 0); fullscrape_deliver(sock, format); - http_interest_drop(sock, cookie, EVENT_IN); + http_interest_set(sock, cookie, 0); return ws->reply_size = -2; } #endif @@ -435,7 +428,7 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct * /* Clients waiting for us should not easily timeout */ fdstate_set_expiry(sock, 0); fullscrape_deliver(sock, format); - http_interest_drop(sock, cookie, EVENT_IN); + http_interest_set(sock, cookie, 0); return ws->reply_size = -2; } #endif diff --git a/ot_http.h b/ot_http.h index 0f351c1..ba16de4 100644 --- a/ot_http.h +++ b/ot_http.h @@ -33,9 +33,8 @@ struct http_data { STRUCT_HTTP_FLAG flag; }; -/* Add to or drop from what this connection is waiting to be told about */ -void http_interest_add(const int64_t s, struct http_data *cookie, int what); -void http_interest_drop(const int64_t s, struct http_data *cookie, int what); +/* What this connection is waiting for: EVENT_IN, EVENT_OUT, or nothing */ +void http_interest_set(const int64_t s, struct http_data *cookie, int what); /* Close a connection and release everything that belongs to it */ void http_close(const int64_t s); -- cgit v1.3