Files
nt-lite/code/udp/udp.c
T

234 lines
6.2 KiB
C

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <syscall.h>
static void print(const char* s) {
if (s) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) }; SysWriteConsole(&req); }
}
static void print_char(char c) {
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
SysWriteConsole(&req);
}
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]);
}
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]);
}
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;
}
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;
}
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;
}
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;
}
static void usage(void) {
print("usage:\n");
print(" udp.exe send <ipv4> <port> [message]\n");
print(" udp.exe listen <port>\n");
print("examples:\n");
print(" udp.exe send 10.0.2.2 9999 hello\n");
print(" udp.exe listen 9999\n");
}
static int run_send(const char* cmd) {
char tok[256];
uint8_t ip[4];
uint16_t port = 0;
cmd = next_token(cmd, tok, sizeof(tok));
if (!tok[0] || !parse_ipv4(tok, ip)) { usage(); 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;
uint32_t st = SysSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysSocket failed "); print_u64(st); print("\n");
return 1;
}
SYS_SOCKET_ADDRESS_IPV4 remote;
memset(&remote, 0, sizeof(remote));
remote.Family = SYS_AF_INET;
remote.Port = port;
remote.Address[0] = ip[0];
remote.Address[1] = ip[1];
remote.Address[2] = ip[2];
remote.Address[3] = ip[3];
size_t sent = 0;
SYS_SOCKET_SEND_TO_REQUEST req;
memset(&req, 0, sizeof(req));
req.Buffer = msg;
req.Length = strlen(msg);
req.RemoteAddress = &remote;
req.RemoteAddressSize = sizeof(remote);
req.SentOut = &sent;
st = SysSendTo(sock, &req);
SysCloseHandle(sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysSendTo failed "); print_u64(st); print("\n");
return 1;
}
print("udp: sent "); print_u64(sent); print(" bytes to "); print_ipv4(ip); print(":"); print_u64(port); print("\n");
return 0;
}
static int run_listen(const char* cmd) {
char tok[64];
uint16_t port = 0;
(void)next_token(cmd, tok, sizeof(tok));
if (!tok[0] || !parse_port(tok, &port)) { usage(); return 1; }
uint32_t sock = 0;
uint32_t st = SysSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysSocket failed "); print_u64(st); print("\n");
return 1;
}
SYS_SOCKET_ADDRESS_IPV4 bindAddr;
memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.Family = SYS_AF_INET;
bindAddr.Port = port;
st = SysBind(sock, &bindAddr, sizeof(bindAddr));
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysBind failed "); print_u64(st); print("\n");
SysCloseHandle(sock);
return 1;
}
print("udp: listening on 0.0.0.0:"); print_u64(port); print(" for one datagram\n");
char buf[1025];
SYS_SOCKET_ADDRESS_IPV4 remote;
size_t remoteSize = sizeof(remote);
size_t got = 0;
SYS_SOCKET_RECV_FROM_REQUEST req;
memset(&req, 0, sizeof(req));
req.Buffer = buf;
req.Length = sizeof(buf) - 1;
req.RemoteAddressOut = &remote;
req.RemoteAddressSizeInOut = &remoteSize;
req.ReceivedOut = &got;
st = SysRecvFrom(sock, &req);
SysCloseHandle(sock);
if (st != SYS_STATUS_SUCCESS) {
print("udp: SysRecvFrom failed "); print_u64(st); print("\n");
return 1;
}
buf[got] = 0;
print("udp: received "); print_u64(got); print(" bytes from ");
if (remote.Family == SYS_AF_INET) {
print_ipv4(remote.Address); print(":"); print_u64(remote.Port);
} else {
print("unknown");
}
print("\n");
print(buf);
if (got && buf[got - 1] != '\n') print("\n");
return 0;
}
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;
}