Files
nt-lite/code/user/apps/httpget/httpget.c
T

259 lines
7.4 KiB
C

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <ntlite/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 append_char(char* dst, size_t cap, size_t* off, char c) {
if (!dst || !off || cap == 0 || *off + 1 >= cap) return;
dst[*off] = c;
*off += 1;
dst[*off] = 0;
}
static void append_str(char* dst, size_t cap, size_t* off, const char* s) {
if (!s) return;
while (*s) append_char(dst, cap, off, *s++);
}
static void append_u8(char* dst, size_t cap, size_t* off, uint8_t v) {
if (v >= 100) {
append_char(dst, cap, off, (char)('0' + v / 100));
v %= 100;
append_char(dst, cap, off, (char)('0' + v / 10));
append_char(dst, cap, off, (char)('0' + v % 10));
} else if (v >= 10) {
append_char(dst, cap, off, (char)('0' + v / 10));
append_char(dst, cap, off, (char)('0' + v % 10));
} else {
append_char(dst, cap, off, (char)('0' + v));
}
}
static void format_ipv4(char* dst, size_t cap, const uint8_t ip[4]) {
size_t off = 0;
if (!dst || cap == 0) return;
dst[0] = 0;
append_u8(dst, cap, &off, ip[0]); append_char(dst, cap, &off, '.');
append_u8(dst, cap, &off, ip[1]); append_char(dst, cap, &off, '.');
append_u8(dst, cap, &off, ip[2]); append_char(dst, cap, &off, '.');
append_u8(dst, cap, &off, ip[3]);
}
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 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 void usage(void) {
print("usage: httpget.exe [host-or-ipv4] [path]\n");
print("default: httpget.exe 10.0.2.2 /\n");
}
static uint32_t resolve_host(const char* host, uint8_t ip[4]) {
if (parse_ipv4(host, ip))
return SYS_STATUS_SUCCESS;
SYS_SOCKET_ADDRESS_IPV4 resolved;
size_t resolvedSize = sizeof(resolved);
SYS_RESOLVE_HOST_REQUEST req;
memset(&resolved, 0, sizeof(resolved));
memset(&req, 0, sizeof(req));
req.Name = SysSvFromCstr(host);
req.Family = SYS_AF_INET;
req.AddressOut = &resolved;
req.AddressSizeInOut = &resolvedSize;
uint32_t st = SysResolveHost(&req);
if (st != SYS_STATUS_SUCCESS)
return st;
if (resolved.Family != SYS_AF_INET)
return SYS_STATUS_NOT_FOUND;
ip[0] = resolved.Address[0];
ip[1] = resolved.Address[1];
ip[2] = resolved.Address[2];
ip[3] = resolved.Address[3];
return SYS_STATUS_SUCCESS;
}
int main(void) {
uint8_t ip[4] = {10, 0, 2, 2};
char host[256];
char path[128];
strcpy(host, "10.0.2.2");
path[0] = '/';
path[1] = 0;
const char* cmd = SysGetPeb()->CommandLine.Data;
char tok[256];
cmd = next_token(cmd, tok, sizeof(tok)); // program path
if (cmd) {
const char* rest = next_token(cmd, tok, sizeof(tok));
if (tok[0]) {
if (strlen(tok) >= sizeof(host)) {
print("httpget: host too long\n");
SysExitProcess(1);
}
strcpy(host, tok);
cmd = rest;
}
if (cmd) {
(void)next_token(cmd, tok, sizeof(tok));
if (tok[0]) {
size_t len = strlen(tok);
if (len + 2 > sizeof(path)) {
print("httpget: path too long\n");
SysExitProcess(1);
}
if (tok[0] != '/') {
path[0] = '/';
memcpy(path + 1, tok, len + 1);
} else {
memcpy(path, tok, len + 1);
}
}
}
}
uint32_t st = resolve_host(host, ip);
if (st != SYS_STATUS_SUCCESS) {
print("httpget: resolve failed "); print_u64(st); print(" for "); print(host); print("\n");
usage();
SysExitProcess(1);
}
char ipText[16];
format_ipv4(ipText, sizeof(ipText), ip);
print("httpget: GET http://");
print(host);
print(path);
print(" (");
print(ipText);
print(")\n");
uint32_t sock = 0;
st = SysCreateSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &sock);
if (st != SYS_STATUS_SUCCESS) {
print("httpget: SysCreateSocket failed "); print_u64(st); print("\n");
SysExitProcess(1);
}
SYS_SOCKET_ADDRESS_IPV4 addr;
memset(&addr, 0, sizeof(addr));
addr.Family = SYS_AF_INET;
addr.Port = 80;
addr.Address[0] = ip[0];
addr.Address[1] = ip[1];
addr.Address[2] = ip[2];
addr.Address[3] = ip[3];
st = SysConnectSocket(sock, &addr, sizeof(addr));
if (st != SYS_STATUS_SUCCESS) {
print("httpget: SysConnectSocket failed "); print_u64(st); print("\n");
SysCloseHandle(sock);
SysExitProcess(1);
}
char request[512];
size_t off = 0;
request[0] = 0;
append_str(request, sizeof(request), &off, "GET ");
append_str(request, sizeof(request), &off, path);
append_str(request, sizeof(request), &off, " HTTP/1.0\r\nHost: ");
append_str(request, sizeof(request), &off, host);
append_str(request, sizeof(request), &off, "\r\nUser-Agent: nt-lite-sys-socket\r\nConnection: close\r\n\r\n");
size_t totalSent = 0;
while (totalSent < off) {
size_t sent = 0;
st = SysSendSocket(sock, request + totalSent, off - totalSent, 0, &sent);
if (st != SYS_STATUS_SUCCESS || sent == 0) {
print("httpget: SysSendSocket failed "); print_u64(st); print(" sent="); print_u64(sent); print("\n");
SysCloseHandle(sock);
SysExitProcess(1);
}
totalSent += sent;
}
char buf[513];
size_t total = 0;
for (;;) {
size_t got = 0;
st = SysRecvSocket(sock, buf, sizeof(buf) - 1, 0, &got);
if (st != SYS_STATUS_SUCCESS) {
print("\nhttpget: SysRecvSocket failed "); print_u64(st); print(" after "); print_u64(total); print(" bytes\n");
SysCloseHandle(sock);
SysExitProcess(1);
}
if (got == 0) break;
buf[got] = 0;
print(buf);
total += got;
}
print("\nhttpget: done, "); print_u64(total); print(" bytes\n");
SysShutdownSocket(sock, SYS_SHUTDOWN_BOTH);
SysCloseHandle(sock);
SysExitProcess(0);
return 0;
}