Mercurial
view seobeo/os/s_linux_edge.c @ 196:83f16548ba41
[AI] Adding s3 bucket uploader code using Seobeo.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sat, 14 Feb 2026 16:08:15 -0800 |
| parents | a8976a008a9d |
| children |
line wrap: on
line source
#include <sys/epoll.h> #include <netinet/tcp.h> #include "seobeo/seobeo.h" // TCP keep-alive settings #define KEEP_ALIVE_IDLE_SEC 30 // Start probes after 30s idle #define KEEP_ALIVE_INTERVAL 5 // Probe every 5 seconds #define KEEP_ALIVE_COUNT 3 // Close after 3 failed probes // Configure TCP keep-alive on socket (kernel handles timeout) static void configure_keep_alive(int socket) { int enable = 1; setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); int idle = KEEP_ALIVE_IDLE_SEC; setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)); int interval = KEEP_ALIVE_INTERVAL; setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); int count = KEEP_ALIVE_COUNT; setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count)); } void *Seobeo_Web_Edge_Worker(void *vargs) { WorkerArgs *args = vargs; const int max_events = 64; struct epoll_event events[max_events]; int epfd = epoll_create1(0); if (epfd < 0) { perror("epoll_create1"); return NULL; } struct epoll_event ev = { .events = EPOLLIN | EPOLLET, .data.ptr = args->srv }; if (epoll_ctl(epfd, EPOLL_CTL_ADD, args->srv->socket, &ev) < 0) { perror("epoll_ctl ADD server"); close(epfd); return NULL; } while (1) { int n = epoll_wait(epfd, events, max_events, -1); // Block indefinitely, kernel handles timeouts if (n < 0) { if (errno == EINTR) continue; perror("epoll_wait"); continue; } for (int i = 0; i < n; i++) { Seobeo_Handle *p_handle = events[i].data.ptr; // Server socket - accept new connections if (p_handle == args->srv) { while (1) { Seobeo_Handle *p_cli_handle = Seobeo_Stream_Handle_Server_Accept(args->srv); if (!p_cli_handle) break; // Let kernel handle keep-alive timeout configure_keep_alive(p_cli_handle->socket); struct epoll_event client_ev = { .events = EPOLLIN | EPOLLET, .data.ptr = p_cli_handle }; if (epoll_ctl(epfd, EPOLL_CTL_ADD, p_cli_handle->socket, &client_ev) < 0) { perror("epoll_ctl ADD client"); Seobeo_Handle_Destroy(p_cli_handle); } } } // Client socket - handle request else { Seobeo_Handle *p_client_handle = p_handle; // Connection error or hangup - clean up if (events[i].events & (EPOLLERR | EPOLLHUP)) { epoll_ctl(epfd, EPOLL_CTL_DEL, p_client_handle->socket, NULL); Seobeo_Handle_Destroy(p_client_handle); continue; } // Handle requests (loop for pipelined requests) boolean keep_alive = TRUE; while (keep_alive) { keep_alive = Seobeo_Web_ClientHandle_Request(p_client_handle, args->cache, TRUE); // No more data in buffer, wait for next epoll event if (keep_alive && p_client_handle->read_buffer_len == 0) break; } // Client wants to close if (!keep_alive) { epoll_ctl(epfd, EPOLL_CTL_DEL, p_client_handle->socket, NULL); Seobeo_Handle_Destroy(p_client_handle); } // Connection stays open, kernel will timeout if idle } } } close(epfd); return NULL; } void Seobeo_Web_Edge( Seobeo_Handle *p_server_handle, int thread_count, Seobeo_Cache_Entry *p_html_cache) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 5 * 1024 * 1024); // 5 MB pthread_t threads[thread_count]; for (int i = 0; i < thread_count; i++) { WorkerArgs *args = malloc(sizeof(WorkerArgs)); *args = (WorkerArgs){ p_server_handle, p_html_cache }; pthread_create(&threads[i], &attr, Seobeo_Web_Edge_Worker, args); } // Join threads instead of detaching for proper cleanup for (int i = 0; i < thread_count; i++) pthread_join(threads[i], NULL); pthread_attr_destroy(&attr); }