From f311b242c2cce0743a27ede777764eed1d38a774 Mon Sep 17 00:00:00 2001 From: Daniel Ledda Date: Fri, 28 Nov 2025 19:35:09 +0100 Subject: [PATCH] made sockets non-blocking --- app.c | 69 ++++++++++++++++++++++++++++++++++-------------------- core.h | 2 +- os.h | 4 ++++ os_linux.c | 32 ++++++++++++++++++------- 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/app.c b/app.c index 38610ac..f568001 100644 --- a/app.c +++ b/app.c @@ -46,7 +46,7 @@ int djstd_entry(Arena *arena, StringList args) { if (isServer) { println("Starting server on port %d", port); Server myserver = serverInit((ServerInitInfo){ - .concurrentClients=16, + .concurrentClients=2, .port=port, .memory=Megabytes(64), }); @@ -54,48 +54,67 @@ int djstd_entry(Arena *arena, StringList args) { server = &myserver; serverListen(&myserver); - Socket *client = serverAccept(&myserver); + Socket *client1 = serverAccept(&myserver); + Socket *client2 = serverAccept(&myserver); + + Forever { + string message = s("Hello. You are client 1.\n"); + socketWrite(client1, message.str, message.length); + message = s("Hello. You are client 2.\n"); + socketWrite(client2, message.str, message.length); - forever { string buf = PushStringFill(arena, 256, 0); - uint64 bytesRead = socketRead(client, buf.str, buf.length - 1); + uint64 bytesRead = socketRead(client1, buf.str, buf.length - 1); if (bytesRead > 0) { buf.length = bytesRead; - println("Client said: %S", strSplit(arena, s("\n"), buf).data[0]); + string message = strSplit(arena, s("\n"), buf).data[0]; + message = strPrintf(arena, "Client 1 said: %S\n", message); + println("%S", message); + socketWrite(client2, message.str, message.length); - println("Saying goodbye"); - string message = s("Goodbye\n"); - socketWrite(client, message.str, message.length); + println("Saying goodbye to everyone"); + message = s("Goodbye\n"); + socketWrite(client1, message.str, message.length); + socketWrite(client2, message.str, message.length); break; } - serverClose(&myserver); } - socketClose(client); + socketClose(client1); + socketClose(client2); + serverClose(&myserver); } else { println("Connecting to socket at %S on port %d", addr, port); Socket sock = socketConnect(arena, (SocketConnectInfo){ .address=addr, .port=port }); - println("CONNECTED"); + if (sock.closed) { + println("Connection error. Closing."); + } else { + string message; + uint64 bytesWritten; - string message; - uint64 bytesWritten; - - string buf = PushStringFill(arena, 256, 0); - - forever { - message = s("Howdy partner\n"); - print("Saying: %S", message); - bytesWritten = socketWrite(&sock, message.str, message.length); + string buf = PushStringFill(arena, 256, 0); socketRead(&sock, buf.str, buf.length); - message = strSplit(arena, s("\n"), buf).data[0]; - println("Received message: %S", message); - if (strEql(message, s("Goodbye"))) { - println("Quitting"); - break; + string messageReceived = strSplit(arena, s("\n"), buf).data[0]; + println("%S", strPrintf(arena, "Server said: %S", messageReceived)); + + if (strEql(messageReceived, s("Hello. You are client 1."))) { + string broadcast = s("HELLO WORLD!!!!\n"); + socketWrite(&sock, broadcast.str, broadcast.length); + } + + Forever { + socketRead(&sock, buf.str, buf.length); + messageReceived = strSplit(arena, s("\n"), buf).data[0]; + println("Server said: %S", messageReceived); + if (strEql(messageReceived, s("Goodbye"))) { + println("Quitting"); + break; + } } } + socketClose(&sock); } diff --git a/core.h b/core.h index ccfe935..b76e5bf 100644 --- a/core.h +++ b/core.h @@ -16,7 +16,7 @@ #define function static #define global static #define local_persist static -#define forever for (;;) +#define Forever for (;;) #define DeferLoop(begin_stmnt, end_stmnt) for(int __defer_i = ((begin_stmnt), 0); __defer_i < 1; (++__defer_i, (end_stmnt))) diff --git a/os.h b/os.h index 3dbbf7b..f4d5b20 100644 --- a/os.h +++ b/os.h @@ -33,6 +33,9 @@ struct Address; typedef struct SocketHandle SocketHandle; struct SocketHandle; +typedef struct ServerEvents ServerEvents; +struct ServerEvents; + typedef struct Socket Socket; struct Socket { const Address *address; @@ -49,6 +52,7 @@ struct Server { SocketHandle *handle; SocketList clients; bool listening; + ServerEvents *events; }; typedef struct ServerInitInfo ServerInitInfo; diff --git a/os_linux.c b/os_linux.c index 75f08b6..2fbbbac 100644 --- a/os_linux.c +++ b/os_linux.c @@ -8,6 +8,8 @@ #include "unistd.h" // POSIX Standard #include "stdio.h" #include "pthread.h" +#include "fcntl.h" +#include "sys/epoll.h" #include "sys/socket.h" #include "arpa/inet.h" @@ -141,9 +143,17 @@ OS_Thread os_createThread(void *(*entry)(void *), void *ctx) { return (OS_Thread){ .id=handle }; } +typedef struct EPollServerEvents EPollServerEvents; +struct EPollServerEvents { + int epollFd; +}; + Server serverInit(ServerInitInfo info) { Arena *arena = arenaAlloc(info.memory); + EPollServerEvents *events = PushStructZero(arena, EPollServerEvents); + events->epollFd = epoll_create1(0); + struct sockaddr_in6 *serverAddr = PushStructZero(arena, struct sockaddr_in6); serverAddr->sin6_family = AF_INET6; serverAddr->sin6_port = htons(info.port); @@ -156,9 +166,12 @@ Server serverInit(ServerInitInfo info) { .listening=false, .port=info.port, .handle=(SocketHandle *)(uint64)socket(AF_INET6, SOCK_STREAM, 0 /* IPPROTO_TCP */), + .events=(ServerEvents *)events, }; - int bindErr = bind((int)(uint64)server.handle, (struct sockaddr *)serverAddr, sizeof(*serverAddr)); + fcntl((uint64)server.handle, F_SETFL, fcntl((uint64)server.handle, F_GETFL, 0) | O_NONBLOCK); + + int bindErr = bind((uint64)server.handle, (struct sockaddr *)serverAddr, sizeof(*serverAddr)); if (bindErr == -1) { // TODO(dledda): handle err } @@ -169,7 +182,7 @@ Server serverInit(ServerInitInfo info) { void serverListen(Server *s) { int listenErr = listen((uint64)s->handle, s->clients.capacity); if (listenErr == -1) { - // TODO(dledda): handle err + // TODO(dledda): handle err ? } } @@ -177,19 +190,22 @@ Socket *serverAccept(Server *s) { struct sockaddr_in6 *clientAddr = PushStructZero(s->arena, struct sockaddr_in6); socklen_t clientAddrLen = sizeof(*clientAddr); - uint64 clientSock = accept((int)(uint64)s->handle, (struct sockaddr *)clientAddr, &clientAddrLen); - if (clientSock == -1) { - // TODO(dledda): handle err + uint64 clientSockHandle = accept((int)(uint64)s->handle, (struct sockaddr *)clientAddr, &clientAddrLen); + if (clientSockHandle == -1) { + clientSockHandle = (uint64)NULL; + } else { + fcntl((uint64)clientSockHandle, F_SETFL, fcntl((uint64)clientSockHandle, F_GETFL, 0) | O_NONBLOCK); } if (s->clients.length < s->clients.capacity) { AppendList(&s->clients, ((Socket){ - .handle=(SocketHandle *)(uint64)clientSock, + .handle=(SocketHandle *)(uint64)clientSockHandle, .address=(Address *)clientAddr, })); + return &s->clients.data[s->clients.length - 1]; + } else { + return PushStructZero(s->arena, Socket); } - - return &s->clients.data[s->clients.length - 1]; } int64 socketRead(Socket *socket, byte *dest, uint64 numBytes) {