259 lines
7.4 KiB
C
259 lines
7.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 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 = SysSocket(SYS_AF_INET, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &sock);
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("httpget: SysSocket 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 = SysConnect(sock, &addr, sizeof(addr));
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("httpget: SysConnect 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 = SysSend(sock, request + totalSent, off - totalSent, 0, &sent);
|
|
if (st != SYS_STATUS_SUCCESS || sent == 0) {
|
|
print("httpget: SysSend 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 = SysRecv(sock, buf, sizeof(buf) - 1, 0, &got);
|
|
if (st != SYS_STATUS_SUCCESS) {
|
|
print("\nhttpget: SysRecv 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");
|
|
SysShutdown(sock, SYS_SHUTDOWN_BOTH);
|
|
SysCloseHandle(sock);
|
|
SysExitProcess(0);
|
|
return 0;
|
|
}
|