// User application entry points for httpget. #include #include #include #include #include // Prints the requested operation. static void print(const char* s) { if (s) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) }; SysWriteConsole(&req); } } // Prints char. static void print_char(char c) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) }; SysWriteConsole(&req); } // 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]); } // Appends char. 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; } // Appends str. 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++); } // Appends u8. 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)); } } // Implements the format ipv4 operation. 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 void append_hex16(char* dst, size_t cap, size_t* off, uint16_t value) { static const char hex[] = "0123456789abcdef"; int started = 0; for (int shift = 12; shift >= 0; shift -= 4) { unsigned nibble = (value >> shift) & 0xfu; if (nibble || started || shift == 0) { append_char(dst, cap, off, hex[nibble]); started = 1; } } } // Implements the format ipv6 operation. static void format_ipv6(char* dst, size_t cap, const uint8_t ip[16]) { size_t off = 0; if (!dst || cap == 0) return; dst[0] = 0; for (int i = 0; i < 8; ++i) { uint16_t word = ((uint16_t)ip[i * 2] << 8) | ip[i * 2 + 1]; append_hex16(dst, cap, &off, word); if (i != 7) append_char(dst, cap, &off, ':'); } } // Implements the format socket address operation. static void format_socket_address(char* dst, size_t cap, const SYS_SOCKET_ADDRESS* address) { if (!address || address->Family == SYS_AF_INET) format_ipv4(dst, cap, address ? address->Address : (const uint8_t*)"\0\0\0\0"); else format_ipv6(dst, cap, address->Address); } // 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; } // 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; } // Implements the usage operation. static void usage(void) { print("usage: httpget.exe [host-or-ipv4] [path]\n"); print("default: httpget.exe 10.0.2.2 /\n"); } // Implements the resolve host operation. static uint32_t resolve_host(const char* host, SYS_SOCKET_ADDRESS* address) { uint8_t ip[4]; if (parse_ipv4(host, ip)) { memset(address, 0, sizeof(*address)); address->Size = sizeof(*address); address->Family = SYS_AF_INET; memcpy(address->Address, ip, 4); return NTLSTATUS_SUCCESS; } size_t resolvedSize = sizeof(*address); SYS_RESOLVE_HOST_REQUEST req; memset(address, 0, sizeof(*address)); memset(&req, 0, sizeof(req)); req.Name = SysSvFromCstr(host); req.Family = SYS_AF_INET6; req.AddressOut = address; req.AddressSizeInOut = &resolvedSize; uint32_t st = SysResolveHost(&req); if (st == NTLSTATUS_SUCCESS) return NTLSTATUS_SUCCESS; resolvedSize = sizeof(*address); memset(address, 0, sizeof(*address)); req.Family = SYS_AF_INET; st = SysResolveHost(&req); return st; } // Runs the requested operation. int main(void) { SYS_SOCKET_ADDRESS addr; 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, &addr); if (st != NTLSTATUS_SUCCESS) { print("httpget: resolve failed "); print_u64(st); print(" for "); print(host); print("\n"); usage(); SysExitProcess(1); } char ipText[64]; format_socket_address(ipText, sizeof(ipText), &addr); print("httpget: GET http://"); print(host); print(path); print(" ("); print(ipText); print(")\n"); uint32_t sock = 0; st = SysCreateSocket(addr.Family, SYS_SOCK_STREAM, SYS_IPPROTO_TCP, &sock); if (st != NTLSTATUS_SUCCESS) { print("httpget: SysCreateSocket failed "); print_u64(st); print("\n"); SysExitProcess(1); } addr.Port = 80; st = SysConnectSocket(sock, &addr, sizeof(addr)); if (st != NTLSTATUS_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 != NTLSTATUS_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; while (true) { size_t got = 0; st = SysRecvSocket(sock, buf, sizeof(buf) - 1, 0, &got); if (st != NTLSTATUS_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; }