// User application entry points for udp. #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 u8. static bool parse_u8(const char** p, uint8_t* out) { const char* s = *p; uint32_t v = 0; int digits = 0; while (*s >= '0' && *s <= '9') { v = v * 10u + (uint32_t)(*s - '0'); if (v > 255u) return false; s++; digits++; } if (digits == 0) return false; *out = (uint8_t)v; *p = s; return true; } // Parses ipv4. static bool parse_ipv4(const char* s, uint8_t ip[4]) { if (!s || !ip) return false; for (int i = 0; i < 4; i++) { if (!parse_u8(&s, &ip[i])) return false; if (i != 3) { if (*s != '.') return false; s++; } } return *s == 0; } // 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:\n"); print(" udp.exe send [message]\n"); print(" udp.exe listen [-4|-6] \n"); print("examples:\n"); print(" udp.exe send 10.0.2.2 9999 hello\n"); print(" udp.exe send ::1 9999 hello\n"); print(" udp.exe listen -6 9999\n"); } // Resolves an IPv4 or IPv6 destination. static KSTATUS resolve_address(const char* text, SYS_SOCKET_ADDRESS* out) { uint8_t ip[4]; if (parse_ipv4(text, ip)) { memset(out, 0, sizeof(*out)); out->Size = sizeof(*out); out->Family = SYS_AF_INET; memcpy(out->Address, ip, 4); return NTLSTATUS_SUCCESS; } SYS_RESOLVE_HOST_REQUEST req; size_t addressSize = sizeof(*out); memset(out, 0, sizeof(*out)); memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Name = SysSvFromCstr(text); req.Family = SYS_AF_INET6; req.AddressOut = out; req.AddressSizeInOut = &addressSize; KSTATUS status = SysResolveHost(&req); if (status == NTLSTATUS_SUCCESS) return NTLSTATUS_SUCCESS; addressSize = sizeof(*out); memset(out, 0, sizeof(*out)); req.Family = SYS_AF_INET; return SysResolveHost(&req); } // Runs send. static int run_send(const char* cmd) { char tok[256]; SYS_SOCKET_ADDRESS remote; uint16_t port = 0; cmd = next_token(cmd, tok, sizeof(tok)); if (!tok[0]) { usage(); return 1; } KSTATUS status = resolve_address(tok, &remote); if (status != NTLSTATUS_SUCCESS) { print("udp: resolve failed "); print_u64(status); print("\n"); return 1; } cmd = next_token(cmd, tok, sizeof(tok)); if (!tok[0] || !parse_port(tok, &port)) { usage(); return 1; } // Skip leading whitespace, then take the entire remaining command line. if (cmd) { while (*cmd == ' ' || *cmd == '\t') { cmd++; } } const char* msg = "hello from nt-lite udp\n"; if (cmd && *cmd != '\0') { msg = cmd; } uint32_t sock = 0; KSTATUS st = SysCreateSocket(remote.Family, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock); if (st != NTLSTATUS_SUCCESS) { print("udp: SysCreateSocket failed "); print_u64(st); print("\n"); return 1; } remote.Port = port; size_t sent = 0; SYS_SOCKET_SEND_TO_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Buffer = msg; req.Length = strlen(msg); req.RemoteAddress = &remote; req.RemoteAddressSize = sizeof(remote); req.SentOut = &sent; st = SysSendToSocket(sock, &req); SysCloseHandle(sock); if (st != NTLSTATUS_SUCCESS) { print("udp: SysSendToSocket failed "); print_u64(st); print("\n"); return 1; } print("udp: sent "); print_u64(sent); print(" bytes to "); print_socket_address(&remote); print("\n"); return 0; } // Runs listen. static int run_listen(const char* cmd) { char tok[64]; uint16_t port = 0; uint32_t family = SYS_AF_INET; 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; if (rest) (void)next_token(rest, tok, sizeof(tok)); else tok[0] = 0; } if (!tok[0] || !parse_port(tok, &port)) { usage(); return 1; } uint32_t sock = 0; KSTATUS st = SysCreateSocket(family, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock); if (st != NTLSTATUS_SUCCESS) { print("udp: SysCreateSocket failed "); print_u64(st); print("\n"); return 1; } SYS_SOCKET_ADDRESS bindAddr; memset(&bindAddr, 0, sizeof(bindAddr)); bindAddr.Size = sizeof(bindAddr); bindAddr.Family = family; bindAddr.Port = port; st = SysBindSocket(sock, &bindAddr, sizeof(bindAddr)); if (st != NTLSTATUS_SUCCESS) { print("udp: SysBindSocket failed "); print_u64(st); print("\n"); SysCloseHandle(sock); return 1; } print("udp: listening on "); if (family == SYS_AF_INET6) print("[::]:"); else print("0.0.0.0:"); print_u64(port); print(" for one datagram\n"); char buf[1025]; SYS_SOCKET_ADDRESS remote; size_t remoteSize = sizeof(remote); size_t got = 0; SYS_SOCKET_RECV_FROM_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Buffer = buf; req.Length = sizeof(buf) - 1; req.RemoteAddressOut = &remote; req.RemoteAddressSizeInOut = &remoteSize; req.ReceivedOut = &got; st = SysRecvFromSocket(sock, &req); SysCloseHandle(sock); if (st != NTLSTATUS_SUCCESS) { print("udp: SysRecvFromSocket failed "); print_u64(st); print("\n"); return 1; } buf[got] = 0; print("udp: received "); print_u64(got); print(" bytes from "); print_socket_address(&remote); print("\n"); print(buf); if (got && buf[got - 1] != '\n') print("\n"); return 0; } // Runs the requested operation. int main(void) { const char* cmd = SysGetPeb()->CommandLine.Data; char tok[64]; cmd = next_token(cmd, tok, sizeof(tok)); // program path cmd = next_token(cmd, tok, sizeof(tok)); // verb if (!tok[0]) { usage(); SysExitProcess(1); } int rc; if (strcmp(tok, "send") == 0) { rc = run_send(cmd); } else if (strcmp(tok, "listen") == 0) { rc = run_listen(cmd); } else { usage(); rc = 1; } SysExitProcess(rc); return rc; }