cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
async_server.c
Go to the documentation of this file.
1#define _POSIX_C_SOURCE 200809L
2#include <cwist/sys/app/app.h>
9#include "../../sys/io/reactor_rx.h"
10#include "sockopts.h"
11#include <fcntl.h>
12#include <errno.h>
13#include <unistd.h>
14#include <stdio.h>
15#include <string.h>
16#include <time.h>
17#include <sys/socket.h>
18#include <arpa/inet.h>
19#include <netinet/tcp.h>
20#if defined(__linux__)
22#endif
23
24static cwist_reactor_t *g_reactor = NULL;
25
35static bool app_use_https(const cwist_app *app) {
36 return app && app->use_ssl && app->ssl_ctx && app->https_request_handler;
37}
38
46static void async_accept_dispatch(cwist_app *app, int client_fd) {
47 /* The fd number may have been a closed socket's: reset its epoll
48 * registration hint before the first arm. */
49 cwist_reactor_fd_forget(client_fd);
50 int nodelay = 1;
51 setsockopt(client_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay));
52#if defined(__linux__) && defined(TCP_QUICKACK)
53 int quickack = 1;
54 setsockopt(client_fd, IPPROTO_TCP, TCP_QUICKACK, &quickack, sizeof(quickack));
55#endif
56
57 if (app_use_https(app)) {
58 cwist_https_dispatch(client_fd, app->ssl_ctx, app->https_request_handler, app);
59 } else if (app && !app->use_ssl) {
61 } else {
62 fprintf(
63 stderr,
64 "[async] SSL request accepted but HTTPS not ready (use_ssl=%d ssl_ctx=%p handler=%p), closing fd=%d\n",
65 app ? app->use_ssl : -1, app ? (void *)app->ssl_ctx : NULL,
66 app ? (void *)app->https_request_handler : NULL, client_fd);
67 close(client_fd);
68 }
69}
70
71#if defined(__linux__)
72/* Multishot-accept arm context: outlives the registration, so it is static
73 * (one async server loop per process, like g_reactor). */
74typedef struct {
75 cwist_app *app;
76 int listen_fd;
79
80static void async_accept_cb(int fd, void *ctx);
81
90static void async_accept_uring_cb(void *ctx, int fd) {
92 if (fd < 0) {
93 if (g_reactor && atomic_load(&g_cwist_running)) {
94 cwist_reactor_add(g_reactor, ac->listen_fd, async_accept_cb, &ac->app,
95 sizeof(ac->app));
96 }
97 return;
98 }
99 async_accept_dispatch(ac->app, fd);
100}
101#endif
102
119static void async_accept_cb(int fd, void *ctx) {
120 /* ctx is the reactor slot's inline payload holding the app pointer. */
121 cwist_app *app = *(cwist_app **)ctx;
122 int client_fd;
123#if defined(__linux__)
124 while ((client_fd = accept4(fd, NULL, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK)) >= 0) {
125#else
126 struct sockaddr_in addr;
127 socklen_t len = sizeof(addr);
128 while ((client_fd = accept(fd, (struct sockaddr *)&addr, &len)) >= 0) {
129#endif
130 async_accept_dispatch(app, client_fd);
131 }
132
133 /* Re-arm the listening socket so we can accept the next batch. A
134 * transient submission failure (e.g. a momentarily full io_uring SQ
135 * under a connect burst) must not silently stop accepting on this
136 * worker forever — retry with a short backoff, then scream. */
137 if (g_reactor) {
139 for (int attempt = 0; attempt < 1000; attempt++) {
140 if (cwist_reactor_add(g_reactor, fd, async_accept_cb, &app, sizeof(app))) {
141 return;
142 }
143 struct timespec ts = {.tv_sec = 0, .tv_nsec = 10 * 1000 * 1000};
144 nanosleep(&ts, NULL);
145 }
146 fprintf(
147 stderr,
148 "[async] FATAL: listen socket re-arm failed 1000x; this worker stopped accepting\n");
149 } else {
150 cwist_reactor_stop(g_reactor);
151 }
152 }
153}
154
176 memset(&err, 0, sizeof(err));
177 err.errtype = CWIST_ERR_INT16;
178 err.error.err_i16 = -1;
179
180 bool use_https = app_use_https(app);
181 if (use_https) {
182 if (https_pool_init() != 0) {
183 fprintf(stderr, "[async] Failed to init HTTPS thread pool\n");
184 return err;
185 }
186 } else {
187 /* This loop only drives reactor workers: do not re-read
188 * CWIST_C1M_MODE, which cwist_app_listen_ex() may have overridden. */
189 if (cwist_http_pool_init_mode(true) != 0) {
190 fprintf(stderr, "[async] Failed to init HTTP thread pool\n");
191 return err;
192 }
193 }
194
195 int flags = fcntl(server_fd, F_GETFL, 0);
196 if (flags < 0 || fcntl(server_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
197 perror("[async] Failed to set server socket non-blocking");
198 if (use_https)
200 else
202 return err;
203 }
204
205#if defined(SO_REUSEPORT)
207 int reuseport = 1;
209 }
210#endif
211
213
214 g_reactor = cwist_reactor_create();
215 if (!g_reactor) {
216 fprintf(stderr, "[async] Failed to create reactor\n");
217 if (use_https)
219 else
221 return err;
222 }
223
224#if defined(__linux__)
225 /* io_uring reactors: one multishot ACCEPT SQE replaces the one-shot
226 * POLL + accept4 drain loop. Arm failure (no ring, knob off) and a
227 * terminal completion both land on the legacy path. */
228 g_accept_ctx = (async_accept_ctx_t){.app = app, .listen_fd = server_fd};
229 if (!cwist_reactor_accept_arm(g_reactor, server_fd, async_accept_uring_cb, &g_accept_ctx))
230#endif
231 cwist_reactor_add(g_reactor, server_fd, async_accept_cb, &app, sizeof(app));
232#if defined(__linux__)
234 if (cwist_io_uring_init_sqpoll(&sq_probe, 64, 1000) == 0) {
235 printf("[io_uring/SQPOLL] Kernel submission poller verified (0-syscall I/O enabled).\n");
237 }
238#endif
239 printf("[io_uring/kqueue/epoll] Reactor started for C1M scale.\n");
240
241 cwist_reactor_run(g_reactor);
242
243 cwist_reactor_destroy(g_reactor);
244 g_reactor = NULL;
245
246 if (use_https) {
248 } else {
250 }
251
252 err.error.err_i16 = 0;
253 return err;
254}
Memory allocation wrappers backed by libttak.
cwist_error_t cwist_async_server_loop(int server_fd, cwist_app *app)
Run the async (reactor-based) HTTP/HTTPS server loop for C1M scale.
@ CWIST_ERR_INT16
used when checking common errcodes in Unix/Linux
Definition cwist_err.h:16
HTTP/2 Protocol Definitions for CWIST.
bool cwist_reuseport_enabled(void)
Definition http.c:5347
HTTP Protocol Definitions and Helpers.
bool cwist_http_pool_submit_async(int client_fd, cwist_async_handler_t handler, void *ctx)
Submit a connection to the C1M async reactor pool.
Definition http.c:1468
void cwist_http_pool_destroy(void)
Tear down both pool variants.
Definition http.c:836
int cwist_http_pool_init_mode(bool use_c1m)
Initialize the handler pool as reactor workers (use_c1m) or the classic thread pool,...
Definition http.c:696
HTTPS/TLS wrapper interface.
void https_pool_destroy(void)
Shut down the global HTTPS thread pool: signal workers to exit, join them, close any connections stil...
Definition https.c:370
int https_pool_init(void)
Create the worker threads, mutex, and condition variables of the global HTTPS thread pool....
Definition https.c:268
void cwist_https_dispatch(int client_fd, cwist_https_context *ctx, void(*handler)(cwist_https_connection *, void *), void *user_ctx)
Accept a TLS connection without parking a worker on the handshake. Completes the handshake inline whe...
Definition https.c:1141
#define SOCK_CLOEXEC
Definition orm_socket.c:442
size_t cap
Definition otel.c:56
struct cwist_reactor cwist_reactor_t
Definition reactor.h:14
bool cwist_reactor_add(cwist_reactor_t *reactor, int fd, cwist_reactor_cb_t cb, const void *payload, size_t payload_size)
Definition reactor.c:1357
void cwist_reactor_destroy(cwist_reactor_t *reactor)
Definition reactor.c:1116
void cwist_reactor_stop(cwist_reactor_t *reactor)
Definition reactor.c:1904
cwist_reactor_t * cwist_reactor_create(void)
Definition reactor.c:1006
void cwist_reactor_run(cwist_reactor_t *reactor)
Definition reactor.c:1579
Unified Graceful Shutdown support for CWIST.
int g_cwist_listen_fd
Registered TCP listening socket (for signal-handler closure).
Definition shutdown.c:18
atomic_int g_cwist_running
Global running flag. Checked by all server event loops.
Definition shutdown.c:17
Listen-socket option knobs shared by the bind sites (private).
Main Application Context.
Definition app.h:155
bool use_ssl
Definition app.h:157
cwist_https_context * ssl_ctx
SSL context when TLS is enabled.
Definition app.h:177
cwist_https_request_handler_func https_request_handler
Definition app.h:164
Integrated error structure used throughout the system.
Definition cwist_err.h:72
Core Application Structure and Lifecycle Management.
cwist_async_action_t cwist_app_http_handler_async(int client_fd, cwist_http_async_conn_t *conn)
Definition app.c:3343
Zero-syscall I/O engine powered by Linux io_uring SQPOLL.