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 "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
24
core.c
@@ -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;
|
||||||
|
|||||||
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) \
|
#define DefineList(type, prefix) \
|
||||||
typedef struct prefix ## List prefix ## List;\
|
typedef struct prefix ## List prefix ## List;\
|
||||||
struct prefix ## List {\
|
struct prefix ## List {\
|
||||||
type* data;\
|
type *data;\
|
||||||
size_t length;\
|
size_t length;\
|
||||||
size_t capacity;\
|
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 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);
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ extern void (*print)(const char *fmt, ...);
|
|||||||
|
|
||||||
// ### Loops ###
|
// ### Loops ###
|
||||||
#define EachIn(list, it) size_t it = 0; it < (list).length; it++
|
#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 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
|
#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);
|
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
|
||||||
|
|||||||
76
os_linux.c
76
os_linux.c
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user