added simple socket server
This commit is contained in:
53
app.c
53
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;
|
||||
}
|
||||
|
||||
24
core.c
24
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;
|
||||
|
||||
28
core.h
28
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
|
||||
|
||||
|
||||
40
os.h
40
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
|
||||
|
||||
76
os_linux.c
76
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
|
||||
|
||||
Reference in New Issue
Block a user