From be8c35eef173a4d38b1843a4b35fe818a506a6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Mon, 1 Sep 2025 00:02:26 +0200 Subject: [PATCH] Implement send/recvmsg (#3487) * Implement send/recvmsg * Windows * fixed windows * cleanups * updated * suggestions --------- Co-authored-by: georgemoralis --- src/core/libraries/kernel/kernel.cpp | 1 + src/core/libraries/network/p2p_sockets.cpp | 12 +++++ src/core/libraries/network/posix_sockets.cpp | 51 ++++++++++++++++++++ src/core/libraries/network/sockets.h | 26 ++++++++++ src/core/libraries/network/sys_net.cpp | 27 ++++++++++- 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index 8cc5a55c5..1898e1849 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -288,6 +288,7 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket); LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto); LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom); + LIB_FUNCTION("hI7oVeOluPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvmsg); LIB_FUNCTION("TXFFFiNldU8", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_getpeername); LIB_FUNCTION("6O8EwYOgH9Y", "libScePosix", 1, "libkernel", 1, 1, diff --git a/src/core/libraries/network/p2p_sockets.cpp b/src/core/libraries/network/p2p_sockets.cpp index a9deacf2f..cfdd1bda7 100644 --- a/src/core/libraries/network/p2p_sockets.cpp +++ b/src/core/libraries/network/p2p_sockets.cpp @@ -34,6 +34,12 @@ int P2PSocket::Listen(int backlog) { return 0; } +int P2PSocket::SendMessage(const OrbisNetMsghdr* msg, int flags) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + *Libraries::Kernel::__Error() = ORBIS_NET_EAGAIN; + return -1; +} + int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); @@ -41,6 +47,12 @@ int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSoc return -1; } +int P2PSocket::ReceiveMessage(OrbisNetMsghdr* msg, int flags) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + *Libraries::Kernel::__Error() = ORBIS_NET_EAGAIN; + return -1; +} + int P2PSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); *Libraries::Kernel::__Error() = ORBIS_NET_EAGAIN; diff --git a/src/core/libraries/network/posix_sockets.cpp b/src/core/libraries/network/posix_sockets.cpp index 15e73e3c3..41aaeb46a 100644 --- a/src/core/libraries/network/posix_sockets.cpp +++ b/src/core/libraries/network/posix_sockets.cpp @@ -183,6 +183,32 @@ int PosixSocket::Listen(int backlog) { return ConvertReturnErrorCode(::listen(sock, backlog)); } +int PosixSocket::SendMessage(const OrbisNetMsghdr* msg, int flags) { + std::scoped_lock lock{m_mutex}; +#ifdef _WIN32 + DWORD bytesSent = 0; + LPFN_WSASENDMSG wsasendmsg = nullptr; + GUID guid = WSAID_WSASENDMSG; + DWORD bytes = 0; + + if (WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &wsasendmsg, + sizeof(wsasendmsg), &bytes, nullptr, nullptr) != 0) { + return ConvertReturnErrorCode(-1); + } + + int res = wsasendmsg(sock, reinterpret_cast(const_cast(msg)), flags, + &bytesSent, nullptr, nullptr); + + if (res == SOCKET_ERROR) { + return ConvertReturnErrorCode(-1); + } + return static_cast(bytesSent); +#else + int res = sendmsg(sock, reinterpret_cast(msg), flags); + return ConvertReturnErrorCode(res); +#endif +} + int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) { std::scoped_lock lock{m_mutex}; @@ -196,6 +222,31 @@ int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetS } } +int PosixSocket::ReceiveMessage(OrbisNetMsghdr* msg, int flags) { + std::scoped_lock lock{receive_mutex}; +#ifdef _WIN32 + LPFN_WSARECVMSG wsarecvmsg = nullptr; + GUID guid = WSAID_WSARECVMSG; + DWORD bytes = 0; + + if (WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &wsarecvmsg, + sizeof(wsarecvmsg), &bytes, nullptr, nullptr) != 0) { + return ConvertReturnErrorCode(-1); + } + + DWORD bytesReceived = 0; + int res = wsarecvmsg(sock, reinterpret_cast(msg), &bytesReceived, nullptr, nullptr); + + if (res == SOCKET_ERROR) { + return ConvertReturnErrorCode(-1); + } + return static_cast(bytesReceived); +#else + int res = recvmsg(sock, reinterpret_cast(msg), flags); + return ConvertReturnErrorCode(res); +#endif +} + int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) { std::scoped_lock lock{receive_mutex}; diff --git a/src/core/libraries/network/sockets.h b/src/core/libraries/network/sockets.h index 42fe1bcd7..f997ddb7b 100644 --- a/src/core/libraries/network/sockets.h +++ b/src/core/libraries/network/sockets.h @@ -7,9 +7,29 @@ #define _WINSOCK_DEPRECATED_NO_WARNINGS #include #include +#include #include typedef SOCKET net_socket; typedef int socklen_t; +#ifndef LPFN_WSASENDMSG +typedef INT(PASCAL* LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, + LPDWORD lpNumberOfBytesSent, LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +#endif +#ifndef WSAID_WSASENDMSG +static const GUID WSAID_WSASENDMSG = { + 0xa441e712, 0x754f, 0x43ca, {0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d}}; +#endif +#ifndef LPFN_WSARECVMSG +typedef INT(PASCAL* LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg, LPDWORD lpdwNumberOfBytesRecvd, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +#endif + +#ifndef WSAID_WSARECVMSG +static const GUID WSAID_WSARECVMSG = { + 0xf689d7c8, 0x6f1f, 0x436b, {0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22}}; +#endif #else #include #include @@ -49,9 +69,11 @@ struct Socket { virtual int GetSocketOptions(int level, int optname, void* optval, u32* optlen) = 0; virtual int Bind(const OrbisNetSockaddr* addr, u32 addrlen) = 0; virtual int Listen(int backlog) = 0; + virtual int SendMessage(const OrbisNetMsghdr* msg, int flags) = 0; virtual int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) = 0; virtual SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) = 0; + virtual int ReceiveMessage(OrbisNetMsghdr* msg, int flags) = 0; virtual int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) = 0; virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0; @@ -86,8 +108,10 @@ struct PosixSocket : public Socket { int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override; int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override; int Listen(int backlog) override; + int SendMessage(const OrbisNetMsghdr* msg, int flags) override; int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) override; + int ReceiveMessage(OrbisNetMsghdr* msg, int flags) override; int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override; SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; @@ -109,8 +133,10 @@ struct P2PSocket : public Socket { int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override; int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override; int Listen(int backlog) override; + int SendMessage(const OrbisNetMsghdr* msg, int flags) override; int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) override; + int ReceiveMessage(OrbisNetMsghdr* msg, int flags) override; int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override; SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; diff --git a/src/core/libraries/network/sys_net.cpp b/src/core/libraries/network/sys_net.cpp index 0fd1bc4c2..c49e07093 100644 --- a/src/core/libraries/network/sys_net.cpp +++ b/src/core/libraries/network/sys_net.cpp @@ -225,7 +225,18 @@ int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags, } int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); + auto file = FDTable::Instance()->GetSocket(s); + if (!file) { + *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + LOG_DEBUG(Lib_Net, "s = {} ({}), flags = {:#x}", s, file->m_guest_name, flags); + int returncode = file->socket->SendMessage(msg, flags); + if (returncode >= 0) { + return returncode; + } + LOG_ERROR(Lib_Net, "error code returned: {}", (u32)*Libraries::Kernel::__Error()); return -1; } @@ -246,7 +257,19 @@ s64 PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, Orbis } s64 PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); + auto file = FDTable::Instance()->GetSocket(s); + if (!file) { + *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + LOG_DEBUG(Lib_Net, "s = {} ({}), flags = {:#x}", s, file->m_guest_name, flags); + int returncode = file->socket->ReceiveMessage(msg, flags); + if (returncode >= 0) { + return returncode; + } + LOG_ERROR(Lib_Net, "s = {} ({}) returned error code: {}", s, file->m_guest_name, + (u32)*Libraries::Kernel::__Error()); return -1; }