added simple socket server

This commit is contained in:
Daniel Ledda
2025-11-27 23:45:15 +01:00
parent cbedadd36e
commit 9b772e2046
5 changed files with 187 additions and 34 deletions

53
app.c
View File

@@ -1,13 +1,52 @@
#define DJSTD_BASIC_ENTRY
#include "core.c" #include "core.c"
#include "signal.h"
int main(int argc, char **argv) { Server *server = NULL;
initialiseDjStdCore();
Arena *arena = arenaAlloc(Megabytes(64));
StringList args = getArgs(arena, argc, argv);
print("Args:\n"); void handleSigint(int dummy) {
printStrList(args); if (server) {
printStrList(strSplit(arena, s("-"), s("the-quick-brown-fox-jumps-over-the-lazy-dog"))); 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; return 0;
} }

24
core.c
View File

@@ -231,28 +231,27 @@ StringList strSplit(Arena *arena, string splitStr, string inputStr) {
return result; return result;
} }
ParsePositiveIntResult parsePositiveInt(string str, size_t *lengthPointer) { Int32Result parsePositiveInt(string str) {
size_t numEnd = 0; size_t numEnd = 0;
char currChar = str.str[numEnd]; char currChar = str.str[numEnd];
while (numEnd < str.length && isNumeric(currChar)) { while (numEnd < str.length && isNumeric(currChar)) {
currChar = str.str[++numEnd]; numEnd++;
*lengthPointer += 1; currChar = str.str[numEnd];
} }
*lengthPointer -= 1;
if (numEnd > 0) { if (numEnd > 0) {
uint8 result = 0; uint32 result = 0;
for (size_t i = 0; i < numEnd; i++) { for (size_t i = 0; i < numEnd; i++) {
result *= 10; result *= 10;
result += str.str[i] - '0'; result += str.str[i] - '0';
} }
return (ParsePositiveIntResult){ .result=result, .valid=true }; return (Int32Result){ .result=result, .valid=true };
} else { } else {
return (ParsePositiveIntResult){ .result=0, .valid=false}; return (Int32Result){ .result=0, .valid=false};
} }
} }
ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer) { Real32Result parsePositiveReal32(string str) {
ParsePositiveReal32Result result = { .result=NAN, .valid=false}; Real32Result result = { .result=NAN, .valid=false};
string wholePartStr = (string){0}; string wholePartStr = (string){0};
string fractionalPartStr = (string){0}; string fractionalPartStr = (string){0};
@@ -271,9 +270,8 @@ ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer)
c++; c++;
} }
if (split) { if (split) {
ParsePositiveIntResult wholePartParsed = parsePositiveInt(wholePartStr, lengthPointer); Int32Result wholePartParsed = parsePositiveInt(wholePartStr);
*lengthPointer += 1; Int32Result fractionalPartParsed = parsePositiveInt(fractionalPartStr);
ParsePositiveIntResult fractionalPartParsed = parsePositiveInt(fractionalPartStr, lengthPointer);
if (wholePartParsed.valid && fractionalPartParsed.valid) { if (wholePartParsed.valid && fractionalPartParsed.valid) {
// TODO(dledda): implement powf with intrinsics? or just custom // TODO(dledda): implement powf with intrinsics? or just custom
real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length); real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length);
@@ -281,7 +279,7 @@ ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer)
result.valid = true; result.valid = true;
} }
} else if (c > 0) { } else if (c > 0) {
ParsePositiveIntResult intPartParsed = parsePositiveInt(str, lengthPointer); Int32Result intPartParsed = parsePositiveInt(str);
if (intPartParsed.valid) { if (intPartParsed.valid) {
result.result = (real32)intPartParsed.result; result.result = (real32)intPartParsed.result;
result.valid = true; result.valid = true;

24
core.h
View File

@@ -211,19 +211,19 @@ StringList strSplit(Arena *arena, string splitStr, string inputStr);
string strPrintfv(Arena *arena, const char *fmt, va_list args); string strPrintfv(Arena *arena, const char *fmt, va_list args);
string strPrintf(Arena *arena, const char *fmt, ...); string strPrintf(Arena *arena, const char *fmt, ...);
typedef struct ParsePositiveIntResult ParsePositiveIntResult; #define DefineResult(type, prefix) \
struct ParsePositiveIntResult { typedef struct prefix ## Result prefix ## Result;\
uint8 result; struct prefix ## Result {\
bool valid; type result;\
}; bool valid;\
ParsePositiveIntResult parsePositiveInt(string str, size_t *lengthPointer); };\
typedef type prefix ## Result ## _underlying
typedef struct ParsePositiveReal32Result ParsePositiveReal32Result; DefineResult(int32, Int32);
struct ParsePositiveReal32Result { Int32Result parsePositiveInt(string str);
real32 result;
bool valid; DefineResult(real32, Real32);
}; Real32Result parsePositiveReal32(string str);
ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer);
inline function bool isNumeric(char c); inline function bool isNumeric(char c);

40
os.h
View File

@@ -25,4 +25,44 @@ struct OS_Thread {
OS_Thread os_createThread(void *(*entry)(void *ctx), void *ctx); 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 #endif

View File

@@ -9,6 +9,12 @@
#include "stdio.h" #include "stdio.h"
#include "pthread.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) { void *os_alloc(size_t capacity) {
return mmap(0, capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 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 }; 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 #endif