| @@ -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]); | |||
| println("Saying goodbye"); | |||
| string message = s("Goodbye\n"); | |||
| socketWrite(client, message.str, message.length); | |||
| 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 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); | |||
| string buf = PushStringFill(arena, 256, 0); | |||
| socketRead(&sock, buf.str, buf.length); | |||
| string messageReceived = strSplit(arena, s("\n"), buf).data[0]; | |||
| println("%S", strPrintf(arena, "Server said: %S", messageReceived)); | |||
| forever { | |||
| message = s("Howdy partner\n"); | |||
| print("Saying: %S", message); | |||
| bytesWritten = socketWrite(&sock, message.str, message.length); | |||
| if (strEql(messageReceived, s("Hello. You are client 1."))) { | |||
| string broadcast = s("HELLO WORLD!!!!\n"); | |||
| socketWrite(&sock, broadcast.str, broadcast.length); | |||
| } | |||
| 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; | |||
| 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); | |||
| } | |||
| @@ -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))) | |||
| @@ -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; | |||
| @@ -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) { | |||