Sockets are now files (#3319)

* Socket support for read/write/fstat

* Sockets are now files

* Fix ssize_t for windows

* Return posix error codes in net functions
This commit is contained in:
Marcin Mikołajczyk 2025-07-28 23:20:10 +02:00 committed by GitHub
parent 93767ae31b
commit 26a92d97fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 182 additions and 92 deletions

View File

@ -219,6 +219,18 @@ File* HandleTable::GetFile(int d) {
return m_files.at(d);
}
File* HandleTable::GetSocket(int d) {
std::scoped_lock lock{m_mutex};
if (d < 0 || d >= m_files.size()) {
return nullptr;
}
auto file = m_files.at(d);
if (file->type != Core::FileSys::FileType::Socket) {
return nullptr;
}
return file;
}
File* HandleTable::GetFile(const std::filesystem::path& host_name) {
for (auto* file : m_files) {
if (file != nullptr && file->m_host_name == host_name) {

View File

@ -12,6 +12,10 @@
#include "common/logging/formatter.h"
#include "core/devices/base_device.h"
namespace Libraries::Net {
struct Socket;
}
namespace Core::FileSys {
class MntPoints {
@ -77,6 +81,7 @@ enum class FileType {
Regular, // standard file
Directory,
Device,
Socket,
};
struct File {
@ -88,7 +93,8 @@ struct File {
std::vector<DirEntry> dirents;
u32 dirents_index;
std::mutex m_mutex;
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
};
class HandleTable {
@ -99,6 +105,7 @@ public:
int CreateHandle();
void DeleteHandle(int d);
File* GetFile(int d);
File* GetSocket(int d);
File* GetFile(const std::filesystem::path& host_name);
int GetFileDescriptor(File* file);

View File

@ -20,6 +20,7 @@
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/kernel/posix_error.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/sockets.h"
#include "core/memory.h"
#include "kernel.h"
@ -257,6 +258,8 @@ s32 PS4_SYSV_ABI close(s32 fd) {
}
if (file->type == Core::FileSys::FileType::Regular) {
file->f.Close();
} else if (file->type == Core::FileSys::FileType::Socket) {
file->socket->Close();
}
file->is_opened = false;
LOG_INFO(Kernel_Fs, "Closing {}", file->m_guest_name);
@ -294,6 +297,13 @@ s64 PS4_SYSV_ABI write(s32 fd, const void* buf, size_t nbytes) {
return -1;
}
return result;
} else if (file->type == Core::FileSys::FileType::Socket) {
s64 result = file->socket->SendPacket(buf, nbytes, 0, nullptr, 0);
if (result < 0) {
ErrSceToPosix(result);
return -1;
}
return result;
}
return file->f.WriteRaw<u8>(buf, nbytes);
@ -475,6 +485,13 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) {
return -1;
}
return result;
} else if (file->type == Core::FileSys::FileType::Socket) {
s64 result = file->socket->ReceivePacket(buf, nbytes, 0, nullptr, 0);
if (result < 0) {
ErrSceToPosix(result);
return -1;
}
return result;
}
return ReadFile(file->f, buf, nbytes);
}
@ -667,6 +684,14 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) {
// TODO incomplete
break;
}
case Core::FileSys::FileType::Socket: {
s32 result = file->socket->fstat(sb);
if (result < 0) {
ErrSceToPosix(result);
return -1;
}
return result;
}
default:
UNREACHABLE();
}

View File

@ -222,14 +222,15 @@ s32 PS4_SYSV_ABI posix_getpagesize() {
s32 PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<Libraries::Net::NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
LOG_INFO(Lib_Kernel, "s = {}", s);
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto file = h->GetSocket(s);
if (!file) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1;
}
s32 returncode = sock->GetSocketAddress(addr, paddrlen);
s32 returncode = file->socket->GetSocketAddress(addr, paddrlen);
if (returncode >= 0) {
LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode);
return 0;

View File

@ -20,6 +20,8 @@ class SymbolsResolver;
namespace Libraries::Net {
static int ConvertFamilies(int family);
enum OrbisNetFamily : u32 {
ORBIS_NET_AF_INET = 2,
ORBIS_NET_AF_INET6 = 28,

View File

@ -57,4 +57,9 @@ int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
return 0;
}
int P2PSocket::fstat(Libraries::Kernel::OrbisKernelStat* stat) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return 0;
}
} // namespace Libraries::Net

View File

@ -2,7 +2,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/assert.h>
#include "common/error.h"
#include "core/libraries/kernel/file_system.h"
#include "net.h"
#ifndef _WIN32
#include <sys/stat.h>
#endif
#include "net_error.h"
#include "sockets.h"
@ -142,6 +147,14 @@ static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) {
memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4);
}
bool PosixSocket::IsValid() const {
#ifdef _WIN32
return sock != INVALID_SOCKET;
#else
return sock != -1;
#endif
}
int PosixSocket::Close() {
std::scoped_lock lock{m_mutex};
#ifdef _WIN32
@ -194,14 +207,17 @@ int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr*
SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
std::scoped_lock lock{m_mutex};
sockaddr addr2;
net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen);
socklen_t len = sizeof(addr2);
net_socket new_socket = ::accept(sock, &addr2, &len);
#ifdef _WIN32
if (new_socket != INVALID_SOCKET) {
#else
if (new_socket >= 0) {
#endif
convertPosixSockaddrToOrbis(&addr2, addr);
*addrlen = sizeof(OrbisNetSockaddrIn);
if (addr && addrlen) {
convertPosixSockaddrToOrbis(&addr2, addr);
*addrlen = sizeof(OrbisNetSockaddrIn);
}
return std::make_shared<PosixSocket>(new_socket);
}
return nullptr;
@ -211,7 +227,13 @@ int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
std::scoped_lock lock{m_mutex};
sockaddr addr2;
convertOrbisNetSockaddrToPosix(addr, &addr2);
return ::connect(sock, &addr2, sizeof(sockaddr_in));
int result = 0;
do {
result = ::connect(sock, &addr2, sizeof(sockaddr_in));
LOG_DEBUG(Lib_Net, "raw connect result = {}, errno = {}", result,
result == -1 ? Common::GetLastErrorMsg() : "none");
} while (result == -1 && (errno == EINTR || errno == EINPROGRESS));
return ConvertReturnErrorCode(result);
}
int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
@ -394,4 +416,21 @@ int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* opt
return 0;
}
int PosixSocket::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
#ifdef _WIN32
LOG_ERROR(Lib_Net, "(STUBBED) called");
sb->st_mode = 0000777u | 0140000u;
return 0;
#else
struct stat st{};
int result = ::fstat(sock, &st);
sb->st_mode = 0000777u | 0140000u;
sb->st_size = st.st_size;
sb->st_blocks = st.st_blocks;
sb->st_blksize = st.st_blksize;
// sb->st_flags = st.st_flags;
return result;
#endif
}
} // namespace Libraries::Net

View File

@ -26,6 +26,10 @@ typedef int net_socket;
#include <mutex>
#include "net.h"
namespace Libraries::Kernel {
struct OrbisKernelStat;
}
namespace Libraries::Net {
struct Socket;
@ -39,6 +43,7 @@ struct OrbisNetLinger {
struct Socket {
explicit Socket(int domain, int type, int protocol) {}
virtual ~Socket() = default;
virtual bool IsValid() const = 0;
virtual int Close() = 0;
virtual int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) = 0;
virtual int GetSocketOptions(int level, int optname, void* optval, u32* optlen) = 0;
@ -51,6 +56,7 @@ struct Socket {
u32* fromlen) = 0;
virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0;
virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0;
virtual int fstat(Libraries::Kernel::OrbisKernelStat* stat) = 0;
std::mutex m_mutex;
};
@ -71,6 +77,7 @@ struct PosixSocket : public Socket {
socket_type = type;
}
explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {}
bool IsValid() const override;
int Close() override;
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override;
@ -82,10 +89,14 @@ struct PosixSocket : public Socket {
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
int fstat(Libraries::Kernel::OrbisKernelStat* stat) override;
};
struct P2PSocket : public Socket {
explicit P2PSocket(int domain, int type, int protocol) : Socket(domain, type, protocol) {}
bool IsValid() const override {
return true;
}
int Close() override;
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override;
@ -97,25 +108,7 @@ struct P2PSocket : public Socket {
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
int fstat(Libraries::Kernel::OrbisKernelStat* stat) override;
};
class NetInternal {
public:
explicit NetInternal() = default;
~NetInternal() = default;
SocketPtr FindSocket(int sockid) {
std::scoped_lock lock{m_mutex};
const auto it = socks.find(sockid);
if (it != socks.end()) {
return it->second;
}
return 0;
}
public:
std::mutex m_mutex;
typedef std::map<int, SocketPtr> NetSockets;
NetSockets socks;
int next_sock_id = 0;
};
} // namespace Libraries::Net

View File

@ -4,22 +4,25 @@
#include <common/assert.h>
#include <common/logging/log.h>
#include <core/libraries/kernel/kernel.h>
#include "common/error.h"
#include "common/singleton.h"
#include "core/file_sys/fs.h"
#include "net_error.h"
#include "sockets.h"
#include "sys_net.h"
namespace Libraries::Net {
using FDTable = Common::Singleton<Core::FileSys::HandleTable>;
int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->Connect(addr, addrlen);
int returncode = file->socket->Connect(addr, addrlen);
if (returncode >= 0) {
return returncode;
}
@ -28,14 +31,13 @@ int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 add
return -1;
}
int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->Bind(addr, addrlen);
int returncode = file->socket->Bind(addr, addrlen);
if (returncode >= 0) {
return returncode;
}
@ -44,36 +46,38 @@ int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrle
return -1;
}
int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
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;
}
auto new_sock = sock->Accept(addr, paddrlen);
auto new_sock = file->socket->Accept(addr, paddrlen);
if (!new_sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_EBADF;
LOG_ERROR(Lib_Net, "error creating new socket for accepting");
LOG_ERROR(Lib_Net, "error creating new socket for accepting: {}",
Common::GetLastErrorMsg());
return -1;
}
auto id = ++netcall->next_sock_id;
netcall->socks.emplace(id, new_sock);
return id;
auto fd = FDTable::Instance()->CreateHandle();
auto* new_file = FDTable::Instance()->GetFile(fd);
new_file->is_opened = true;
new_file->type = Core::FileSys::FileType::Socket;
new_file->socket = new_sock;
return fd;
}
int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->GetSocketAddress(addr, paddrlen);
int returncode = file->socket->GetSocketAddress(addr, paddrlen);
if (returncode >= 0) {
return returncode;
}
@ -82,14 +86,13 @@ int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* padd
return -1;
}
int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->GetSocketOptions(level, optname, optval, optlen);
int returncode = file->socket->GetSocketOptions(level, optname, optval, optlen);
if (returncode >= 0) {
return returncode;
}
@ -98,14 +101,13 @@ int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optv
return -1;
}
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->Listen(backlog);
int returncode = file->socket->Listen(backlog);
if (returncode >= 0) {
return returncode;
}
@ -115,14 +117,13 @@ int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) {
}
int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval,
u32 optlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->SetSocketOptions(level, optname, optval, optlen);
int returncode = file->socket->SetSocketOptions(level, optname, optval, optlen);
if (returncode >= 0) {
return returncode;
}
@ -141,24 +142,32 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc
LOG_INFO(Lib_Net, "name = {} family = {} type = {} protocol = {}", std::string(name),
family, type, protocol);
}
SocketPtr sock;
SocketPtr socket;
switch (type) {
case ORBIS_NET_SOCK_STREAM:
case ORBIS_NET_SOCK_DGRAM:
case ORBIS_NET_SOCK_RAW:
sock = std::make_shared<PosixSocket>(family, type, protocol);
socket = std::make_shared<PosixSocket>(family, type, protocol);
break;
case ORBIS_NET_SOCK_DGRAM_P2P:
case ORBIS_NET_SOCK_STREAM_P2P:
sock = std::make_shared<P2PSocket>(family, type, protocol);
socket = std::make_shared<P2PSocket>(family, type, protocol);
break;
default:
UNREACHABLE_MSG("Unknown type {}", type);
}
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto id = ++netcall->next_sock_id;
netcall->socks.emplace(id, sock);
return id;
if (!socket->IsValid()) {
*Libraries::Kernel::__Error() = ORBIS_NET_EPROTONOSUPPORT;
return -1;
}
auto fd = FDTable::Instance()->CreateHandle();
auto* sock = FDTable::Instance()->GetFile(fd);
sock->is_opened = true;
sock->type = Core::FileSys::FileType::Socket;
sock->socket = socket;
sock->m_guest_name = name ? name : "anon_sock";
return fd;
}
int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) {
return sys_socketex(nullptr, family, type, protocol);
@ -168,14 +177,13 @@ int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) {
return -1;
}
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->Close();
int returncode = file->socket->Close();
if (returncode >= 0) {
return returncode;
}
@ -185,14 +193,13 @@ int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
}
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->SendPacket(buf, len, flags, addr, addrlen);
int returncode = file->socket->SendPacket(buf, len, flags, addr, addrlen);
if (returncode >= 0) {
return returncode;
}
@ -204,16 +211,15 @@ int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags)
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
s64 PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
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;
}
int returncode = sock->ReceivePacket(buf, len, flags, addr, paddrlen);
int returncode = file->socket->ReceivePacket(buf, len, flags, addr, paddrlen);
if (returncode >= 0) {
return returncode;
}
@ -221,7 +227,7 @@ int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, Orbis
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
s64 PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}

View File

@ -25,7 +25,7 @@ int PS4_SYSV_ABI sys_socketclose(OrbisNetId s);
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
s64 PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
u32* paddrlen);
int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
s64 PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
} // namespace Libraries::Net