diff --git a/userspace/CMakeLists.txt b/userspace/CMakeLists.txt index 0e72806a..29f6c707 100644 --- a/userspace/CMakeLists.txt +++ b/userspace/CMakeLists.txt @@ -34,6 +34,7 @@ set(USERSPACE_PROJECTS test-globals test-mouse test-sort + test-tcp test-unix-socket touch u8sum diff --git a/userspace/test-tcp/CMakeLists.txt b/userspace/test-tcp/CMakeLists.txt new file mode 100644 index 00000000..b96ed9d0 --- /dev/null +++ b/userspace/test-tcp/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.26) + +project(test-tcp CXX) + +set(SOURCES + main.cpp +) + +add_executable(test-tcp ${SOURCES}) +target_compile_options(test-tcp PUBLIC -O2 -g) +target_link_libraries(test-tcp PUBLIC libc) + +add_custom_target(test-tcp-install + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/test-tcp ${BANAN_BIN}/ + DEPENDS test-tcp +) diff --git a/userspace/test-tcp/main.cpp b/userspace/test-tcp/main.cpp new file mode 100644 index 00000000..9234cbd0 --- /dev/null +++ b/userspace/test-tcp/main.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include + +in_addr_t get_ipv4_address(const char* query) +{ + if (in_addr_t ipv4 = inet_addr(query); ipv4 != (in_addr_t)(-1)) + return ipv4; + + int socket = ::socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (socket == -1) + { + perror("socket"); + return -1; + } + + sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, "/tmp/resolver.sock"); + if (connect(socket, (sockaddr*)&addr, sizeof(addr)) == -1) + { + perror("connect"); + close(socket); + return -1; + } + + if (send(socket, query, strlen(query), 0) == -1) + { + perror("send"); + close(socket); + return -1; + } + + sockaddr_storage storage; + if (recv(socket, &storage, sizeof(storage), 0) == -1) + { + perror("recv"); + close(socket); + return -1; + } + + close(socket); + + return *reinterpret_cast(storage.ss_storage); +} + +int main(int argc, char** argv) +{ + if (argc != 2) + { + fprintf(stderr, "usage: %s IPADDR\n", argv[0]); + return 1; + } + + in_addr_t ipv4 = get_ipv4_address(argv[1]); + if (ipv4 == (in_addr_t)(-1)) + { + fprintf(stderr, "could not parse address '%s'\n", argv[1]); + return 1; + } + + int socket = ::socket(AF_INET, SOCK_STREAM, 0); + if (socket == -1) + { + perror("socket"); + return 1; + } + + printf("connecting to %s\n", inet_ntoa({ .s_addr = ipv4 })); + + sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(80); + server_addr.sin_addr.s_addr = ipv4; + if (connect(socket, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) + { + perror("connect"); + return 1; + } + + char request[128]; + strcpy(request, "GET / HTTP/1.1\r\n"); + strcat(request, "Host: "); strcat(request, argv[1]); strcat(request, "\r\n"); + strcat(request, "Accept: */*\r\n"); + strcat(request, "Connection: close\r\n"); + strcat(request, "\r\n"); + if (send(socket, request, strlen(request), 0) == -1) + { + perror("send"); + return 1; + } + + char buffer[1024]; + for (;;) + { + ssize_t nrecv = recv(socket, buffer, sizeof(buffer), 0); + if (nrecv == -1) + { + perror("recv"); + break; + } + write(STDOUT_FILENO, buffer, nrecv); + } + + close(socket); + return 0; +}