| @@ -1,13 +1,52 @@ | |||
| #define DJSTD_BASIC_ENTRY | |||
| #include "core.c" | |||
| #include "signal.h" | |||
| Server *server = NULL; | |||
| 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); | |||
| int main(int argc, char **argv) { | |||
| initialiseDjStdCore(); | |||
| Arena *arena = arenaAlloc(Megabytes(64)); | |||
| StringList args = getArgs(arena, argc, argv); | |||
| if (bytesRead > 0) { | |||
| print("Client said: %s\n", buf.data); | |||
| print("Now that's insightful.\n"); | |||
| } else if (bytesRead == -1) { | |||
| print("Connection error\n"); | |||
| } | |||
| print("Args:\n"); | |||
| printStrList(args); | |||
| printStrList(strSplit(arena, s("-"), s("the-quick-brown-fox-jumps-over-the-lazy-dog"))); | |||
| clientClose(client); | |||
| return 0; | |||
| } | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||