summaryrefslogtreecommitdiff
path: root/reduced_system_layer.c
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-08-12 20:10:40 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-08-12 20:10:40 +0200
commitec7ce54de5583ab11de5b19e6efc146cb52c3418 (patch)
tree8596c1f11d73c0d78273f4455225eb9a1c56c299 /reduced_system_layer.c
parent4f20ddeb9e0e08fd32f66ea049eb5d97c4b1c1a8 (diff)
downloadreduced_system_layer-ec7ce54de5583ab11de5b19e6efc146cb52c3418.zip
Refactor examples
Diffstat (limited to 'reduced_system_layer.c')
-rwxr-xr-xreduced_system_layer.c333
1 files changed, 299 insertions, 34 deletions
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 <time.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
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 <assert.h>
-#include <string.h>
-
c32 utf8_read(i64 len, c8 *s) {
if (len >= 1 &&
(s[0] & 0x80) == 0)
@@ -304,29 +319,269 @@ i32 utf8_write(c32 c, c8 *buffer) {
// ================================================================
//
+// Unix
+//
+// ================================================================
+
+#ifdef __unix__
+
+#include <sched.h>
+#include <unistd.h>
+
+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 <errno.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
-#include <sched.h>
-#include <time.h>
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) {