diff --git a/userspace/CMakeLists.txt b/userspace/CMakeLists.txt index 95091e98e1..0e72806ad1 100644 --- a/userspace/CMakeLists.txt +++ b/userspace/CMakeLists.txt @@ -34,6 +34,7 @@ set(USERSPACE_PROJECTS test-globals test-mouse test-sort + test-unix-socket touch u8sum whoami diff --git a/userspace/test-unix-socket/CMakeLists.txt b/userspace/test-unix-socket/CMakeLists.txt new file mode 100644 index 0000000000..814407c288 --- /dev/null +++ b/userspace/test-unix-socket/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.26) + +project(test-unix-socket CXX) + +set(SOURCES + main.cpp +) + +add_executable(test-unix-socket ${SOURCES}) +target_compile_options(test-unix-socket PUBLIC -O2 -g) +target_link_libraries(test-unix-socket PUBLIC libc) + +add_custom_target(test-unix-socket-install + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/test-unix-socket ${BANAN_BIN}/ + DEPENDS test-unix-socket +) diff --git a/userspace/test-unix-socket/main.cpp b/userspace/test-unix-socket/main.cpp new file mode 100644 index 0000000000..d3e0308fb4 --- /dev/null +++ b/userspace/test-unix-socket/main.cpp @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include + +#define SOCK_PATH "/tmp/test.sock" + +int server_connection() +{ + int socket = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (socket == -1) + { + perror("server: socket"); + return 1; + } + + sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, SOCK_PATH); + if (bind(socket, (sockaddr*)&addr, sizeof(addr))) + { + perror("server: bind"); + return 1; + } + + if (listen(socket, 0) == -1) + { + perror("server: listen"); + return 1; + } + + int client = accept(socket, nullptr, nullptr); + if (client == -1) + { + perror("server: accept"); + return 1; + } + + sleep(2); + + char buffer[128]; + ssize_t nrecv = recv(client, buffer, sizeof(buffer), 0); + if (nrecv == -1) + { + perror("server: recv"); + return 1; + } + + printf("server: read %d bytes\n", (int)nrecv); + printf("server: '%s'\n", buffer); + + char message[] = "Hello from server"; + if (send(client, message, sizeof(message), 0) == -1) + { + perror("server: send"); + return 1; + } + + close(client); + close(socket); + return 0; +} + +int client_connection() +{ + sleep(1); + + int socket = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (socket == -1) + { + perror("client: socket"); + return 1; + } + + sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, SOCK_PATH); + if (connect(socket, (sockaddr*)&addr, sizeof(addr)) == -1) + { + perror("client: connect"); + return 1; + } + + char message[] = "Hello from client"; + if (send(socket, message, sizeof(message), 0) == -1) + { + perror("client: send"); + return 1; + } + + char buffer[128]; + ssize_t nrecv = recv(socket, buffer, sizeof(buffer), 0); + if (nrecv == -1) + { + perror("client: recv"); + return 1; + } + + printf("client: read %d bytes\n", (int)nrecv); + printf("client: '%s'\n", buffer); + + close(socket); + return 0; +} + +int server_connectionless() +{ + int socket = ::socket(AF_UNIX, SOCK_DGRAM, 0); + if (socket == -1) + { + perror("server: socket"); + return 1; + } + + sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, SOCK_PATH); + if (bind(socket, (sockaddr*)&addr, sizeof(addr))) + { + perror("server: bind"); + return 1; + } + + sleep(2); + + char buffer[128]; + ssize_t nrecv = recv(socket, buffer, sizeof(buffer), 0); + if (nrecv == -1) + { + perror("server: recv"); + return 1; + } + + close(socket); + return 0; +} + +int client_connectionless() +{ + sleep(1); + + int socket = ::socket(AF_UNIX, SOCK_DGRAM, 0); + if (socket == -1) + { + perror("client: socket"); + return 1; + } + + sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, SOCK_PATH); + char message[] = "Hello from client"; + if (sendto(socket, message, sizeof(message), 0, (sockaddr*)&addr, sizeof(addr)) == -1) + { + perror("client: send"); + return 1; + } + + close(socket); + return 0; +} + +int test_mode(int (*client)(), int (*server)()) +{ + pid_t pid = fork(); + if (pid == -1) + { + perror("fork"); + return 1; + } + + if (pid == 0) + exit(server()); + + if (int ret = client()) + { + kill(pid, SIGKILL); + return ret; + } + + int ret; + waitpid(pid, &ret, 0); + + if (remove(SOCK_PATH) == -1) + perror("remove"); + + return ret; +} + +int main() +{ + if (test_mode(client_connection, server_connection)) + return 1; + if (test_mode(client_connectionless, server_connectionless)) + return 2; + return 0; +}