184 lines
5.4 KiB
C
184 lines
5.4 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_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: tcpserve.exe [port]\n");
|
|
print("default: tcpserve.exe 8080\n");
|
|
}
|
|
|
|
int main(void) {
|
|
uint16_t port = 8080;
|
|
|
|
const char* cmd = SysGetPeb()->CommandLine.Data;
|
|
char tok[64];
|
|
cmd = next_token(cmd, tok, sizeof(tok)); // program path
|
|
if (cmd) {
|
|
(void)next_token(cmd, tok, sizeof(tok));
|
|
if (tok[0] && !parse_port(tok, &port)) {
|
|
usage();
|
|
SysExitProcess(1);
|
|
}
|
|
}
|
|
|
|
uint32_t listener = 0;
|
|
uint32_t st = SysSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &listener);
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("tcpserve: SysSocket failed "); print_u64(st); print("\n");
|
|
SysExitProcess(1);
|
|
}
|
|
|
|
SYS_SOCKET_ADDRESS_IPV4 bindAddr;
|
|
memset(&bindAddr, 0, sizeof(bindAddr));
|
|
bindAddr.Family = SYS_AF_INET;
|
|
bindAddr.Port = port;
|
|
bindAddr.Address[0] = 0;
|
|
bindAddr.Address[1] = 0;
|
|
bindAddr.Address[2] = 0;
|
|
bindAddr.Address[3] = 0;
|
|
|
|
st = SysBind(listener, &bindAddr, sizeof(bindAddr));
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("tcpserve: SysBind failed "); print_u64(st); print("\n");
|
|
SysCloseHandle(listener);
|
|
SysExitProcess(1);
|
|
}
|
|
|
|
st = SysListen(listener, 4);
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("tcpserve: SysListen failed "); print_u64(st); print("\n");
|
|
SysCloseHandle(listener);
|
|
SysExitProcess(1);
|
|
}
|
|
|
|
print("tcpserve: listening on 0.0.0.0:"); print_u64(port); print("\n");
|
|
print("tcpserve: accepting one connection...\n");
|
|
|
|
SYS_SOCKET_ADDRESS_IPV4 remote;
|
|
size_t remoteSize = sizeof(remote);
|
|
uint32_t client = 0;
|
|
st = SysAccept(listener, &remote, &remoteSize, &client);
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("tcpserve: SysAccept failed "); print_u64(st); print("\n");
|
|
SysCloseHandle(listener);
|
|
SysExitProcess(1);
|
|
}
|
|
|
|
print("tcpserve: accepted from ");
|
|
if (remote.Family == SYS_AF_INET) {
|
|
print_ipv4(remote.Address);
|
|
print(":"); print_u64(remote.Port);
|
|
} else {
|
|
print("unknown");
|
|
}
|
|
print("\n");
|
|
|
|
char request[1025];
|
|
size_t got = 0;
|
|
st = SysRecv(client, request, sizeof(request) - 1, 0, &got);
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("tcpserve: SysRecv 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;
|
|
st = SysSend(client, response, off, 0, &sent);
|
|
if (st == SYS_STATUS_SUCCESS)
|
|
st = SysSend(client, body, sizeof(body) - 1, 0, &sent);
|
|
if (st != SYS_STATUS_SUCCESS)
|
|
print("tcpserve: SysSend failed "), print_u64(st), print("\n");
|
|
|
|
SysShutdown(client, SYS_SHUTDOWN_BOTH);
|
|
SysCloseHandle(client);
|
|
SysCloseHandle(listener);
|
|
print("tcpserve: done\n");
|
|
SysExitProcess(0);
|
|
return 0;
|
|
}
|