From ec7ce54de5583ab11de5b19e6efc146cb52c3418 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Mon, 12 Aug 2024 20:10:40 +0200 Subject: Refactor examples --- reduced_system_layer.c | 333 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 299 insertions(+), 34 deletions(-) (limited to 'reduced_system_layer.c') diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 379cc97..a200695 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -44,6 +44,7 @@ gcc \ -Wno-overlength-strings \ -O3 \ -fsanitize=undefined,address,leak -mshstk \ + -D REDUCED_SYSTEM_LAYER_EXAMPLE \ -lX11 -lm \ -o $BIN $SRC && \ ./$BIN $@ && rm $BIN @@ -57,6 +58,13 @@ exit $? # */ #define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + typedef signed char i8; typedef signed short i16; typedef signed i32; @@ -82,13 +90,13 @@ enum { MAX_INPUT_SIZE = 256, MAX_CLIPBOARD_SIZE = 10 * 1024 * 1024, MAX_NUM_AUDIO_SAMPLES = 0, - MAX_NUM_SOCKETS = 0, + MAX_NUM_SOCKETS = 64, AUDIO_NUM_CHANNELS = 2, AUDIO_SAMPLE_RATE = 44100, - IPv4 = 1, - IPv6 = 2, + IPv4_UDP = 1, + IPv6_UDP = 2, KEY_LEFT = 128, KEY_RIGHT, @@ -143,6 +151,7 @@ typedef struct { i64 clipboard_size; c8 * clipboard; b8 done; + b8 graceful_exit; b8 has_focus; b8 has_cursor; i32 cursor_x; @@ -155,11 +164,12 @@ typedef struct { } Platform; typedef struct { - u16 type; + u16 protocol; u16 port; union { - u8 v4_address[4]; - u8 v6_address[16]; + u32 v4_address_as_u32; + u8 v4_address[4]; + u8 v6_address[16]; }; } IP_Address; @@ -170,6 +180,11 @@ i32 utf8_size(c32 c); c32 utf8_read(i64 len, c8 *s); i32 utf8_write(c32 c, c8 *buffer); +// Time and sleep +i64 p_time(void); +void p_yield(void); +void p_sleep_for(i64 duration); + // Window void p_init(void); void p_cleanup(void); @@ -185,8 +200,8 @@ void p_handle_audio(i64 time_elapsed); void p_queue_sound(i64 delay, i64 num_samples, f32 *samples); // UDP sockets -i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, IP_Address *remote_address); -i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data); +i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address); +i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port); Platform platform = {0}; @@ -196,14 +211,16 @@ Platform platform = {0}; // // ================================================================ +#ifdef REDUCED_SYSTEM_LAYER_EXAMPLE + i32 main(i32 argc, c8 **argv) { (void) argc; (void) argv; platform = (Platform) { .title = "Reduced System Layer", - .frame_width = 960, - .frame_height = 720, + .frame_width = 1280, + .frame_height = 720, }; p_init(); @@ -217,6 +234,8 @@ i32 main(i32 argc, c8 **argv) { return 0; } +#endif + // ================================================================ // // PLATFORM IMPLEMENTATION @@ -225,7 +244,6 @@ i32 main(i32 argc, c8 **argv) { // // TODO // - Sound -// - Sockets // - Clipboard daemon // // ALSA @@ -233,9 +251,6 @@ i32 main(i32 argc, c8 **argv) { // // ================================================================ -#include -#include - c32 utf8_read(i64 len, c8 *s) { if (len >= 1 && (s[0] & 0x80) == 0) @@ -302,31 +317,271 @@ i32 utf8_write(c32 c, c8 *buffer) { return 0; } +// ================================================================ +// +// Unix +// +// ================================================================ + +#ifdef __unix__ + +#include +#include + +i64 p_time(void) { + struct timespec t; + timespec_get(&t, TIME_UTC); + return 1000 * t.tv_sec + t.tv_nsec / 1000000; +} + +void p_yield(void) { + sched_yield(); +} + +void p_sleep_for(i64 duration) { + if (duration <= 0) { + usleep(0); + return; + } + + if (duration >= 1000) + // seconds + sleep(duration / 1000); + + if ((duration % 1000) > 0) + // microseconds + usleep((duration % 1000) * 1000); +} + +#endif + // ================================================================ // // UDP sockets // // ================================================================ -i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, IP_Address *remote_address) { - (void) slot; - (void) address; - (void) size; - (void) data; - (void) remote_address; - assert(0); - return 0; +#ifdef __unix__ + +#include +#include +#include +#include + +typedef struct { + b8 ready; + i32 socket; + u16 local_port; + IP_Address address; +} Socket_Slot; + +b8 _sockets_init = 0; +Socket_Slot _sockets[MAX_NUM_SOCKETS] = {0}; + +void sockets_initialize(void) { + if (_sockets_init) + return; + + signal(SIGPIPE, SIG_IGN); + _sockets_init = 1; } -i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data) { - (void) slot; - (void) address; - (void) size; - (void) data; - assert(0); - return 0; +void sockets_cleanup(void) { + for (i64 i = 0; i < MAX_NUM_SOCKETS; ++i) + if (_sockets[i].ready) { + close(_sockets[i].socket); + _sockets[i].ready = 0; + } +} + +b8 sockets_open(u16 slot, IP_Address address, u16 *local_port) { + sockets_initialize(); + + b8 change_address = + !_sockets[slot].ready + || _sockets[slot].address.protocol != address.protocol + || (address.port != 0 && _sockets[slot].local_port != address.port) + || (memcmp(_sockets[slot].address.v6_address, &(u8[sizeof address.v6_address]) {0}, sizeof address.v6_address) != 0 && + memcmp(_sockets[slot].address.v6_address, address.v6_address, sizeof address.v6_address) != 0); + + if (change_address && _sockets[slot].ready) { + close(_sockets[slot].socket); + _sockets[slot].ready = 0; + } + + struct sockaddr *p; + i32 p_len; + + struct sockaddr_in a4 = {0}; + struct sockaddr_in6 a6 = {0}; + + if (address.protocol == IPv4_UDP) { + p = (struct sockaddr *) &a4; + p_len = sizeof a4; + } else { + p = (struct sockaddr *) &a6; + p_len = sizeof a6; + } + + if (!_sockets[slot].ready) { + _sockets[slot].socket = socket(address.protocol == IPv4_UDP ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + if (_sockets[slot].socket == -1) { + fprintf(stderr, "ERROR: socket failed (errno %d)\n", errno); + return 0; + } + + if (address.protocol == IPv4_UDP) { + a4.sin_family = AF_INET; + a4.sin_port = htons(address.port); + a4.sin_addr.s_addr = address.v4_address_as_u32; + } else { + a6.sin6_family = AF_INET6; + a6.sin6_port = htons(address.port); + memcpy(a6.sin6_addr.s6_addr, address.v6_address, sizeof a6.sin6_addr.s6_addr); + } + + if (bind(_sockets[slot].socket, p, p_len) == -1) { + close(_sockets[slot].socket); + + fprintf(stderr, "ERROR: bind failed (errno %d)\n", errno); + return 0; + } + + if (getsockname(_sockets[slot].socket, p, &(socklen_t) {p_len}) == -1) { + close(_sockets[slot].socket); + + fprintf(stderr, "ERROR: getsockname failed (errno %d)\n", errno); + return 0; + } + + if (p->sa_family == AF_INET) + _sockets[slot].local_port = ntohs(a4.sin_port); + else + _sockets[slot].local_port = ntohs(a6.sin6_port); + + _sockets[slot].ready = 1; + _sockets[slot].address = address; + } + + if (local_port != NULL) + *local_port = _sockets[slot].local_port; + + return 1; +} + +i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) { + assert(slot < MAX_NUM_SOCKETS); + assert(address.protocol == IPv4_UDP || address.protocol == IPv6_UDP); + + if (!sockets_open(slot, address, local_port)) + return 0; + if (size <= 0) + return 0; + + struct sockaddr *p; + i32 p_len; + + struct sockaddr_in a4 = {0}; + struct sockaddr_in6 a6 = {0}; + + if (address.protocol == IPv4_UDP) { + p = (struct sockaddr *) &a4; + p_len = sizeof a4; + } else { + p = (struct sockaddr *) &a6; + p_len = sizeof a6; + } + + i64 recieved = recvfrom( + _sockets[slot].socket, + data, + size, + MSG_DONTWAIT, + p, + &(socklen_t) {p_len} + ); + + if (recieved < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + + fprintf(stderr, "ERROR: recvfrom failed (errno %d)\n", errno); + return 0; + } + + if (remote_address != NULL) { + memset(remote_address, 0, sizeof *remote_address); + remote_address->protocol = address.protocol; + + if (address.protocol == IPv4_UDP) { + remote_address->port = ntohs(a4.sin_port); + remote_address->v4_address_as_u32 = a4.sin_addr.s_addr; + } else { + remote_address->port = ntohs(a6.sin6_port); + memcpy(remote_address->v6_address, a6.sin6_addr.s6_addr, sizeof remote_address->v6_address); + } + } + + return recieved; +} + +i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { + assert(slot < MAX_NUM_SOCKETS); + assert(address.protocol == IPv4_UDP || address.protocol == IPv6_UDP); + + IP_Address local_address = address; + local_address.port = 0; + + if (!sockets_open(slot, local_address, local_port)) + return 0; + if (size <= 0) + return 0; + + struct sockaddr *p; + i32 p_len; + + struct sockaddr_in a4 = {0}; + struct sockaddr_in6 a6 = {0}; + + if (address.protocol == IPv4_UDP) { + p = (struct sockaddr *) &a4; + p_len = sizeof a4; + + a4.sin_family = AF_INET; + a4.sin_port = htons(address.port); + a4.sin_addr.s_addr = address.v4_address_as_u32; + } else { + p = (struct sockaddr *) &a6; + p_len = sizeof a6; + + a6.sin6_family = AF_INET6; + a6.sin6_port = htons(address.port); + memcpy(a6.sin6_addr.s6_addr, address.v6_address, sizeof a6.sin6_addr.s6_addr); + } + + i64 sent = sendto( + _sockets[0].socket, + data, + size, + MSG_DONTWAIT, + p, + p_len + ); + + if (sent < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + + fprintf(stderr, "ERROR: sendto failed (errno %d)\n", errno); + return 0; + } + + return sent; } +#endif + // ================================================================ // // X11 @@ -338,8 +593,6 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data) { #include #include #include -#include -#include static i16 _key_table[512] = {0}; static u32 _buffer[MAX_NUM_PIXELS] = {0}; @@ -516,13 +769,25 @@ void p_init(void) { XSetICFocus(_ic); XSetWMProtocols(_display, _window, &_wm_delete_window, 1); - XStoreName(_display, _window, platform.title); + if (platform.title != NULL) + XStoreName(_display, _window, platform.title); + XMapWindow(_display, _window); } void p_cleanup(void) { - XDestroyWindow(_display, _window); - XCloseDisplay (_display); + if (!platform.graceful_exit) + return; + + if (_window != 0) + XDestroyWindow(_display, _window); + if (_display != NULL) + XCloseDisplay (_display); + + _display = NULL; + _window = 0; + + sockets_cleanup(); } i32 p_handle_events(void) { -- cgit v1.2.3