| @@ -1,209 +1,65 @@ | |||||
| #include "core.h" | |||||
| #define DJSTD_BASIC_ENTRY | #define DJSTD_BASIC_ENTRY | ||||
| #include "core.c" | #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); | |||||
| int djstd_entry(Arena *arena, StringList args) { | |||||
| Socket sock = socketConnect(arena, (SocketConnectInfo){ .address="::1", .port=8080, .blocking=true }); | |||||
| void startServer(Arena *arena, int32 port) { | |||||
| println("Starting server..."); | |||||
| Server server = serverInit((ServerInitInfo){ | |||||
| .concurrentClients=2, | |||||
| .port=port, | |||||
| .memory=Megabytes(64), | |||||
| .maxEvents=64, | |||||
| }); | |||||
| openServer = &server; | |||||
| string newLine = s("\r\n"); | |||||
| string lines[] = { | |||||
| s("GET / HTTP/1.1"), | |||||
| s("Host: localhost"), | |||||
| }; | |||||
| serverListen(&server); | |||||
| if (server.listening) { | |||||
| println("Listening on port %d", port); | |||||
| for (EachInArray(lines, i)) { | |||||
| socketWriteStr(&sock, lines[i]); | |||||
| socketWriteStr(&sock, newLine); | |||||
| } | } | ||||
| socketWriteStr(&sock, newLine); | |||||
| Arena *serverLoopArena = arenaAlloc(Megabytes(64)); | |||||
| ChatClientList chatClients = PushListZero(arena, ChatClientList, 256); | |||||
| CharList body = EmptyList(); | |||||
| bool streamingBody = false; | |||||
| Forever { | Forever { | ||||
| ServerEvent *nextEvent; | |||||
| do { | |||||
| 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 | |||||
| } | |||||
| StringResult response = socketReadStr(arena, &sock); | |||||
| if (response.valid) { | |||||
| if (streamingBody) { | |||||
| if (body.capacity - body.length >= response.result.length) { | |||||
| memcpy(body.data + body.length, response.result.str, response.result.length); | |||||
| body.length += response.result.length; | |||||
| } | |||||
| } else { | |||||
| StringList lines = strSplit(arena, s("\r\n"), response.result); | |||||
| for (EachEl(lines, string, line)) { | |||||
| if (body.capacity > 0 && strEql(*line, s(""))) { | |||||
| streamingBody = true; | |||||
| } else if (streamingBody && (body.capacity - body.length) >= line->length) { | |||||
| // TODO(dledda): append list to list, string to string, whatever | |||||
| // TODO(dledda): `joinStringList` | |||||
| memcpy(body.data + body.length, line->str, line->length); | |||||
| body.length += line->length; | |||||
| } else { | |||||
| // TODO(dledda): `strContains` | |||||
| // TODO(dledda): `stringContains` -> `strContainsChar` | |||||
| StringList split = strSplit(arena, s("Content-Length: "), *line); | |||||
| if (split.length > 1) { | |||||
| Int32Result lengthResult = parsePositiveInt(split.data[1]); | |||||
| if (lengthResult.valid) { | |||||
| body = PushList(arena, CharList, lengthResult.result); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| break; | |||||
| }; | |||||
| case ServerEventType_None: { | |||||
| break; | |||||
| }; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } while (nextEvent != NULL); | |||||
| 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 (streamingBody == true && body.length == body.capacity) { | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| if (argumentErr) { | |||||
| println("Usage:"); | |||||
| println("server [PORT]"); | |||||
| println("OR"); | |||||
| println("client [REMOTE_ADDRESS:PORT] [NICKNAME]"); | |||||
| } | |||||
| // TODO(dledda): string from CharList/ByteList | |||||
| // TODO(dledda): `printStr` | |||||
| print("%S", (string){.str=body.data, .length=body.length}); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -0,0 +1,205 @@ | |||||
| #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; | |||||
| } | |||||
| @@ -67,6 +67,7 @@ typedef struct SocketConnectInfo SocketConnectInfo; | |||||
| struct SocketConnectInfo { | struct SocketConnectInfo { | ||||
| string address; | string address; | ||||
| uint16 port; | uint16 port; | ||||
| bool blocking; | |||||
| }; | }; | ||||
| @@ -5,15 +5,15 @@ | |||||
| #include "sys/mman.h" | #include "sys/mman.h" | ||||
| #include "sys/stat.h" | #include "sys/stat.h" | ||||
| #include "unistd.h" // POSIX Standard | |||||
| #include "stdio.h" | |||||
| #include "string.h" // memcpy TODO(dledda): replace memcpy with custom impl? | |||||
| #include "unistd.h" // POSIX Standard, read, write, close, open, etc. | |||||
| #include "pthread.h" | #include "pthread.h" | ||||
| #include "fcntl.h" | #include "fcntl.h" | ||||
| #include "sys/epoll.h" | #include "sys/epoll.h" | ||||
| #include "sys/socket.h" | #include "sys/socket.h" | ||||
| #include "arpa/inet.h" | #include "arpa/inet.h" | ||||
| #include "string.h" // memcpy | |||||
| void *os_alloc(uint64 capacity) { | void *os_alloc(uint64 capacity) { | ||||
| @@ -34,17 +34,21 @@ void os_free(void *ptr, uint64 size) { | |||||
| string os_readEntireFile(Arena *arena, string filename) { | string os_readEntireFile(Arena *arena, string filename) { | ||||
| Scratch temp = scratchStart(&arena, 1); | Scratch temp = scratchStart(&arena, 1); | ||||
| FILE *input = fopen(cstring(temp.arena, filename), "r"); | |||||
| int input = open(cstring(temp.arena, filename), O_RDONLY); | |||||
| string readBuffer; | string readBuffer; | ||||
| if (input) { | if (input) { | ||||
| struct stat st; | struct stat st; | ||||
| stat((char *)filename.str, &st); | stat((char *)filename.str, &st); | ||||
| uint64 fsize = st.st_size; | uint64 fsize = st.st_size; | ||||
| readBuffer = PushString(arena, fsize); | readBuffer = PushString(arena, fsize); | ||||
| fread(readBuffer.str, sizeof(byte), readBuffer.length, input); | |||||
| fclose(input); | |||||
| int64 bytesRead = read(input, readBuffer.str, readBuffer.length); | |||||
| close(input); | |||||
| if (bytesRead == -1) { | |||||
| arenaPopTo(arena, readBuffer.str); | |||||
| return s(""); | |||||
| } | |||||
| } else { | } else { | ||||
| readBuffer = PushString(arena, 0); | |||||
| readBuffer = s(""); | |||||
| } | } | ||||
| scratchEnd(temp); | scratchEnd(temp); | ||||
| @@ -55,11 +59,13 @@ bool os_writeEntireFile(Arena *arena, string filename, const byte *contents, uin | |||||
| Scratch temp = scratchStart(&arena, 1); | Scratch temp = scratchStart(&arena, 1); | ||||
| bool result = false; | bool result = false; | ||||
| FILE *output = fopen(cstring(temp.arena, filename), "w"); | |||||
| int output = open(cstring(temp.arena, filename), O_WRONLY); | |||||
| if (output) { | if (output) { | ||||
| fwrite(contents, sizeof(byte), contentsLength, output); | |||||
| fclose(output); | |||||
| result = true; | |||||
| int64 bytesWritten = write(output, contents, contentsLength); | |||||
| if (bytesWritten != -1) { | |||||
| result = true; | |||||
| } | |||||
| close(output); | |||||
| } | } | ||||
| scratchEnd(temp); | scratchEnd(temp); | ||||
| @@ -70,11 +76,13 @@ bool os_fileAppend(Arena *arena, string filename, const byte *contents, uint64 c | |||||
| Scratch temp = scratchStart(&arena, 1); | Scratch temp = scratchStart(&arena, 1); | ||||
| bool result = false; | bool result = false; | ||||
| FILE *output = fopen(cstring(temp.arena, filename), "a"); | |||||
| int output = open(cstring(temp.arena, filename), O_APPEND); | |||||
| if (output) { | if (output) { | ||||
| fwrite(contents, sizeof(byte), contentsLength, output); | |||||
| fclose(output); | |||||
| result = true; | |||||
| int bytesWritten = write(output, contents, contentsLength); | |||||
| if (bytesWritten != -1) { | |||||
| result = true; | |||||
| } | |||||
| close(output); | |||||
| } | } | ||||
| scratchEnd(temp); | scratchEnd(temp); | ||||
| @@ -98,12 +106,10 @@ void os_println(StdStream target, const char *fmt, va_list argList) { | |||||
| write(0, (const void *)result.str, result.length); | write(0, (const void *)result.str, result.length); | ||||
| break; | break; | ||||
| case StdStream_stderr: | case StdStream_stderr: | ||||
| fflush(stderr); | |||||
| write(2, (const void *)result.str, result.length); | write(2, (const void *)result.str, result.length); | ||||
| break; | break; | ||||
| case StdStream_stdout: | case StdStream_stdout: | ||||
| default: | default: | ||||
| fflush(stdout); | |||||
| write(1, (const void *)result.str, result.length); | write(1, (const void *)result.str, result.length); | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -121,12 +127,10 @@ void os_print(StdStream target, const char *fmt, va_list argList) { | |||||
| write(0, (const void *)result.str, result.length); | write(0, (const void *)result.str, result.length); | ||||
| break; | break; | ||||
| case StdStream_stderr: | case StdStream_stderr: | ||||
| fflush(stderr); | |||||
| write(2, (const void *)result.str, result.length); | write(2, (const void *)result.str, result.length); | ||||
| break; | break; | ||||
| case StdStream_stdout: | case StdStream_stdout: | ||||
| default: | default: | ||||
| fflush(stdout); | |||||
| write(1, (const void *)result.str, result.length); | write(1, (const void *)result.str, result.length); | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -211,8 +215,6 @@ Socket *serverAccept(Server *s) { | |||||
| uint64 clientSockHandle = accept((int)(uint64)s->handle, (struct sockaddr *)clientAddr, &clientAddrLen); | uint64 clientSockHandle = accept((int)(uint64)s->handle, (struct sockaddr *)clientAddr, &clientAddrLen); | ||||
| if (clientSockHandle == -1) { | if (clientSockHandle == -1) { | ||||
| clientSockHandle = (uint64)NULL; | clientSockHandle = (uint64)NULL; | ||||
| println("ERR server accept"); | |||||
| perror("accept"); | |||||
| } else { | } else { | ||||
| fcntl((uint64)clientSockHandle, F_SETFL, fcntl((uint64)clientSockHandle, F_GETFL, 0) | O_NONBLOCK); | fcntl((uint64)clientSockHandle, F_SETFL, fcntl((uint64)clientSockHandle, F_GETFL, 0) | O_NONBLOCK); | ||||
| } | } | ||||
| @@ -339,7 +341,9 @@ void socketClose(Socket *s) { | |||||
| Socket socketConnect(Arena *arena, SocketConnectInfo info) { | Socket socketConnect(Arena *arena, SocketConnectInfo info) { | ||||
| int socketFd = socket(AF_INET6, SOCK_STREAM, 0 /* IPPROTO_TCP */); | int socketFd = socket(AF_INET6, SOCK_STREAM, 0 /* IPPROTO_TCP */); | ||||
| fcntl(socketFd, F_SETFL, fcntl(socketFd, F_GETFL, 0) | O_NONBLOCK); | |||||
| if (!info.blocking) { | |||||
| fcntl(socketFd, F_SETFL, fcntl(socketFd, F_GETFL, 0) | O_NONBLOCK); | |||||
| } | |||||
| struct sockaddr_in6 *remoteAddr = PushStructZero(arena, struct sockaddr_in6); | struct sockaddr_in6 *remoteAddr = PushStructZero(arena, struct sockaddr_in6); | ||||
| remoteAddr->sin6_family = AF_INET6; | remoteAddr->sin6_family = AF_INET6; | ||||
| @@ -352,6 +356,7 @@ Socket socketConnect(Arena *arena, SocketConnectInfo info) { | |||||
| .address=(Address *)remoteAddr, | .address=(Address *)remoteAddr, | ||||
| .closed=false, | .closed=false, | ||||
| //.closed=connectErr == -1, | //.closed=connectErr == -1, | ||||
| // TODO(dledda): investigate error behaviour | |||||
| }; | }; | ||||
| return result; | return result; | ||||