mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-08 20:58:41 +00:00
AF_UNIX preliminary support (#3506)
* AF_UNIX preliminary support * fixed windows * added windows implemenation for socketpair * More gotos * added sys_socketpair for libkernel_ps2emu --------- Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
committed by
GitHub
parent
17568353a9
commit
90f6bf0516
@@ -390,6 +390,7 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
|
||||
src/core/libraries/network/sys_net.h
|
||||
src/core/libraries/network/posix_sockets.cpp
|
||||
src/core/libraries/network/p2p_sockets.cpp
|
||||
src/core/libraries/network/unix_sockets.cpp
|
||||
src/core/libraries/network/sockets.h
|
||||
)
|
||||
|
||||
|
||||
@@ -277,16 +277,26 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_connect);
|
||||
LIB_FUNCTION("pG70GT5yRo4", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketex);
|
||||
LIB_FUNCTION("KuOmgKoqCdY", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
|
||||
LIB_FUNCTION("6O8EwYOgH9Y", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_getsockopt);
|
||||
LIB_FUNCTION("fFxGkxF2bVo", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_setsockopt);
|
||||
LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen);
|
||||
LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept);
|
||||
LIB_FUNCTION("TUuiYS2kE8s", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_shutdown);
|
||||
LIB_FUNCTION("TU-d9PfIHPM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socket);
|
||||
LIB_FUNCTION("MZb0GKT3mo8", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketpair);
|
||||
LIB_FUNCTION("MZb0GKT3mo8", "libkernel_ps2emu", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sys_socketpair);
|
||||
LIB_FUNCTION("K1S8oc61xiM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_htonl);
|
||||
LIB_FUNCTION("jogUIsOV3-U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_htons);
|
||||
LIB_FUNCTION("fZOeZIOEmLw", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_send);
|
||||
LIB_FUNCTION("oBr313PppNE", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto);
|
||||
LIB_FUNCTION("Ez8xjo9UF4E", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_recv);
|
||||
LIB_FUNCTION("lUk6wrGXyMw", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom);
|
||||
|
||||
LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket);
|
||||
LIB_FUNCTION("fZOeZIOEmLw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_send);
|
||||
LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto);
|
||||
LIB_FUNCTION("Ez8xjo9UF4E", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recv);
|
||||
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,
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Libraries::Net {
|
||||
static int ConvertFamilies(int family);
|
||||
|
||||
enum OrbisNetFamily : u32 {
|
||||
ORBIS_NET_AF_UNIX = 1,
|
||||
ORBIS_NET_AF_INET = 2,
|
||||
ORBIS_NET_AF_INET6 = 28,
|
||||
};
|
||||
@@ -126,6 +127,12 @@ struct OrbisNetInAddr {
|
||||
OrbisNetInAddr_t inaddr_addr;
|
||||
};
|
||||
|
||||
struct OrbisNetSockaddrUn {
|
||||
u8 sun_len;
|
||||
u8 sun_family; // AF_UNIX
|
||||
char sun_path[104];
|
||||
};
|
||||
|
||||
struct OrbisNetIovec {
|
||||
void* iov_base;
|
||||
u64 iov_len;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifdef _WIN32
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#include <Ws2tcpip.h>
|
||||
#include <afunix.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <mstcpip.h>
|
||||
#include <winsock2.h>
|
||||
@@ -148,4 +149,33 @@ struct P2PSocket : public Socket {
|
||||
}
|
||||
};
|
||||
|
||||
struct UnixSocket : public Socket {
|
||||
net_socket sock;
|
||||
int socket_type;
|
||||
explicit UnixSocket(int domain, int type, int protocol)
|
||||
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {
|
||||
socket_type = type;
|
||||
}
|
||||
explicit UnixSocket(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;
|
||||
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;
|
||||
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
|
||||
int GetPeerName(OrbisNetSockaddr* addr, u32* namelen) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* stat) override;
|
||||
std::optional<net_socket> Native() override {
|
||||
return sock;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Libraries::Net
|
||||
@@ -160,6 +160,11 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc
|
||||
switch (type) {
|
||||
case ORBIS_NET_SOCK_STREAM:
|
||||
case ORBIS_NET_SOCK_DGRAM:
|
||||
if (family == ORBIS_NET_AF_UNIX) {
|
||||
socket = std::make_shared<UnixSocket>(family, type, protocol);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case ORBIS_NET_SOCK_RAW:
|
||||
socket = std::make_shared<PosixSocket>(family, type, protocol);
|
||||
break;
|
||||
@@ -188,6 +193,99 @@ int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) {
|
||||
return sys_socketex(nullptr, family, type, protocol);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int socketpair(int family, int type, int protocol, net_socket fd[2]) {
|
||||
if (family != AF_UNIX && family != AF_INET) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
if (type != SOCK_STREAM) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SOCKET listener = INVALID_SOCKET;
|
||||
SOCKET sock1 = INVALID_SOCKET;
|
||||
SOCKET sock2 = INVALID_SOCKET;
|
||||
sockaddr_in addr{};
|
||||
int addrlen = sizeof(addr);
|
||||
|
||||
listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listener == INVALID_SOCKET)
|
||||
goto fail1;
|
||||
|
||||
ZeroMemory(&addr, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
addr.sin_port = 0;
|
||||
|
||||
if (bind(listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
|
||||
goto fail1;
|
||||
if (listen(listener, 1) == SOCKET_ERROR)
|
||||
goto fail1;
|
||||
|
||||
if (getsockname(listener, (sockaddr*)&addr, &addrlen) == SOCKET_ERROR)
|
||||
goto fail1;
|
||||
|
||||
sock1 = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock1 == INVALID_SOCKET)
|
||||
goto fail2;
|
||||
|
||||
if (connect(sock1, (sockaddr*)&addr, addrlen) == SOCKET_ERROR)
|
||||
goto fail2;
|
||||
|
||||
sock2 = accept(listener, nullptr, nullptr);
|
||||
if (sock2 == INVALID_SOCKET)
|
||||
goto fail3;
|
||||
|
||||
closesocket(listener);
|
||||
fd[0] = sock1;
|
||||
fd[1] = sock2;
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
closesocket(sock2);
|
||||
fail2:
|
||||
closesocket(sock1);
|
||||
fail1:
|
||||
closesocket(listener);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int PS4_SYSV_ABI sys_socketpair(int family, int type, int protocol, int sv[2]) {
|
||||
if (sv == nullptr) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (family != ORBIS_NET_AF_UNIX) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_socket fd[2];
|
||||
if (socketpair(family, type, protocol, fd) != 0) {
|
||||
LOG_ERROR(Lib_Net, "socketpair failed with {}", Common::GetLastErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fd1 = FDTable::Instance()->CreateHandle();
|
||||
auto fd2 = FDTable::Instance()->CreateHandle();
|
||||
auto* sock = FDTable::Instance()->GetFile(fd1);
|
||||
sock->is_opened = true;
|
||||
sock->type = Core::FileSys::FileType::Socket;
|
||||
sock->socket = std::make_shared<UnixSocket>(fd[0]);
|
||||
sock->m_guest_name = "anon_sock0";
|
||||
sock = FDTable::Instance()->GetFile(fd2);
|
||||
sock->is_opened = true;
|
||||
sock->type = Core::FileSys::FileType::Socket;
|
||||
sock->socket = std::make_shared<UnixSocket>(fd[1]);
|
||||
sock->m_guest_name = "anon_sock1";
|
||||
sv[0] = fd1;
|
||||
sv[1] = fd2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
@@ -208,6 +306,10 @@ int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sys_send(OrbisNetId s, const void* buf, u64 len, int flags) {
|
||||
return sys_sendto(s, buf, len, flags, nullptr, 0);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
|
||||
const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
auto file = FDTable::Instance()->GetSocket(s);
|
||||
@@ -240,6 +342,10 @@ int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags)
|
||||
return -1;
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI sys_recv(OrbisNetId s, void* buf, u64 len, int flags) {
|
||||
return sys_recvfrom(s, buf, len, flags, nullptr, nullptr);
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
|
||||
u32* paddrlen) {
|
||||
auto file = FDTable::Instance()->GetSocket(s);
|
||||
|
||||
@@ -20,11 +20,14 @@ int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void
|
||||
int PS4_SYSV_ABI sys_shutdown(OrbisNetId s, int how);
|
||||
int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protocol);
|
||||
int PS4_SYSV_ABI sys_socket(int family, int type, int protocol);
|
||||
int PS4_SYSV_ABI sys_socketpair(int family, int type, int protocol, int sv[2]);
|
||||
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags);
|
||||
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s);
|
||||
int PS4_SYSV_ABI sys_send(OrbisNetId s, const void* buf, u64 len, int flags);
|
||||
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);
|
||||
s64 PS4_SYSV_ABI sys_recv(OrbisNetId s, void* buf, u64 len, int flags);
|
||||
s64 PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
|
||||
u32* paddrlen);
|
||||
s64 PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
|
||||
|
||||
393
src/core/libraries/network/unix_sockets.cpp
Normal file
393
src/core/libraries/network/unix_sockets.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/assert.h>
|
||||
#include "common/error.h"
|
||||
#include "core/libraries/kernel/file_system.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "net.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include "net_error.h"
|
||||
#include "sockets.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ERROR_CASE(errname) \
|
||||
case (WSA##errname): \
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_##errname; \
|
||||
return -1;
|
||||
#else
|
||||
#define ERROR_CASE(errname) \
|
||||
case (errname): \
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_##errname; \
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
static int ConvertReturnErrorCode(int retval) {
|
||||
if (retval < 0) {
|
||||
#ifdef _WIN32
|
||||
switch (WSAGetLastError()) {
|
||||
#else
|
||||
switch (errno) {
|
||||
#endif
|
||||
#ifndef _WIN32 // These errorcodes don't exist in WinSock
|
||||
ERROR_CASE(EPERM)
|
||||
ERROR_CASE(ENOENT)
|
||||
// ERROR_CASE(ESRCH)
|
||||
// ERROR_CASE(EIO)
|
||||
// ERROR_CASE(ENXIO)
|
||||
// ERROR_CASE(E2BIG)
|
||||
// ERROR_CASE(ENOEXEC)
|
||||
// ERROR_CASE(EDEADLK)
|
||||
ERROR_CASE(ENOMEM)
|
||||
// ERROR_CASE(ECHILD)
|
||||
// ERROR_CASE(EBUSY)
|
||||
ERROR_CASE(EEXIST)
|
||||
// ERROR_CASE(EXDEV)
|
||||
ERROR_CASE(ENODEV)
|
||||
// ERROR_CASE(ENOTDIR)
|
||||
// ERROR_CASE(EISDIR)
|
||||
ERROR_CASE(ENFILE)
|
||||
// ERROR_CASE(ENOTTY)
|
||||
// ERROR_CASE(ETXTBSY)
|
||||
// ERROR_CASE(EFBIG)
|
||||
ERROR_CASE(ENOSPC)
|
||||
// ERROR_CASE(ESPIPE)
|
||||
// ERROR_CASE(EROFS)
|
||||
// ERROR_CASE(EMLINK)
|
||||
ERROR_CASE(EPIPE)
|
||||
// ERROR_CASE(EDOM)
|
||||
// ERROR_CASE(ERANGE)
|
||||
// ERROR_CASE(ENOLCK)
|
||||
// ERROR_CASE(ENOSYS)
|
||||
// ERROR_CASE(EIDRM)
|
||||
// ERROR_CASE(EOVERFLOW)
|
||||
// ERROR_CASE(EILSEQ)
|
||||
// ERROR_CASE(ENOTSUP)
|
||||
ERROR_CASE(ECANCELED)
|
||||
// ERROR_CASE(EBADMSG)
|
||||
ERROR_CASE(ENODATA)
|
||||
// ERROR_CASE(ENOSR)
|
||||
// ERROR_CASE(ENOSTR)
|
||||
// ERROR_CASE(ETIME)
|
||||
#endif
|
||||
ERROR_CASE(EINTR)
|
||||
ERROR_CASE(EBADF)
|
||||
ERROR_CASE(EACCES)
|
||||
ERROR_CASE(EFAULT)
|
||||
ERROR_CASE(EINVAL)
|
||||
ERROR_CASE(EMFILE)
|
||||
ERROR_CASE(EWOULDBLOCK)
|
||||
ERROR_CASE(EINPROGRESS)
|
||||
ERROR_CASE(EALREADY)
|
||||
ERROR_CASE(ENOTSOCK)
|
||||
ERROR_CASE(EDESTADDRREQ)
|
||||
ERROR_CASE(EMSGSIZE)
|
||||
ERROR_CASE(EPROTOTYPE)
|
||||
ERROR_CASE(ENOPROTOOPT)
|
||||
ERROR_CASE(EPROTONOSUPPORT)
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ERROR_CASE(EOPNOTSUPP)
|
||||
#endif
|
||||
ERROR_CASE(EAFNOSUPPORT)
|
||||
ERROR_CASE(EADDRINUSE)
|
||||
ERROR_CASE(EADDRNOTAVAIL)
|
||||
ERROR_CASE(ENETDOWN)
|
||||
ERROR_CASE(ENETUNREACH)
|
||||
ERROR_CASE(ENETRESET)
|
||||
ERROR_CASE(ECONNABORTED)
|
||||
ERROR_CASE(ECONNRESET)
|
||||
ERROR_CASE(ENOBUFS)
|
||||
ERROR_CASE(EISCONN)
|
||||
ERROR_CASE(ENOTCONN)
|
||||
ERROR_CASE(ETIMEDOUT)
|
||||
ERROR_CASE(ECONNREFUSED)
|
||||
ERROR_CASE(ELOOP)
|
||||
ERROR_CASE(ENAMETOOLONG)
|
||||
ERROR_CASE(EHOSTUNREACH)
|
||||
ERROR_CASE(ENOTEMPTY)
|
||||
}
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EINTERNAL;
|
||||
return -1;
|
||||
}
|
||||
// if it is 0 or positive return it as it is
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ConvertLevels(int level) {
|
||||
switch (level) {
|
||||
case ORBIS_NET_SOL_SOCKET:
|
||||
return SOL_SOCKET;
|
||||
case ORBIS_NET_IPPROTO_IP:
|
||||
return IPPROTO_IP;
|
||||
case ORBIS_NET_IPPROTO_TCP:
|
||||
return IPPROTO_TCP;
|
||||
case ORBIS_NET_IPPROTO_IPV6:
|
||||
return IPPROTO_IPV6;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void convertOrbisNetSockaddrToUnix(const OrbisNetSockaddr* src, sockaddr_un* dst) {
|
||||
if (src == nullptr || dst == nullptr)
|
||||
return;
|
||||
memset(dst, 0, sizeof(sockaddr_un));
|
||||
const OrbisNetSockaddrUn* src_in = (const OrbisNetSockaddrUn*)src;
|
||||
sockaddr_un* dst_in = (sockaddr_un*)dst;
|
||||
dst_in->sun_family = src_in->sun_family;
|
||||
memcpy(&dst_in->sun_path, &src_in->sun_path, src_in->sun_len);
|
||||
}
|
||||
|
||||
static void convertUnixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) {
|
||||
if (src == nullptr || dst == nullptr)
|
||||
return;
|
||||
memset(dst, 0, sizeof(OrbisNetSockaddrUn));
|
||||
OrbisNetSockaddrUn* dst_in = (OrbisNetSockaddrUn*)dst;
|
||||
sockaddr_un* src_in = (sockaddr_un*)src;
|
||||
dst_in->sun_len = strnlen(src_in->sun_path, 108);
|
||||
dst_in->sun_family = src_in->sun_family;
|
||||
memcpy(&dst_in->sun_path, &src_in->sun_path, dst_in->sun_len);
|
||||
}
|
||||
|
||||
bool UnixSocket::IsValid() const {
|
||||
#ifdef _WIN32
|
||||
return sock != INVALID_SOCKET;
|
||||
#else
|
||||
return sock != -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int UnixSocket::Close() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
#ifdef _WIN32
|
||||
auto out = closesocket(sock);
|
||||
#else
|
||||
auto out = ::close(sock);
|
||||
#endif
|
||||
return ConvertReturnErrorCode(out);
|
||||
}
|
||||
|
||||
int UnixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr_un addr2;
|
||||
convertOrbisNetSockaddrToUnix(addr, &addr2);
|
||||
return ConvertReturnErrorCode(::bind(sock, (const sockaddr*)&addr2, sizeof(sockaddr_un)));
|
||||
}
|
||||
|
||||
int UnixSocket::Listen(int backlog) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return ConvertReturnErrorCode(::listen(sock, backlog));
|
||||
}
|
||||
|
||||
int UnixSocket::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<LPWSAMSG>(const_cast<OrbisNetMsghdr*>(msg)), flags,
|
||||
&bytesSent, nullptr, nullptr);
|
||||
|
||||
if (res == SOCKET_ERROR) {
|
||||
return ConvertReturnErrorCode(-1);
|
||||
}
|
||||
return static_cast<int>(bytesSent);
|
||||
#else
|
||||
int res = sendmsg(sock, reinterpret_cast<const msghdr*>(msg), flags);
|
||||
return ConvertReturnErrorCode(res);
|
||||
#endif
|
||||
}
|
||||
|
||||
int UnixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
LOG_ERROR(Lib_Net, "called");
|
||||
if (to != nullptr) {
|
||||
sockaddr_un addr;
|
||||
convertOrbisNetSockaddrToUnix(to, &addr);
|
||||
return ConvertReturnErrorCode(
|
||||
sendto(sock, (const char*)msg, len, flags, (sockaddr*)&addr, sizeof(sockaddr_un)));
|
||||
} else {
|
||||
return ConvertReturnErrorCode(send(sock, (const char*)msg, len, flags));
|
||||
}
|
||||
}
|
||||
|
||||
int UnixSocket::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<LPWSAMSG>(msg), &bytesReceived, nullptr, nullptr);
|
||||
|
||||
if (res == SOCKET_ERROR) {
|
||||
return ConvertReturnErrorCode(-1);
|
||||
}
|
||||
return static_cast<int>(bytesReceived);
|
||||
#else
|
||||
int res = recvmsg(sock, reinterpret_cast<msghdr*>(msg), flags);
|
||||
return ConvertReturnErrorCode(res);
|
||||
#endif
|
||||
}
|
||||
|
||||
int UnixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) {
|
||||
std::scoped_lock lock{receive_mutex};
|
||||
LOG_ERROR(Lib_Net, "called");
|
||||
if (from != nullptr) {
|
||||
sockaddr_un addr;
|
||||
int res = recvfrom(sock, (char*)buf, len, flags, (sockaddr*)&addr, (socklen_t*)fromlen);
|
||||
convertUnixSockaddrToOrbis((sockaddr*)&addr, from);
|
||||
*fromlen = sizeof(OrbisNetSockaddrUn);
|
||||
return ConvertReturnErrorCode(res);
|
||||
} else {
|
||||
return ConvertReturnErrorCode(recv(sock, (char*)buf, len, flags));
|
||||
}
|
||||
}
|
||||
|
||||
SocketPtr UnixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr_un addr2;
|
||||
socklen_t len = sizeof(addr2);
|
||||
net_socket new_socket = ::accept(sock, (sockaddr*)&addr2, &len);
|
||||
#ifdef _WIN32
|
||||
if (new_socket != INVALID_SOCKET) {
|
||||
#else
|
||||
if (new_socket >= 0) {
|
||||
#endif
|
||||
if (addr && addrlen) {
|
||||
convertUnixSockaddrToOrbis((sockaddr*)&addr2, addr);
|
||||
*addrlen = sizeof(OrbisNetSockaddrUn);
|
||||
}
|
||||
return std::make_shared<UnixSocket>(new_socket);
|
||||
}
|
||||
ConvertReturnErrorCode(new_socket);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int UnixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr_un addr2;
|
||||
convertOrbisNetSockaddrToUnix(addr, &addr2);
|
||||
int result = 0;
|
||||
do {
|
||||
result = ::connect(sock, (sockaddr*)&addr2, sizeof(sockaddr_un));
|
||||
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 UnixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
sockaddr_un addr;
|
||||
convertOrbisNetSockaddrToUnix(name, &addr);
|
||||
if (name != nullptr) {
|
||||
*namelen = sizeof(sockaddr_un);
|
||||
}
|
||||
int res = getsockname(sock, (sockaddr*)&addr, (socklen_t*)namelen);
|
||||
if (res >= 0) {
|
||||
convertUnixSockaddrToOrbis((sockaddr*)&addr, name);
|
||||
*namelen = sizeof(OrbisNetSockaddrUn);
|
||||
}
|
||||
return ConvertReturnErrorCode(res);
|
||||
}
|
||||
|
||||
#define CASE_SETSOCKOPT(opt) \
|
||||
case ORBIS_NET_##opt: \
|
||||
return ConvertReturnErrorCode( \
|
||||
setsockopt(sock, native_level, opt, (const char*)optval, optlen))
|
||||
|
||||
#define CASE_SETSOCKOPT_VALUE(opt, value) \
|
||||
case opt: \
|
||||
if (optlen != sizeof(*value)) { \
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EFAULT; \
|
||||
return -1; \
|
||||
} \
|
||||
memcpy(value, optval, optlen); \
|
||||
return 0
|
||||
|
||||
int UnixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
LOG_ERROR(Lib_Net, "Unknown level = {} optname = {}", level, optname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define CASE_GETSOCKOPT(opt) \
|
||||
case ORBIS_NET_##opt: { \
|
||||
socklen_t optlen_temp = *optlen; \
|
||||
auto retval = ConvertReturnErrorCode( \
|
||||
getsockopt(sock, native_level, opt, (char*)optval, &optlen_temp)); \
|
||||
*optlen = optlen_temp; \
|
||||
return retval; \
|
||||
}
|
||||
#define CASE_GETSOCKOPT_VALUE(opt, value) \
|
||||
case opt: \
|
||||
if (*optlen < sizeof(value)) { \
|
||||
*optlen = sizeof(value); \
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EFAULT; \
|
||||
return -1; \
|
||||
} \
|
||||
*optlen = sizeof(value); \
|
||||
*(decltype(value)*)optval = value; \
|
||||
return 0;
|
||||
|
||||
int UnixSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
LOG_ERROR(Lib_Net, "Unknown level = {} optname = {}", level, optname);
|
||||
return ConvertReturnErrorCode(-1);
|
||||
}
|
||||
|
||||
int UnixSocket::GetPeerName(OrbisNetSockaddr* name, u32* namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
LOG_DEBUG(Lib_Net, "called");
|
||||
|
||||
sockaddr_un addr;
|
||||
convertOrbisNetSockaddrToUnix(name, &addr);
|
||||
if (name != nullptr) {
|
||||
*namelen = sizeof(sockaddr_un);
|
||||
}
|
||||
int res = ::getpeername(sock, (sockaddr*)&addr, (socklen_t*)namelen);
|
||||
if (res >= 0) {
|
||||
convertUnixSockaddrToOrbis((sockaddr*)&addr, name);
|
||||
*namelen = sizeof(OrbisNetSockaddrUn);
|
||||
}
|
||||
return ConvertReturnErrorCode(res);
|
||||
}
|
||||
|
||||
int UnixSocket::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 ConvertReturnErrorCode(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
||||
Reference in New Issue
Block a user