|
- #include "core.h"
- #define DJSTD_BASIC_ENTRY
-
- #include "core.c"
- #include "signal.h"
-
- Server *openServer = NULL;
- SocketList *openSockets = NULL;
-
- void handleSigint(int dummy) {
- if (openServer) {
- println("");
- println("Closing server socket.");
- serverClose(openServer);
- println("Success.");
- }
- if (openSockets && openSockets->length) {
- println("");
- println("Closing open sockets.");
- for (EachEl(*openSockets, Socket, socket)) {
- socketClose(socket);
- }
- println("Success.");
- }
- signal(SIGINT, SIG_DFL);
- raise(SIGINT);
- }
-
- typedef struct ChatClient ChatClient;
- struct ChatClient {
- Socket *socket;
- string nickname;
- };
- DefineList(ChatClient, ChatClient);
-
- void startServer(Arena *arena, int32 port) {
- println("Starting server...");
- Server server = serverInit((ServerInitInfo){
- .concurrentClients=2,
- .port=port,
- .memory=Megabytes(64),
- .maxEvents=64,
- });
- openServer = &server;
-
- serverListen(&server);
- if (server.listening) {
- println("Listening on port %d", port);
- }
-
- Arena *serverLoopArena = arenaAlloc(Megabytes(64));
- ChatClientList chatClients = PushListZero(arena, ChatClientList, 256);
-
- ServerEvent *nextEvent;
-
- Forever {
- nextEvent = serverGetNextEvent(&server);
- switch (nextEvent->type) {
- case ServerEventType_AcceptClient: {
- Socket *client = serverAccept(&server);
- if (client != NULL) {
- println("New client connected from %d", client->address);
- }
- break;
- };
- case ServerEventType_ClientMessage: {
- StringResult clientMsg = socketReadStr(serverLoopArena, nextEvent->tClientMessage.client);
- ChatClient *chatClient = NULL;
- if (clientMsg.valid) {
- if (strStartsWith(clientMsg.result, s("hello-"))) {
- StringList nickSplit = strSplit(serverLoopArena, s("-"), clientMsg.result);
- if (nickSplit.length == 2 && nickSplit.data[1].length > 0) {
- string newNick = PushString(arena, nickSplit.data[1].length);
- newNick.length = nickSplit.data[1].length;
- memcpy(newNick.str, nickSplit.data[1].str, nickSplit.data[1].length);
- ChatClient newChatClient = (ChatClient){
- .socket=nextEvent->tClientMessage.client,
- .nickname=newNick,
- };
- AppendList(&chatClients, newChatClient);
- println("Client from %d calls themselves \"%S\"", newChatClient.socket->address, newChatClient.nickname);
- }
- } else {
- for (EachEl(chatClients, ChatClient, maybeChatClient)) {
- if (maybeChatClient->socket->handle == nextEvent->tClientMessage.client->handle) {
- chatClient = maybeChatClient;
- }
- }
- if (chatClient != NULL) {
- if (strStartsWith(clientMsg.result, s("say-"))) {
- StringList saySplit = strSplit(arena, s("-"), clientMsg.result);
- if (saySplit.length == 2 && saySplit.data[1].length > 0) {
- string broadcast = strPrintf(serverLoopArena, "%S says:\n%S", chatClient->nickname, saySplit.data[1]);
- for (EachEl(server.clients, Socket, client)) {
- socketWriteStr(client, broadcast);
- }
- }
- } else {
- // Invalid client message
- }
- }
- }
- }
- break;
- };
- case ServerEventType_None:
- default:
- break;
- }
-
- arenaFreeFrom(serverLoopArena, 0);
- }
-
- println("Shutting down chat.");
- serverClose(&server);
- }
-
- void clearStdInLn() {
- print("\r");
- print(ANSI_INSTRUCTION(J));
- }
-
- void clearStdInLnAfterInput() {
- print("\r");
- print(ANSI_INSTRUCTION(A));
- print(ANSI_INSTRUCTION(J));
- }
-
- void startClient(Arena *arena, string addr, int32 port, string nickname) {
- fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
-
- println("Connecting to server at [%S]:%d with nickname \"%S\"", addr, port, nickname);
- Socket server = socketConnect(arena, (SocketConnectInfo){ .address=addr, .port=port });
- if (server.closed) {
- println("Connection error. Closing.");
- } else {
- println("Connected successfully");
- string message = strPrintf(arena, "hello-%S", nickname);
- CharList inputBuf = PushList(arena, CharList, 512);
- socketWriteStr(&server, message);
-
- print("(you)> ");
- Forever {
- Scratch scratch = scratchStart(&arena, 1);
-
- int32 numRead = read(0, inputBuf.data + inputBuf.length, inputBuf.capacity - inputBuf.length);
- if (numRead >= 0) {
- inputBuf.length += numRead;
- if (inputBuf.data[inputBuf.length - 1] == '\n') {
- clearStdInLnAfterInput();
- socketWriteStr(&server, strPrintf(scratch.arena, "say-%S", (string){.str=inputBuf.data,.length=inputBuf.length}));
- inputBuf.length = 0;
- }
- }
-
- StringResult serverMsg = socketReadStr(scratch.arena, &server);
- if (serverMsg.valid && serverMsg.result.length > 0) {
- clearStdInLn();
- println("%S", serverMsg.result);
- print("(you)> %S", (string){.str=inputBuf.data, inputBuf.length});
- }
-
- scratchEnd(scratch);
- }
- }
- socketClose(&server);
- }
-
- int djstd_entry(Arena *arena, StringList args) {
- signal(SIGINT, &handleSigint);
-
- bool argumentErr = true;
- bool isServer = strEql(args.data[0], s("server"));
- bool isClient = strEql(args.data[0], s("client"));
-
- if (isServer) {
- Int32Result portParsed = parsePositiveInt(args.data[1]);
- if (portParsed.valid) {
- startServer(arena, portParsed.result);
- argumentErr = false;
- }
- } else if (isClient) {
- if (args.length == 3) {
- StringList split = strSplit(arena, s("]:"), args.data[1]);
- if (split.length == 2) {
- Int32Result portParsed = parsePositiveInt(split.data[1]);
- string addr = strSlice(split.data[0], 1, split.data[0].length);
- string nickname = args.data[2];
- if (portParsed.valid && addr.length > 0 && nickname.length > 0) {
- startClient(arena, addr, portParsed.result, nickname);
- argumentErr = false;
- }
- }
- }
- }
-
- if (argumentErr) {
- println("Usage:");
- println("server [PORT]");
- println("OR");
- println("client [REMOTE_ADDRESS:PORT] [NICKNAME]");
- }
-
- return 0;
- }
|