// User application entry points for tcpserve. #include #include #include #include #include #include // Prints the requested operation. static void print(const char* s) { if (s) (void)NtlConsoleWrite(SYS_HANDLE_INVALID, s, strlen(s), NULL); } // Prints char. static void print_char(char c) { (void)NtlConsoleWrite(SYS_HANDLE_INVALID, &c, 1, NULL); } // Prints u64. static void print_u64(uint64_t v) { char buf[32]; int n = 0; if (v == 0) { print("0"); return; } while (v && n < (int)sizeof(buf)) { buf[n++] = (char)('0' + (v % 10)); v /= 10; } while (n > 0) print_char(buf[--n]); } // Prints ipv4. static void print_ipv4(const uint8_t ip[4]) { print_u64(ip[0]); print("."); print_u64(ip[1]); print("."); print_u64(ip[2]); print("."); print_u64(ip[3]); } // Prints ipv6. static void print_ipv6(const uint8_t ip[16]) { static const char hex[] = "0123456789abcdef"; for (int i = 0; i < 8; ++i) { uint16_t word = ((uint16_t)ip[i * 2] << 8) | ip[i * 2 + 1]; bool started = false; for (int shift = 12; shift >= 0; shift -= 4) { unsigned nibble = (word >> shift) & 0xfu; if (nibble || started || shift == 0) { char c = hex[nibble]; print_char(c); started = true; } } if (i != 7) print(":"); } } // Prints socket address. static void print_socket_address(const SYS_SOCKET_ADDRESS* address) { if (!address) return; if (address->Family == SYS_AF_INET) { print_ipv4(address->Address); print(":"); print_u64(address->Port); } else if (address->Family == SYS_AF_INET6) { print("["); print_ipv6(address->Address); print("]:"); print_u64(address->Port); } else { print("unknown"); } } // Implements the next token operation. static const char* next_token(const char* s, char* out, size_t outSize) { if (!s || !out || outSize == 0) return NULL; while (*s == ' ' || *s == '\t') s++; if (*s == 0) { out[0] = 0; return NULL; } size_t n = 0; while (*s && *s != ' ' && *s != '\t') { if (n + 1 < outSize) out[n++] = *s; s++; } out[n] = 0; return s; } // Parses port. static bool parse_port(const char* s, uint16_t* out) { if (!s || !*s || !out) return false; uint32_t v = 0; while (*s >= '0' && *s <= '9') { v = v * 10u + (uint32_t)(*s - '0'); if (v > 65535u) return false; s++; } if (*s != 0 || v == 0) return false; *out = (uint16_t)v; return true; } // Implements the usage operation. static void usage(void) { print("usage: tcpserve.exe [-4|-6] [port]\n"); print("default: tcpserve.exe 8080\n"); } // Runs the requested operation. int main(void) { uint16_t port = 8080; uint32_t family = SYS_AF_INET; const char* cmd = SysGetPeb()->CommandLine.Data; char tok[64]; cmd = next_token(cmd, tok, sizeof(tok)); // program path if (cmd) { const char* rest = next_token(cmd, tok, sizeof(tok)); if (strcmp(tok, "-4") == 0 || strcmp(tok, "-6") == 0) { family = strcmp(tok, "-6") == 0 ? SYS_AF_INET6 : SYS_AF_INET; cmd = rest; if (cmd) (void)next_token(cmd, tok, sizeof(tok)); else tok[0] = 0; } if (tok[0] && !parse_port(tok, &port)) { usage(); SysExitProcess(1); } } uint32_t listener = 0; KSTATUS st = SysCreateSocket(family, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &listener); if (st != NTLSTATUS_SUCCESS) { print("tcpserve: SysCreateSocket failed "); print_u64(st); print("\n"); SysExitProcess(1); } SYS_SOCKET_ADDRESS bindAddr; memset(&bindAddr, 0, sizeof(bindAddr)); bindAddr.Size = sizeof(bindAddr); bindAddr.Family = family; bindAddr.Port = port; st = SysBindSocket(listener, &bindAddr, sizeof(bindAddr)); if (st != NTLSTATUS_SUCCESS) { print("tcpserve: SysBindSocket failed "); print_u64(st); print("\n"); SysCloseHandle(listener); SysExitProcess(1); } st = SysListenSocket(listener, 4); if (st != NTLSTATUS_SUCCESS) { print("tcpserve: SysListenSocket failed "); print_u64(st); print("\n"); SysCloseHandle(listener); SysExitProcess(1); } print("tcpserve: listening on "); if (family == SYS_AF_INET6) print("[::]:"); else print("0.0.0.0:"); print_u64(port); print("\n"); print("tcpserve: accepting one connection...\n"); SYS_SOCKET_ADDRESS remote; size_t remoteSize = sizeof(remote); uint32_t client = 0; st = SysAcceptSocket(listener, &remote, &remoteSize, &client); if (st != NTLSTATUS_SUCCESS) { print("tcpserve: SysAcceptSocket failed "); print_u64(st); print("\n"); SysCloseHandle(listener); SysExitProcess(1); } print("tcpserve: accepted from "); print_socket_address(&remote); print("\n"); char request[1025]; size_t got = 0; SYS_SOCKET_RECV_REQUEST recvRequest = { sizeof(SYS_SOCKET_RECV_REQUEST), client, 0, request, sizeof(request) - 1, &got }; st = SysRecvSocket(&recvRequest); if (st != NTLSTATUS_SUCCESS) { print("tcpserve: SysRecvSocket failed "); print_u64(st); print("\n"); SysCloseHandle(client); SysCloseHandle(listener); SysExitProcess(1); } request[got] = 0; print("tcpserve: received "); print_u64(got); print(" bytes\n"); if (got) { print("--- request begins ---\n"); print(request); print("\n--- request ends ---\n"); } const char body[] = "hello from nt-lite tcpserve\n"; char response[256]; size_t off = 0; #define APPEND_LITERAL(x) do { const char* _s = (x); while (*_s && off + 1 < sizeof(response)) response[off++] = *_s++; response[off] = 0; } while (0) APPEND_LITERAL("HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: "); char lenbuf[24]; uint64_t len = sizeof(body) - 1; int n = 0; if (len == 0) lenbuf[n++] = '0'; else { char rev[24]; while (len && n < (int)sizeof(rev)) { rev[n++] = (char)('0' + (len % 10)); len /= 10; } for (int i = n - 1; i >= 0 && off + 1 < sizeof(response); --i) response[off++] = rev[i]; response[off] = 0; n = 0; } if (n) { for (int i = 0; i < n && off + 1 < sizeof(response); ++i) response[off++] = lenbuf[i]; response[off] = 0; } APPEND_LITERAL("\r\n\r\n"); #undef APPEND_LITERAL size_t sent = 0; SYS_SOCKET_SEND_REQUEST sendResponse = { sizeof(SYS_SOCKET_SEND_REQUEST), client, 0, response, off, &sent }; st = SysSendSocket(&sendResponse); if (st == NTLSTATUS_SUCCESS) { SYS_SOCKET_SEND_REQUEST sendBody = { sizeof(SYS_SOCKET_SEND_REQUEST), client, 0, body, sizeof(body) - 1, &sent }; st = SysSendSocket(&sendBody); } if (st != NTLSTATUS_SUCCESS) print("tcpserve: SysSendSocket failed "), print_u64(st), print("\n"); SysShutdownSocket(client, SYS_SHUTDOWN_BOTH); SysCloseHandle(client); SysCloseHandle(listener); print("tcpserve: done\n"); SysExitProcess(0); return 0; }