From d5c873a780357928fcccb27f4378b456f0e45dd2 Mon Sep 17 00:00:00 2001 From: turret Date: Wed, 17 Jan 2024 19:13:16 +0000 Subject: net: basic ws handler includes heartbeat mechanism --- net/net.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) (limited to 'net/net.c') diff --git a/net/net.c b/net/net.c index 332aef3..bad34c6 100644 --- a/net/net.c +++ b/net/net.c @@ -1,5 +1,11 @@ +#include +#include +#include +#include +#include #include #include +#include #include #include @@ -10,12 +16,120 @@ #include extern int http_get(char *url); +extern void ws_handle_event(cJSON *event); +extern void ws_send_heartbeat(); +CURL *ws_handle; char *gateway_url; int net_subsystem(void) { print(LOG_INFO "net: starting net subsystem"); + /* Set handler for heartbeats */ + /* + struct sigaction *alrmhandler = malloc(sizeof(struct sigaction)); + memset(alrmhandler, 0, sizeof(struct sigaction)); + alrmhandler->sa_handler = &ws_send_heartbeat; + alrmhandler->sa_flags |= SA_RESTART; + sigaction(SIGALRM, alrmhandler, NULL); + free(alrmhandler); + */ + + if(!gateway_url) + panic("net: gateway url invalid"); + + ws_handle = curl_easy_init(); + + curl_easy_setopt(ws_handle, CURLOPT_URL, gateway_url); + curl_easy_setopt(ws_handle, CURLOPT_CONNECT_ONLY, 2L); + + print(LOG_INFO "net: opening ws"); + CURLcode ret = curl_easy_perform(ws_handle); + + if(ret > 0) + panic("net: cannot open websocket (curl errno %d)", ret); + + int ws_sockfd; + if((ret = curl_easy_getinfo(ws_handle, + CURLINFO_ACTIVESOCKET, &ws_sockfd)) != CURLE_OK) + panic("net: curl cannot get active socket (errno %d)", ret); + +/* struct pollfd ws_sockpoll = { + .fd = ws_sockfd, + .events = POLLIN + }; */ + char *inbuf = malloc(1<<16 * sizeof(char)); + size_t rlen; + const struct curl_ws_frame *meta; + + /* Block ALRM */ + sigset_t *set = malloc(sizeof(sigset_t)); + sigaddset(set, SIGALRM); + sigprocmask(SIG_BLOCK, set, NULL); + int alrmfd = signalfd(-1, set, 0); + free(set); + + struct pollfd pollarray[2] = { + { + .fd = ws_sockfd, + .events = POLLIN, + .revents = POLLIN + }, + { + .fd = alrmfd, + .events = POLLIN, + .revents = 0 + } + }; + + struct pollfd *sockpoll = &(pollarray[0]); + struct pollfd *alrmpoll = &(pollarray[1]); + + errno = 0; + do { + if((sockpoll->revents & POLLIN) == POLLIN) { + ret = curl_ws_recv(ws_handle, inbuf, 1<<16, &rlen, &meta); + if(ret == CURLE_AGAIN) + continue; + if(ret != CURLE_OK) { + print(LOG_ERR "net: encountered curl error while reading socket (curl errno %d)", ret); + break; + } + + /* TODO: partial frames */ + if((meta->offset | meta->bytesleft) > 0) { + print(LOG_ERR "net: dropped partial frame"); + continue; + } + + cJSON *event = cJSON_ParseWithLength(inbuf, rlen); + if(!event) { + print(LOG_ERR "net: dropped malformed frame"); + continue; + } + ws_handle_event(event); + cJSON_Delete(event); + } else if((sockpoll->revents & (POLLRDHUP | POLLERR | POLLHUP | POLLNVAL)) > 0) { + print(LOG_ERR "net: encountered error on socket (revents %d)", sockpoll->revents); + break; + } + + if((alrmpoll->revents & POLLIN) == POLLIN) { + struct signalfd_siginfo siginfo; + read(alrmfd, &siginfo, sizeof(struct signalfd_siginfo)); + ws_send_heartbeat(); + } + } while(poll(pollarray, 2, -1) >= 0); + if(errno > 0) { + print(LOG_ERR "net: error encountered while polling (errno %d)", errno); + } + + free(inbuf); + + curl_easy_cleanup(ws_handle); + + panic("net: websocket closed unexpectedly"); + return 0; } -- cgit v1.2.3