From 9b772e204672e03bf73388ae8aca21ea5559a764 Mon Sep 17 00:00:00 2001 From: Daniel Ledda Date: Thu, 27 Nov 2025 23:45:15 +0100 Subject: [PATCH] added simple socket server --- app.c | 53 ++++++++++++++++++++++++++++++++----- core.c | 24 ++++++++--------- core.h | 28 ++++++++++---------- os.h | 40 ++++++++++++++++++++++++++++ os_linux.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+), 34 deletions(-) diff --git a/app.c b/app.c index 83871bf..6bef844 100644 --- a/app.c +++ b/app.c @@ -1,13 +1,52 @@ +#define DJSTD_BASIC_ENTRY + #include "core.c" +#include "signal.h" -int main(int argc, char **argv) { - initialiseDjStdCore(); - Arena *arena = arenaAlloc(Megabytes(64)); - StringList args = getArgs(arena, argc, argv); +Server *server = NULL; - print("Args:\n"); - printStrList(args); - printStrList(strSplit(arena, s("-"), s("the-quick-brown-fox-jumps-over-the-lazy-dog"))); +void handleSigint(int dummy) { + if (server) { + print("\n"); + print("Closing server socket.\n"); + serverClose(server); + print("Success\n."); + } + exit(0); +} + +int djstd_entry(Arena *arena, StringList args) { + signal(SIGINT, &handleSigint); + + int port = 8080; + Int32Result portParsed = parsePositiveInt(args.data[0]); + if (portParsed.valid) { + port = portParsed.result; + } + + print("Starting server on port %d\n", port); + Server myserver = serverInit((ServerInitInfo){ + .concurrentClients=16, + .port=port, + .memory=Megabytes(64), + }); + + server = &myserver; + + serverListen(&myserver); + Client *client = serverAccept(&myserver); + + CharList buf = PushFullListZero(arena, CharList, 257); + uint64 bytesRead = clientRead(client, (void *)buf.data, buf.length - 1); + + if (bytesRead > 0) { + print("Client said: %s\n", buf.data); + print("Now that's insightful.\n"); + } else if (bytesRead == -1) { + print("Connection error\n"); + } + + clientClose(client); return 0; } diff --git a/core.c b/core.c index 3eba17d..744d408 100644 --- a/core.c +++ b/core.c @@ -231,28 +231,27 @@ StringList strSplit(Arena *arena, string splitStr, string inputStr) { return result; } -ParsePositiveIntResult parsePositiveInt(string str, size_t *lengthPointer) { +Int32Result parsePositiveInt(string str) { size_t numEnd = 0; char currChar = str.str[numEnd]; while (numEnd < str.length && isNumeric(currChar)) { - currChar = str.str[++numEnd]; - *lengthPointer += 1; + numEnd++; + currChar = str.str[numEnd]; } - *lengthPointer -= 1; if (numEnd > 0) { - uint8 result = 0; + uint32 result = 0; for (size_t i = 0; i < numEnd; i++) { result *= 10; result += str.str[i] - '0'; } - return (ParsePositiveIntResult){ .result=result, .valid=true }; + return (Int32Result){ .result=result, .valid=true }; } else { - return (ParsePositiveIntResult){ .result=0, .valid=false}; + return (Int32Result){ .result=0, .valid=false}; } } -ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer) { - ParsePositiveReal32Result result = { .result=NAN, .valid=false}; +Real32Result parsePositiveReal32(string str) { + Real32Result result = { .result=NAN, .valid=false}; string wholePartStr = (string){0}; string fractionalPartStr = (string){0}; @@ -271,9 +270,8 @@ ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer) c++; } if (split) { - ParsePositiveIntResult wholePartParsed = parsePositiveInt(wholePartStr, lengthPointer); - *lengthPointer += 1; - ParsePositiveIntResult fractionalPartParsed = parsePositiveInt(fractionalPartStr, lengthPointer); + Int32Result wholePartParsed = parsePositiveInt(wholePartStr); + Int32Result fractionalPartParsed = parsePositiveInt(fractionalPartStr); if (wholePartParsed.valid && fractionalPartParsed.valid) { // TODO(dledda): implement powf with intrinsics? or just custom real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length); @@ -281,7 +279,7 @@ ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer) result.valid = true; } } else if (c > 0) { - ParsePositiveIntResult intPartParsed = parsePositiveInt(str, lengthPointer); + Int32Result intPartParsed = parsePositiveInt(str); if (intPartParsed.valid) { result.result = (real32)intPartParsed.result; result.valid = true; diff --git a/core.h b/core.h index 19bbd32..c984a06 100644 --- a/core.h +++ b/core.h @@ -139,7 +139,7 @@ inline function Vec4 vec4(real32 x, real32 y, real32 z, real32 w) { #define DefineList(type, prefix) \ typedef struct prefix ## List prefix ## List;\ struct prefix ## List {\ - type* data;\ + type *data;\ size_t length;\ size_t capacity;\ };\ @@ -211,19 +211,19 @@ StringList strSplit(Arena *arena, string splitStr, string inputStr); string strPrintfv(Arena *arena, const char *fmt, va_list args); string strPrintf(Arena *arena, const char *fmt, ...); -typedef struct ParsePositiveIntResult ParsePositiveIntResult; -struct ParsePositiveIntResult { - uint8 result; - bool valid; -}; -ParsePositiveIntResult parsePositiveInt(string str, size_t *lengthPointer); +#define DefineResult(type, prefix) \ + typedef struct prefix ## Result prefix ## Result;\ + struct prefix ## Result {\ + type result;\ + bool valid;\ + };\ + typedef type prefix ## Result ## _underlying -typedef struct ParsePositiveReal32Result ParsePositiveReal32Result; -struct ParsePositiveReal32Result { - real32 result; - bool valid; -}; -ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer); +DefineResult(int32, Int32); +Int32Result parsePositiveInt(string str); + +DefineResult(real32, Real32); +Real32Result parsePositiveReal32(string str); inline function bool isNumeric(char c); @@ -304,7 +304,7 @@ extern void (*print)(const char *fmt, ...); // ### Loops ### #define EachIn(list, it) size_t it = 0; it < (list).length; it++ -#define EachEl(list, type, element) type* element = (list).data; element < (list).data + (list).length; element += 1 +#define EachEl(list, type, element) type *element = (list).data; element < (list).data + (list).length; element += 1 #define EachInReversed(list, it) size_t it = (list).length - 1; it >= 0 && it < (list).length; it-- #define EachInArray(arr, it) size_t it = 0; it < ArrayCount(arr); ++it diff --git a/os.h b/os.h index c830702..250a4b1 100644 --- a/os.h +++ b/os.h @@ -25,4 +25,44 @@ struct OS_Thread { OS_Thread os_createThread(void *(*entry)(void *ctx), void *ctx); +// ### Network I/O ### +typedef struct Address Address; +struct Address; + +typedef struct Socket Socket; +struct Socket; + +typedef struct Client Client; +struct Client { + Address *clientAddressData; + Socket *socket; +}; +DefineList(Client, Client); + +typedef struct Server Server; +struct Server { + Arena *arena; + Address *serverAddressData; + uint32 serverPort; + Socket *socket; + ClientList clients; + bool listening; +}; + +typedef struct ServerInitInfo ServerInitInfo; +struct ServerInitInfo { + uint16 port; + uint32 concurrentClients; + uint64 memory; +}; + +Server serverInit(ServerInitInfo info); +void serverListen(Server *s); +Client *serverAccept(Server *s); +void serverClose(Server *s); + +uint64 clientRead(Client *client, void *dest, size_t bytes); +void clientWrite(Client *client); +void clientClose(Client *client); + #endif diff --git a/os_linux.c b/os_linux.c index 3b1de42..cad0257 100644 --- a/os_linux.c +++ b/os_linux.c @@ -9,6 +9,12 @@ #include "stdio.h" #include "pthread.h" +#include "sys/socket.h" +#include "netinet/in.h" +#include "stdlib.h" +#include "arpa/inet.h" + + void *os_alloc(size_t capacity) { return mmap(0, capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } @@ -106,4 +112,74 @@ OS_Thread os_createThread(void *(*entry)(void *), void *ctx) { return (OS_Thread){ .id=handle }; } +Server serverInit(ServerInitInfo info) { + Arena *arena = arenaAlloc(info.memory); + + struct sockaddr_in6 *serverAddr = PushStructZero(arena, struct sockaddr_in6); + serverAddr->sin6_family = AF_INET6; + serverAddr->sin6_port = htons(info.port); + serverAddr->sin6_addr = in6addr_loopback; + + Server server = { + .arena=arena, + .serverAddressData=(Address *)serverAddr, + .clients=PushListZero(arena, ClientList, info.concurrentClients), + .listening=false, + .serverPort=info.port, + .socket=(Socket *)(uint64)socket(AF_INET6, SOCK_STREAM, 0 /* IPPROTO_TCP */), + }; + + int bindErr = bind((int)(uint64)server.socket, (struct sockaddr *)serverAddr, sizeof(*serverAddr)); + if (bindErr == -1) { + // TODO(dledda): handle err + } + + return server; +} + +void serverListen(Server *s) { + int listenErr = listen((uint64)s->socket, s->clients.capacity); + if (listenErr == -1) { + // TODO(dledda): handle err + } +} + +Client *serverAccept(Server *s) { + struct sockaddr_in6 *clientAddr = PushStructZero(s->arena, struct sockaddr_in6); + socklen_t clientAddrLen = sizeof(*clientAddr); + + uint64 clientSock = accept((int)(uint64)s->socket, (struct sockaddr *)clientAddr, &clientAddrLen); + if (clientSock == -1) { + // TODO(dledda): handle err + } + + if (s->clients.length < s->clients.capacity) { + AppendList(&s->clients, ((Client){ + .socket=(Socket *)(uint64)clientSock, + .clientAddressData=(Address *)clientAddr, + })); + } + + return &s->clients.data[s->clients.length - 1]; +} + +uint64 clientRead(Client *client, void *dest, size_t bytes) { + int bytesRead = read((uint64)client->socket, dest, bytes); + if (bytesRead == -1) { + // TODO(dledda): handle err + } + return bytesRead; +} + +void clientWrite(Client *client) { +} + +void clientClose(Client *client) { + close((int)(uint64)client->socket); +} + +void serverClose(Server *s) { + close((int)(uint64)s->socket); +} + #endif