diff --git a/src/libs/libKernel.cpp b/src/libs/libKernel.cpp index b8b60624c..ac012ba1e 100644 --- a/src/libs/libKernel.cpp +++ b/src/libs/libKernel.cpp @@ -2006,6 +2006,11 @@ int KYTY_SYSV_ABI listen(int s, int backlog) { return Network::Net::Listen(s, backlog); } +int KYTY_SYSV_ABI shutdown(int s, int how) { + PRINT_NAME(); + return Network::Net::Shutdown(s, how); +} + int KYTY_SYSV_ABI accept(int s, void* addr, uint32_t* addrlen) { PRINT_NAME(); return Network::Net::Accept(s, addr, addrlen); @@ -2242,6 +2247,7 @@ LIB_DEFINE(InitLibKernel_1_Posix) { LIB_FUNC("KuOmgKoqCdY", Posix::bind); LIB_FUNC("XVL8So3QJUk", Posix::connect); LIB_FUNC("pxnCmagrtao", Posix::listen); + LIB_FUNC("TUuiYS2kE8s", Posix::shutdown); LIB_FUNC("3e+4Iv7IJ8U", Posix::accept); LIB_FUNC("RenI1lL1WFk", Posix::getsockname); LIB_FUNC("6O8EwYOgH9Y", Posix::getsockopt); diff --git a/src/libs/network.cpp b/src/libs/network.cpp index fc9688544..5b330c62e 100644 --- a/src/libs/network.cpp +++ b/src/libs/network.cpp @@ -2096,19 +2096,15 @@ int KYTY_SYSV_ABI Shutdown(int s, int how) { return -1; } -#if defined(_WIN32) - if (::shutdown(socket, how) == SOCKET_ERROR) { + if (::shutdown(socket, how) != 0) { return SetHostSocketError(); } +#if defined(_WIN32) if (how == SD_RECEIVE || how == SD_BOTH) { transport->receive_shutdown.store(true, std::memory_order_relaxed); } - - return 0; -#else - *Posix::GetErrorAddr() = Posix::POSIX_ENOSYS; - return -1; #endif + return 0; } int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) { diff --git a/tests/KernelFileSystemTests.cpp b/tests/KernelFileSystemTests.cpp index a6e14fe36..c1407c676 100644 --- a/tests/KernelFileSystemTests.cpp +++ b/tests/KernelFileSystemTests.cpp @@ -1905,6 +1905,11 @@ void CheckSocketWakeup() { namespace Net = Libs::Network::Net; Loader::SymbolDatabase symbols; Libs::LibNet::InitNet_1_Net(&symbols); + Libs::InitLibKernel_1(&symbols); + const auto *shutdown_symbol = symbols.Find( + {"TUuiYS2kE8s", "Posix", 1, "libkernel", 1, 1, Loader::SymbolType::Func}); + Check(shutdown_symbol != nullptr, "POSIX shutdown export resolves"); + const auto shutdown = reinterpret_cast(shutdown_symbol->vaddr); const auto *connect_symbol = symbols.Find( {"OXXX4mUk3uk", "Net", 1, "Net", 1, 1, Loader::SymbolType::Func}); const auto *getsockopt_symbol = symbols.Find( @@ -2145,6 +2150,29 @@ void CheckSocketWakeup() { CheckSocketReceiveBuffer(reader, writer); CheckSocketReceiveConcurrency(); #endif + const auto [shutdown_reader, shutdown_writer] = CreateTcpPair(); + const auto ready_to_read = [](int fd) { + std::array readable {}; + readable[fd / 64] = uint64_t {1} << (fd % 64); + const std::array timeout {2, 0}; + return Net::Select(fd + 1, readable.data(), nullptr, nullptr, timeout.data()) == 1; + }; + Check(shutdown(-1, 1) == -1 && + *Libs::Posix::GetErrorAddr() == Libs::Posix::POSIX_EBADF && + shutdown(shutdown_writer, 3) == -1 && + *Libs::Posix::GetErrorAddr() == Libs::Posix::POSIX_EINVAL, + "shutdown rejects invalid descriptors and directions"); + Check(Net::Send(shutdown_writer, "x", 1, 0) == 1 && shutdown(shutdown_writer, 1) == 0 && + ready_to_read(shutdown_reader) && + Net::Recv(shutdown_reader, received.data(), 1, 0) == 1 && received[0] == 'x' && + ready_to_read(shutdown_reader) && + Net::Recv(shutdown_reader, received.data(), 1, 0) == 0 && + Net::Send(shutdown_reader, "y", 1, 0) == 1 && + ready_to_read(shutdown_writer) && + Net::Recv(shutdown_writer, received.data(), 1, 0) == 1 && received[0] == 'y', + "write shutdown drains queued bytes, signals EOF, and preserves reverse traffic"); + Check(Net::SocketClose(shutdown_reader) == 0 && Net::SocketClose(shutdown_writer) == 0, + "close half-shutdown sockets"); Check(Net::SocketClose(writer) == 0, "close wake writer"); *net_errno = Libs::Posix::POSIX_EINVAL; Check(net_recv(reader, received.data(), received.size(), 0) == 0 &&