promote: dev → stage (return type fix) #19

Merged
will.anderson merged 2 commits from dev into stage 2026-05-07 01:12:21 +00:00
2 changed files with 29 additions and 22 deletions
+22 -15
View File
@@ -177,15 +177,17 @@ static el_val_t el_wrap_str(char* s) {
/* ── I/O ──────────────────────────────────────────────────────────────────── */
void println(el_val_t s) {
el_val_t println(el_val_t s) {
const char* str = EL_CSTR(s);
if (str) puts(str);
else puts("");
return 0;
}
void print(el_val_t s) {
el_val_t print(el_val_t s) {
const char* str = EL_CSTR(s);
if (str) fputs(str, stdout);
return 0;
}
el_val_t readline(void) {
@@ -1090,7 +1092,7 @@ void el_runtime_register_handler(const char* name, http_handler_fn fn) {
pthread_mutex_unlock(&_http_handler_mu);
}
void http_set_handler(el_val_t name) {
el_val_t http_set_handler(el_val_t name) {
const char* n = EL_CSTR(name);
pthread_mutex_lock(&_http_handler_mu);
free(_http_active_handler);
@@ -1114,6 +1116,7 @@ void http_set_handler(el_val_t name) {
}
}
pthread_mutex_unlock(&_http_handler_mu);
return 0;
}
static http_handler_fn http_lookup_active(void) {
@@ -1571,18 +1574,18 @@ static void* http_worker(void* arg) {
return NULL;
}
void http_serve(el_val_t port, el_val_t handler) {
el_val_t http_serve(el_val_t port, el_val_t handler) {
/* If `handler` looks like a string name, register it as the active handler. */
const char* hname = EL_CSTR(handler);
if (hname && looks_like_string(handler)) {
http_set_handler(handler);
}
int p = (int)port;
if (p <= 0 || p > 65535) { fprintf(stderr, "http_serve: invalid port %d\n", p); return; }
if (p <= 0 || p > 65535) { fprintf(stderr, "http_serve: invalid port %d\n", p); return 0; }
/* Dual-stack: AF_INET6 with IPV6_V6ONLY=0 accepts both IPv4 and IPv6.
* This makes `localhost` work in browsers that resolve it to ::1 first. */
int sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock < 0) { perror("socket"); return; }
if (sock < 0) { perror("socket"); return 0; }
int yes = 1; int no = 0;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
@@ -1592,9 +1595,9 @@ void http_serve(el_val_t port, el_val_t handler) {
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons((uint16_t)p);
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind"); close(sock); return;
perror("bind"); close(sock); return 0;
}
if (listen(sock, 64) < 0) { perror("listen"); close(sock); return; }
if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; }
fprintf(stderr, "[http] listening on [::]:%d (dual-stack)\n", p);
while (1) {
struct sockaddr_in6 cli;
@@ -1625,6 +1628,7 @@ void http_serve(el_val_t port, el_val_t handler) {
pthread_detach(tid);
}
close(sock);
return 0;
}
/* ── HTTP server v2 — request headers + structured response ──────────────── */
@@ -1676,7 +1680,7 @@ void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn) {
pthread_mutex_unlock(&_http_handler_mu);
}
void http_set_handler_v2(el_val_t name) {
el_val_t http_set_handler_v2(el_val_t name) {
const char* n = EL_CSTR(name);
pthread_mutex_lock(&_http_handler_mu);
free(_http_active_handler4);
@@ -1698,6 +1702,7 @@ void http_set_handler_v2(el_val_t name) {
}
}
pthread_mutex_unlock(&_http_handler_mu);
return 0;
}
static http_handler4_fn http_lookup_active_v2(void) {
@@ -1818,7 +1823,7 @@ static void* http_worker_v2(void* arg) {
return NULL;
}
void http_serve_v2(el_val_t port, el_val_t handler) {
el_val_t http_serve_v2(el_val_t port, el_val_t handler) {
const char* hname = EL_CSTR(handler);
if (hname && looks_like_string(handler)) {
http_set_handler_v2(handler);
@@ -1826,11 +1831,11 @@ void http_serve_v2(el_val_t port, el_val_t handler) {
int p = (int)port;
if (p <= 0 || p > 65535) {
fprintf(stderr, "http_serve_v2: invalid port %d\n", p);
return;
return 0;
}
/* Dual-stack: same as http_serve - AF_INET6 + IPV6_V6ONLY=0. */
int sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock < 0) { perror("socket"); return; }
if (sock < 0) { perror("socket"); return 0; }
int yes = 1; int no = 0;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
@@ -1840,9 +1845,9 @@ void http_serve_v2(el_val_t port, el_val_t handler) {
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons((uint16_t)p);
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind"); close(sock); return;
perror("bind"); close(sock); return 0;
}
if (listen(sock, 64) < 0) { perror("listen"); close(sock); return; }
if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; }
fprintf(stderr, "[http v2] listening on [::]:%d (dual-stack)\n", p);
while (1) {
struct sockaddr_in6 cli;
@@ -1873,6 +1878,7 @@ void http_serve_v2(el_val_t port, el_val_t handler) {
pthread_detach(tid);
}
close(sock);
return 0;
}
/* Build the response envelope a 4-arg handler can return. We hand-write
@@ -5656,8 +5662,9 @@ el_val_t parse_int(el_val_t sv, el_val_t default_val) {
/* ── Process ─────────────────────────────────────────────────────────────── */
void exit_program(el_val_t code) {
el_val_t exit_program(el_val_t code) {
exit((int)code);
return 0; /* unreachable */
}
/* getpid_now — current process id. Named with the _now suffix to avoid
+7 -7
View File
@@ -81,8 +81,8 @@ extern "C" {
/* ── I/O ──────────────────────────────────────────────────────────────────── */
void println(el_val_t s);
void print(el_val_t s);
el_val_t println(el_val_t s);
el_val_t print(el_val_t s);
el_val_t readline(void);
/* ── String builtins ─────────────────────────────────────────────────────── */
@@ -153,8 +153,8 @@ el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_m
el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body);
el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header);
el_val_t http_delete(el_val_t url);
void http_serve(el_val_t port, el_val_t handler);
void http_set_handler(el_val_t name);
el_val_t http_serve(el_val_t port, el_val_t handler);
el_val_t http_set_handler(el_val_t name);
/* HTTP server v2 ─────────────────────────────────────────────────────────────
* Same dispatch model as http_serve, but the handler signature is widened:
@@ -175,8 +175,8 @@ void http_set_handler(el_val_t name);
* The 3-arg http_serve(port, handler) remains supported unchanged for
* existing handlers (e.g. products/web/server.el): it dispatches with
* (method, path, body), hardcodes 200 OK, and auto-detects content type. */
void http_serve_v2(el_val_t port, el_val_t handler);
void http_set_handler_v2(el_val_t name);
el_val_t http_serve_v2(el_val_t port, el_val_t handler);
el_val_t http_set_handler_v2(el_val_t name);
/* Build an HTTP response envelope. `headers_json` should be a JSON object
* literal like `{"WWW-Authenticate":"Basic"}` (or "" / "{}" for none). The
@@ -528,7 +528,7 @@ el_val_t parse_int(el_val_t s, el_val_t default_val);
/* ── Process ─────────────────────────────────────────────────────────────── */
void exit_program(el_val_t code);
el_val_t exit_program(el_val_t code);
el_val_t getpid_now(void);
/* ── CGI identity ─────────────────────────────────────────────────────────────