mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-09 11:11:29 -06:00
Feat: P2PEpoll Refinement
This commit is contained in:
parent
2616af1645
commit
e763e90c2a
@ -34,7 +34,7 @@ using FDTable = Common::Singleton<Core::FileSys::HandleTable>;
|
||||
|
||||
static thread_local int32_t net_errno = 0;
|
||||
|
||||
static bool g_isNetInitialized = false;
|
||||
static bool g_isNetInitialized = true; // TODO init it properly
|
||||
|
||||
static int ConvertFamilies(int family) {
|
||||
switch (family) {
|
||||
@ -617,8 +617,14 @@ int PS4_SYSV_ABI sceNetDuplicateIpStop() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetEpollAbort() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceNetEpollAbort(OrbisNetId epollid, u32 flags) {
|
||||
auto file = FDTable::Instance()->GetEpoll(epollid);
|
||||
if (!file) {
|
||||
*sceNetErrnoLoc() = ORBIS_NET_EBADF;
|
||||
return ORBIS_NET_ERROR_EBADF;
|
||||
}
|
||||
LOG_DEBUG(Lib_Net, "called, epollid = {} ({}), flags = {}", epollid, file->epoll->name, flags);
|
||||
file->epoll->Abort();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -664,11 +670,18 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or
|
||||
return ORBIS_NET_ERROR_EBADF;
|
||||
}
|
||||
|
||||
// P2P dgram sockets only support EPOLLIN (matches PS4 kernel behavior)
|
||||
auto epoll_events = event->events;
|
||||
if (file->socket->socket_type == ORBIS_NET_SOCK_DGRAM_P2P) {
|
||||
epoll_events &= ORBIS_NET_EPOLLIN;
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
epoll_event native_event = {.events = ConvertEpollEventsIn(event->events),
|
||||
epoll_event native_event = {.events = ConvertEpollEventsIn(epoll_events),
|
||||
.data = {.fd = id}};
|
||||
ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_ADD, *native_handle, &native_event) == 0);
|
||||
#endif
|
||||
// Emulator-level event tracking
|
||||
epoll->events.emplace_back(id, *event);
|
||||
break;
|
||||
}
|
||||
@ -713,11 +726,18 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or
|
||||
return ORBIS_NET_ERROR_EBADF;
|
||||
}
|
||||
|
||||
// P2P dgram sockets only support EPOLLIN (matches PS4 kernel behavior)
|
||||
auto epoll_events_mod = event->events;
|
||||
if (file->socket->socket_type == ORBIS_NET_SOCK_DGRAM_P2P) {
|
||||
epoll_events_mod &= ORBIS_NET_EPOLLIN;
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
epoll_event native_event = {.events = ConvertEpollEventsIn(event->events),
|
||||
epoll_event native_event = {.events = ConvertEpollEventsIn(epoll_events_mod),
|
||||
.data = {.fd = id}};
|
||||
ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_MOD, *native_handle, &native_event) == 0);
|
||||
#endif
|
||||
// Emulator-level event tracking
|
||||
*it = {id, *event};
|
||||
break;
|
||||
}
|
||||
@ -827,20 +847,29 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events,
|
||||
LOG_DEBUG(Lib_Net, "called, epollid = {} ({}), maxevents = {}, timeout = {}", epollid,
|
||||
epoll->name, maxevents, timeout);
|
||||
|
||||
int sockets_waited_on = (epoll->events.size() - epoll->async_resolutions.size()) > 0;
|
||||
if (epoll->aborted.load(std::memory_order_acquire)) {
|
||||
epoll->ClearAbort();
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ECANCELED;
|
||||
return ORBIS_NET_ERROR_ECANCELED;
|
||||
}
|
||||
|
||||
std::vector<epoll_event> native_events{static_cast<size_t>(maxevents)};
|
||||
// +1 for the abort fd which is also registered in the epoll instance
|
||||
std::vector<epoll_event> native_events{static_cast<size_t>(maxevents + 1)};
|
||||
int result = ORBIS_OK;
|
||||
if (sockets_waited_on) {
|
||||
#ifdef __linux__
|
||||
const timespec epoll_timeout{.tv_sec = timeout / 1000000,
|
||||
.tv_nsec = (timeout % 1000000) * 1000};
|
||||
result = epoll_pwait2(epoll->epoll_fd, native_events.data(), maxevents,
|
||||
timeout < 0 ? nullptr : &epoll_timeout, nullptr);
|
||||
const timespec epoll_timeout{.tv_sec = timeout / 1000000,
|
||||
.tv_nsec = (timeout % 1000000) * 1000};
|
||||
result = epoll_pwait2(epoll->epoll_fd, native_events.data(), maxevents + 1,
|
||||
timeout < 0 ? nullptr : &epoll_timeout, nullptr);
|
||||
#else
|
||||
result = epoll_wait(epoll->epoll_fd, native_events.data(), maxevents,
|
||||
timeout < 0 ? timeout : timeout / 1000);
|
||||
result = epoll_wait(epoll->epoll_fd, native_events.data(), maxevents + 1,
|
||||
timeout < 0 ? timeout : timeout / 1000);
|
||||
#endif
|
||||
|
||||
if (epoll->aborted.load(std::memory_order_acquire)) {
|
||||
epoll->ClearAbort();
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ECANCELED;
|
||||
return ORBIS_NET_ERROR_ECANCELED;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@ -863,9 +892,13 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events,
|
||||
} else if (result == 0) {
|
||||
LOG_TRACE(Lib_Net, "timed out");
|
||||
} else {
|
||||
for (; i < result; ++i) {
|
||||
const auto& current_event = native_events[i];
|
||||
LOG_DEBUG(Lib_Net, "native_event[{}] = ( .events = {}, .data = {:#x} )", i,
|
||||
for (int j = 0; j < result; ++j) {
|
||||
const auto& current_event = native_events[j];
|
||||
// Skip the abort fd event (registered with data.fd = -1)
|
||||
if (current_event.data.fd == -1) {
|
||||
continue;
|
||||
}
|
||||
LOG_DEBUG(Lib_Net, "native_event[{}] = ( .events = {}, .data = {:#x} )", j,
|
||||
current_event.events, current_event.data.u64);
|
||||
const auto it = std::ranges::find_if(
|
||||
epoll->events, [&](auto& el) { return el.first == current_event.data.fd; });
|
||||
@ -877,6 +910,7 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events,
|
||||
};
|
||||
LOG_DEBUG(Lib_Net, "event[{}] = ( .events = {:#x}, .ident = {}, .data = {:#x} )", i,
|
||||
events[i].events, events[i].ident, events[i].data.data_u64);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -367,7 +367,7 @@ int PS4_SYSV_ABI sceNetDumpDestroy();
|
||||
int PS4_SYSV_ABI sceNetDumpRead();
|
||||
int PS4_SYSV_ABI sceNetDuplicateIpStart();
|
||||
int PS4_SYSV_ABI sceNetDuplicateIpStop();
|
||||
int PS4_SYSV_ABI sceNetEpollAbort();
|
||||
int PS4_SYSV_ABI sceNetEpollAbort(OrbisNetId epollid, u32 flags);
|
||||
int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, OrbisNetId id,
|
||||
OrbisNetEpollEvent* event);
|
||||
int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags);
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <memory>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/types.h"
|
||||
#include "net_epoll.h"
|
||||
#ifdef __linux__
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
@ -43,17 +48,70 @@ u32 ConvertEpollEventsOut(u32 epoll_events) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
Epoll::Epoll(const char* name_) : name(name_ ? name_ : "anon"), epoll_fd(epoll_create1(0)) {
|
||||
#ifdef _WIN32
|
||||
ASSERT(epoll_fd != nullptr);
|
||||
#else
|
||||
ASSERT(epoll_fd != -1);
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
abort_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
ASSERT(abort_fd != -1);
|
||||
epoll_event ev = {.events = EPOLLIN, .data = {.fd = -1}};
|
||||
ASSERT(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, abort_fd, &ev) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Epoll::Abort() {
|
||||
aborted.store(true, std::memory_order_release);
|
||||
#ifdef __linux__
|
||||
if (abort_fd != -1) {
|
||||
uint64_t val = 1;
|
||||
::write(abort_fd, &val, sizeof(val));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Epoll::ClearAbort() {
|
||||
aborted.store(false, std::memory_order_release);
|
||||
#ifdef __linux__
|
||||
if (abort_fd != -1) {
|
||||
uint64_t val;
|
||||
::read(abort_fd, &val, sizeof(val));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Epoll::Destroy() noexcept {
|
||||
events.clear();
|
||||
#ifdef _WIN32
|
||||
epoll_close(epoll_fd);
|
||||
epoll_fd = nullptr;
|
||||
#else
|
||||
close(epoll_fd);
|
||||
epoll_fd = -1;
|
||||
#ifdef __linux__
|
||||
if (abort_fd != -1) {
|
||||
close(abort_fd);
|
||||
abort_fd = -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
name = "";
|
||||
destroyed = true;
|
||||
}
|
||||
|
||||
int EpollTable::CreateHandle(const char* name) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
if (auto it = std::ranges::find_if(epolls, [](const Epoll& e) { return e.Destroyed(); });
|
||||
if (auto it = std::ranges::find_if(epolls, [](const auto& e) { return e && e->Destroyed(); });
|
||||
it != epolls.end()) {
|
||||
*it = Epoll(name);
|
||||
*it = std::make_unique<Epoll>(name);
|
||||
const auto ret = std::distance(epolls.begin(), it);
|
||||
LOG_DEBUG(Lib_Net, "epollid = {}", ret);
|
||||
return ret;
|
||||
} else {
|
||||
epolls.emplace_back(name);
|
||||
epolls.push_back(std::make_unique<Epoll>(name));
|
||||
const auto ret = epolls.size() - 1;
|
||||
LOG_DEBUG(Lib_Net, "epollid = {}", ret);
|
||||
return ret;
|
||||
@ -66,11 +124,11 @@ void EpollTable::DeleteHandle(int d) {
|
||||
|
||||
Epoll* EpollTable::GetEpoll(int epollid) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (epollid >= epolls.size() || epolls[epollid].Destroyed()) {
|
||||
if (epollid >= epolls.size() || !epolls[epollid] || epolls[epollid]->Destroyed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &epolls[epollid];
|
||||
return epolls[epollid].get();
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
@ -15,7 +17,6 @@
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// ADD libepoll-shim if using freebsd!
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@ -33,34 +34,24 @@ struct Epoll {
|
||||
std::string name;
|
||||
epoll_handle epoll_fd;
|
||||
std::deque<u32> async_resolutions{};
|
||||
|
||||
explicit Epoll(const char* name_) : name(name_), epoll_fd(epoll_create1(0)) {
|
||||
#ifdef _WIN32
|
||||
ASSERT(epoll_fd != nullptr);
|
||||
#else
|
||||
ASSERT(epoll_fd != -1);
|
||||
std::atomic<bool> aborted{false};
|
||||
#ifdef __linux__
|
||||
int abort_fd = -1;
|
||||
#endif
|
||||
if (name_ == nullptr) {
|
||||
name = "anon";
|
||||
}
|
||||
}
|
||||
|
||||
explicit Epoll(const char* name_);
|
||||
|
||||
// Signal the epoll to abort any blocking wait
|
||||
void Abort();
|
||||
|
||||
// Drain the abort fd after waking up, reset aborted flag
|
||||
void ClearAbort();
|
||||
|
||||
bool Destroyed() const noexcept {
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
void Destroy() noexcept {
|
||||
events.clear();
|
||||
#ifdef _WIN32
|
||||
epoll_close(epoll_fd);
|
||||
epoll_fd = nullptr;
|
||||
#else
|
||||
close(epoll_fd);
|
||||
epoll_fd = -1;
|
||||
#endif
|
||||
name = "";
|
||||
destroyed = true;
|
||||
}
|
||||
void Destroy() noexcept;
|
||||
|
||||
private:
|
||||
bool destroyed{};
|
||||
@ -79,7 +70,7 @@ public:
|
||||
Epoll* GetEpoll(int d);
|
||||
|
||||
private:
|
||||
std::vector<Epoll> epolls;
|
||||
std::vector<std::unique_ptr<Epoll>> epolls;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
|
||||
@ -1,246 +1,66 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/assert.h>
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "net.h"
|
||||
#include "net_error.h"
|
||||
#include "sockets.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
P2PSocket::P2PSocket(int domain, int type, int protocol) : Socket(domain, type, protocol) {
|
||||
P2PSocket::P2PSocket(int domain, int type, int protocol)
|
||||
: PosixSocket(AF_INET, type == ORBIS_NET_SOCK_DGRAM_P2P ? SOCK_DGRAM : SOCK_STREAM,
|
||||
type == ORBIS_NET_SOCK_DGRAM_P2P ? IPPROTO_UDP : IPPROTO_TCP) {
|
||||
// Store the original PS4 socket type so GetSocketOptions(SO_TYPE) returns the P2P value
|
||||
socket_type = type;
|
||||
// Map P2P socket types to real OS socket types
|
||||
int os_type;
|
||||
int os_protocol;
|
||||
if (type == ORBIS_NET_SOCK_DGRAM_P2P) {
|
||||
os_type = SOCK_DGRAM;
|
||||
os_protocol = IPPROTO_UDP;
|
||||
} else {
|
||||
// ORBIS_NET_SOCK_STREAM_P2P
|
||||
os_type = SOCK_STREAM;
|
||||
os_protocol = IPPROTO_TCP;
|
||||
}
|
||||
sock = ::socket(AF_INET, os_type, os_protocol);
|
||||
LOG_INFO(Lib_Net, "P2P socket created: type={} (os_type={}), fd={}", type, os_type, sock);
|
||||
}
|
||||
|
||||
P2PSocket::~P2PSocket() {
|
||||
#ifdef _WIN32
|
||||
if (sock != INVALID_SOCKET) {
|
||||
closesocket(sock);
|
||||
}
|
||||
#else
|
||||
if (sock != -1) {
|
||||
::close(sock);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool P2PSocket::IsValid() const {
|
||||
#ifdef _WIN32
|
||||
return sock != INVALID_SOCKET;
|
||||
#else
|
||||
return sock != -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int P2PSocket::Close() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
#ifdef _WIN32
|
||||
auto out = closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
#else
|
||||
auto out = ::close(sock);
|
||||
sock = -1;
|
||||
#endif
|
||||
return ConvertReturnErrorCode(out);
|
||||
}
|
||||
|
||||
int P2PSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
int native_level = ConvertLevels(level);
|
||||
|
||||
// Handle PS4-specific options that have no OS equivalent
|
||||
if (native_level == SOL_SOCKET) {
|
||||
switch (optname) {
|
||||
case ORBIS_NET_SO_NBIO: {
|
||||
sockopt_so_nbio = *(int*)optval;
|
||||
int val = sockopt_so_nbio;
|
||||
#ifdef _WIN32
|
||||
u_long mode = val;
|
||||
return ConvertReturnErrorCode(ioctlsocket(sock, FIONBIO, &mode));
|
||||
#else
|
||||
return ConvertReturnErrorCode(ioctl(sock, FIONBIO, &val));
|
||||
#endif
|
||||
}
|
||||
case ORBIS_NET_SO_USECRYPTO:
|
||||
case ORBIS_NET_SO_USESIGNATURE:
|
||||
case ORBIS_NET_SO_REUSEPORT:
|
||||
LOG_DEBUG(Lib_Net, "P2P setsockopt: storing PS4-specific option {}", optname);
|
||||
return 0;
|
||||
case ORBIS_NET_SO_SNDTIMEO:
|
||||
case ORBIS_NET_SO_RCVTIMEO: {
|
||||
int us = *(int*)optval;
|
||||
#ifdef _WIN32
|
||||
DWORD timeout_ms = us / 1000;
|
||||
int native_opt = (optname == ORBIS_NET_SO_SNDTIMEO) ? SO_SNDTIMEO : SO_RCVTIMEO;
|
||||
return ConvertReturnErrorCode(
|
||||
::setsockopt(sock, SOL_SOCKET, native_opt, (char*)&timeout_ms, sizeof(timeout_ms)));
|
||||
#else
|
||||
timeval tv{.tv_sec = us / 1000000, .tv_usec = us % 1000000};
|
||||
int native_opt = (optname == ORBIS_NET_SO_SNDTIMEO) ? SO_SNDTIMEO : SO_RCVTIMEO;
|
||||
return ConvertReturnErrorCode(
|
||||
::setsockopt(sock, SOL_SOCKET, native_opt, &tv, sizeof(tv)));
|
||||
#endif
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (native_level < 0) {
|
||||
LOG_WARNING(Lib_Net, "P2P setsockopt: unknown level {}", level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ConvertReturnErrorCode(
|
||||
::setsockopt(sock, native_level, optname, (const char*)optval, optlen));
|
||||
LOG_INFO(Lib_Net, "P2P socket created: type={} (os_type={}), fd={}", type,
|
||||
type == ORBIS_NET_SOCK_DGRAM_P2P ? int(SOCK_DGRAM) : int(SOCK_STREAM), sock);
|
||||
}
|
||||
|
||||
int P2PSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
int native_level = ConvertLevels(level);
|
||||
|
||||
if (native_level == SOL_SOCKET) {
|
||||
switch (optname) {
|
||||
case ORBIS_NET_SO_NBIO:
|
||||
*(int*)optval = sockopt_so_nbio;
|
||||
*optlen = sizeof(int);
|
||||
return 0;
|
||||
case ORBIS_NET_SO_TYPE:
|
||||
*(int*)optval = socket_type;
|
||||
*optlen = sizeof(int);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (native_level < 0) {
|
||||
LOG_WARNING(Lib_Net, "P2P getsockopt: unknown level {}", level);
|
||||
// Intercept SO_TYPE to return the PS4 P2P socket type, not the native OS type
|
||||
if (ConvertLevels(level) == SOL_SOCKET && optname == ORBIS_NET_SO_TYPE) {
|
||||
*(int*)optval = socket_type;
|
||||
*optlen = sizeof(int);
|
||||
return 0;
|
||||
}
|
||||
|
||||
socklen_t native_optlen = *optlen;
|
||||
int ret = ::getsockopt(sock, native_level, optname, (char*)optval, &native_optlen);
|
||||
*optlen = native_optlen;
|
||||
return ConvertReturnErrorCode(ret);
|
||||
return PosixSocket::GetSocketOptions(level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int P2PSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
// TODO: vport multiplexing not implemented, on PS4, P2P sockets multiplex
|
||||
// virtual ports over a single UDP association. We extract the vport here for
|
||||
// future use but don't perform any demuxing.
|
||||
const auto* orbis_addr = reinterpret_cast<const OrbisNetSockaddrIn*>(addr);
|
||||
if (orbis_addr) {
|
||||
if (orbis_addr && orbis_addr->sin_family == ORBIS_NET_AF_INET) {
|
||||
vport = orbis_addr->sin_vport;
|
||||
if (vport != 0) {
|
||||
LOG_WARNING(Lib_Net, "P2P bind with vport={} — vport multiplexing is not implemented",
|
||||
vport);
|
||||
}
|
||||
LOG_INFO(Lib_Net, "P2P bind: port={}, vport={}", ntohs(orbis_addr->sin_port), vport);
|
||||
}
|
||||
sockaddr native_addr;
|
||||
convertOrbisNetSockaddrToPosix(addr, &native_addr);
|
||||
return ConvertReturnErrorCode(::bind(sock, &native_addr, sizeof(sockaddr_in)));
|
||||
return PosixSocket::Bind(addr, addrlen);
|
||||
}
|
||||
|
||||
int P2PSocket::Listen(int backlog) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return ConvertReturnErrorCode(::listen(sock, backlog));
|
||||
}
|
||||
|
||||
int P2PSocket::SendMessage(const OrbisNetMsghdr* msg, int flags) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
int native_flags = convertOrbisFlagsToPosix(socket_type, flags);
|
||||
#ifdef _WIN32
|
||||
// Windows: loop through buffers with send()
|
||||
int total_sent = 0;
|
||||
for (int i = 0; i < msg->msg_iovlen; i++) {
|
||||
auto& iov = msg->msg_iov[i];
|
||||
int sent = ::send(sock, (const char*)iov.iov_base, iov.iov_len, native_flags);
|
||||
if (sent < 0) {
|
||||
return total_sent > 0 ? total_sent : ConvertReturnErrorCode(sent);
|
||||
int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
// TODO: vport multiplexing not implemented
|
||||
const auto* orbis_addr = reinterpret_cast<const OrbisNetSockaddrIn*>(addr);
|
||||
if (orbis_addr && orbis_addr->sin_family == ORBIS_NET_AF_INET) {
|
||||
vport = orbis_addr->sin_vport;
|
||||
if (vport != 0) {
|
||||
LOG_WARNING(Lib_Net,
|
||||
"P2P connect with vport={} — vport multiplexing is not implemented", vport);
|
||||
}
|
||||
total_sent += sent;
|
||||
LOG_INFO(Lib_Net, "P2P connect: vport={}", vport);
|
||||
}
|
||||
return total_sent;
|
||||
#else
|
||||
return ConvertReturnErrorCode(
|
||||
::sendmsg(sock, reinterpret_cast<const msghdr*>(msg), native_flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
int native_flags = convertOrbisFlagsToPosix(socket_type, flags);
|
||||
if (to == nullptr) {
|
||||
return ConvertReturnErrorCode(::send(sock, (const char*)msg, len, native_flags));
|
||||
}
|
||||
sockaddr native_addr;
|
||||
convertOrbisNetSockaddrToPosix(to, &native_addr);
|
||||
return ConvertReturnErrorCode(
|
||||
::sendto(sock, (const char*)msg, len, native_flags, &native_addr, sizeof(sockaddr_in)));
|
||||
}
|
||||
|
||||
int P2PSocket::ReceiveMessage(OrbisNetMsghdr* msg, int flags) {
|
||||
std::scoped_lock lock{receive_mutex};
|
||||
int native_flags = convertOrbisFlagsToPosix(socket_type, flags);
|
||||
#ifdef _WIN32
|
||||
// Windows: loop through buffers with recv()
|
||||
int total_recv = 0;
|
||||
for (int i = 0; i < msg->msg_iovlen; i++) {
|
||||
auto& iov = msg->msg_iov[i];
|
||||
int recvd = ::recv(sock, (char*)iov.iov_base, iov.iov_len, native_flags);
|
||||
if (recvd < 0) {
|
||||
return total_recv > 0 ? total_recv : ConvertReturnErrorCode(recvd);
|
||||
}
|
||||
total_recv += recvd;
|
||||
if (recvd < (int)iov.iov_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_recv;
|
||||
#else
|
||||
return ConvertReturnErrorCode(::recvmsg(sock, reinterpret_cast<msghdr*>(msg), native_flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
int P2PSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) {
|
||||
std::scoped_lock lock{receive_mutex};
|
||||
int native_flags = convertOrbisFlagsToPosix(socket_type, flags);
|
||||
if (from == nullptr) {
|
||||
return ConvertReturnErrorCode(::recv(sock, (char*)buf, len, native_flags));
|
||||
}
|
||||
sockaddr native_addr;
|
||||
socklen_t native_addrlen = sizeof(native_addr);
|
||||
int ret = ::recvfrom(sock, (char*)buf, len, native_flags, &native_addr, &native_addrlen);
|
||||
if (ret >= 0) {
|
||||
convertPosixSockaddrToOrbis(&native_addr, from);
|
||||
if (fromlen) {
|
||||
*fromlen = sizeof(OrbisNetSockaddrIn);
|
||||
}
|
||||
}
|
||||
return ConvertReturnErrorCode(ret);
|
||||
return PosixSocket::Connect(addr, namelen);
|
||||
}
|
||||
|
||||
SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr native_addr;
|
||||
socklen_t len = sizeof(native_addr);
|
||||
auto new_sock = ::accept(sock, &native_addr, &len);
|
||||
net_socket new_sock = ::accept(sock, &native_addr, &len);
|
||||
#ifdef _WIN32
|
||||
if (new_sock == INVALID_SOCKET) {
|
||||
#else
|
||||
@ -249,64 +69,11 @@ SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
||||
ConvertReturnErrorCode(-1);
|
||||
return nullptr;
|
||||
}
|
||||
if (addr) {
|
||||
if (addr && addrlen) {
|
||||
convertPosixSockaddrToOrbis(&native_addr, addr);
|
||||
if (addrlen) {
|
||||
*addrlen = sizeof(OrbisNetSockaddrIn);
|
||||
}
|
||||
*addrlen = sizeof(OrbisNetSockaddrIn);
|
||||
}
|
||||
return std::make_shared<PosixSocket>(new_sock);
|
||||
}
|
||||
|
||||
int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
const auto* orbis_addr = reinterpret_cast<const OrbisNetSockaddrIn*>(addr);
|
||||
if (orbis_addr) {
|
||||
vport = orbis_addr->sin_vport;
|
||||
LOG_INFO(Lib_Net, "P2P connect: vport={}", vport);
|
||||
}
|
||||
sockaddr native_addr;
|
||||
convertOrbisNetSockaddrToPosix(addr, &native_addr);
|
||||
int ret = ::connect(sock, &native_addr, sizeof(sockaddr_in));
|
||||
#ifdef _WIN32
|
||||
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
WSASetLastError(WSAEINPROGRESS);
|
||||
}
|
||||
#endif
|
||||
return ConvertReturnErrorCode(ret);
|
||||
}
|
||||
|
||||
int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr native_addr;
|
||||
socklen_t len = sizeof(native_addr);
|
||||
int ret = ::getsockname(sock, &native_addr, &len);
|
||||
if (ret == 0) {
|
||||
convertPosixSockaddrToOrbis(&native_addr, name);
|
||||
if (namelen) {
|
||||
*namelen = sizeof(OrbisNetSockaddrIn);
|
||||
}
|
||||
}
|
||||
return ConvertReturnErrorCode(ret);
|
||||
}
|
||||
|
||||
int P2PSocket::GetPeerName(OrbisNetSockaddr* addr, u32* namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr native_addr;
|
||||
socklen_t len = sizeof(native_addr);
|
||||
int ret = ::getpeername(sock, &native_addr, &len);
|
||||
if (ret == 0) {
|
||||
convertPosixSockaddrToOrbis(&native_addr, addr);
|
||||
if (namelen) {
|
||||
*namelen = sizeof(OrbisNetSockaddrIn);
|
||||
}
|
||||
}
|
||||
return ConvertReturnErrorCode(ret);
|
||||
}
|
||||
|
||||
int P2PSocket::fstat(Libraries::Kernel::OrbisKernelStat* stat) {
|
||||
LOG_DEBUG(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
return std::make_shared<P2PSocket>(new_sock, socket_type, vport);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
||||
|
||||
@ -154,24 +154,39 @@ 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() {
|
||||
int NativeSocket::Close() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
#ifdef _WIN32
|
||||
auto out = closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
#else
|
||||
auto out = ::close(sock);
|
||||
sock = -1;
|
||||
#endif
|
||||
return ConvertReturnErrorCode(out);
|
||||
}
|
||||
|
||||
int NativeSocket::Listen(int backlog) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return ConvertReturnErrorCode(::listen(sock, backlog));
|
||||
}
|
||||
|
||||
int NativeSocket::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;
|
||||
return ConvertReturnErrorCode(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
@ -179,11 +194,6 @@ int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in)));
|
||||
}
|
||||
|
||||
int PosixSocket::Listen(int backlog) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return ConvertReturnErrorCode(::listen(sock, backlog));
|
||||
}
|
||||
|
||||
int convertOrbisFlagsToPosix(int sock_type, int sce_flags) {
|
||||
int posix_flags = 0;
|
||||
|
||||
@ -281,7 +291,8 @@ int PosixSocket::SendMessage(const OrbisNetMsghdr* msg, int flags) {
|
||||
|
||||
#else
|
||||
int native_flags = convertOrbisFlagsToPosix(socket_type, flags);
|
||||
int res = sendmsg(sock, reinterpret_cast<const msghdr*>(msg), native_flags);
|
||||
msghdr native_msg = ConvertOrbisToNativeMsghdr(msg);
|
||||
int res = sendmsg(sock, &native_msg, native_flags);
|
||||
return ConvertReturnErrorCode(res);
|
||||
#endif
|
||||
}
|
||||
@ -374,7 +385,9 @@ int PosixSocket::ReceiveMessage(OrbisNetMsghdr* msg, int flags) {
|
||||
|
||||
#else
|
||||
int native_flags = convertOrbisFlagsToPosix(socket_type, flags);
|
||||
int res = recvmsg(sock, reinterpret_cast<msghdr*>(msg), native_flags);
|
||||
msghdr native_msg = ConvertOrbisToNativeMsghdr(msg);
|
||||
int res = recvmsg(sock, &native_msg, native_flags);
|
||||
msg->msg_flags = native_msg.msg_flags;
|
||||
return ConvertReturnErrorCode(res);
|
||||
#endif
|
||||
}
|
||||
@ -523,7 +536,7 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3
|
||||
return -1;
|
||||
}
|
||||
case ORBIS_NET_SO_LINGER: {
|
||||
if (socket_type != ORBIS_NET_SOCK_STREAM) {
|
||||
if (socket_type != ORBIS_NET_SOCK_STREAM && socket_type != ORBIS_NET_SOCK_STREAM_P2P) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EPROCUNAVAIL;
|
||||
return -1;
|
||||
}
|
||||
@ -689,21 +702,4 @@ int PosixSocket::GetPeerName(OrbisNetSockaddr* name, u32* namelen) {
|
||||
return ConvertReturnErrorCode(res);
|
||||
}
|
||||
|
||||
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 ConvertReturnErrorCode(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
||||
} // namespace Libraries::Net
|
||||
|
||||
@ -63,6 +63,22 @@ int ConvertLevels(int level);
|
||||
void convertOrbisNetSockaddrToPosix(const OrbisNetSockaddr* src, sockaddr* dst);
|
||||
void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst);
|
||||
int convertOrbisFlagsToPosix(int sock_type, int sce_flags);
|
||||
#ifndef _WIN32
|
||||
// Build a native msghdr from OrbisNetMsghdr. OrbisNetMsghdr uses
|
||||
// int-sized fields (msg_iovlen, msg_controllen) where native msghdr uses size_t,
|
||||
// so a reinterpret_cast would corrupt the layout on 64-bit systems.
|
||||
inline msghdr ConvertOrbisToNativeMsghdr(const OrbisNetMsghdr* msg) {
|
||||
msghdr native_msg{};
|
||||
native_msg.msg_name = msg->msg_name;
|
||||
native_msg.msg_namelen = msg->msg_namelen;
|
||||
native_msg.msg_iov = reinterpret_cast<iovec*>(msg->msg_iov);
|
||||
native_msg.msg_iovlen = msg->msg_iovlen;
|
||||
native_msg.msg_control = msg->msg_control;
|
||||
native_msg.msg_controllen = msg->msg_controllen;
|
||||
native_msg.msg_flags = msg->msg_flags;
|
||||
return native_msg;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct OrbisNetLinger {
|
||||
s32 l_onoff;
|
||||
@ -94,8 +110,40 @@ struct Socket {
|
||||
int socket_type;
|
||||
};
|
||||
|
||||
struct PosixSocket : public Socket {
|
||||
// Owns the OS socket fd and implements methods identical across all socket types.
|
||||
struct NativeSocket : public Socket {
|
||||
net_socket sock;
|
||||
|
||||
NativeSocket(int domain, int type, int protocol)
|
||||
: Socket(domain, type, protocol), sock(::socket(domain, type, protocol)) {}
|
||||
|
||||
// Wrap an already-existing fd. Queries SO_TYPE from the OS automatically.
|
||||
// Note: Socket base domain/protocol remain 0 — only socket_type is recovered.
|
||||
explicit NativeSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {
|
||||
int type = 0;
|
||||
socklen_t len = sizeof(type);
|
||||
::getsockopt(sock, SOL_SOCKET, SO_TYPE, (char*)&type, &len);
|
||||
socket_type = type;
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
#ifdef _WIN32
|
||||
return sock != INVALID_SOCKET;
|
||||
#else
|
||||
return sock != -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Close() override;
|
||||
int Listen(int backlog) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* stat) override;
|
||||
|
||||
std::optional<net_socket> Native() override {
|
||||
return sock;
|
||||
}
|
||||
};
|
||||
|
||||
struct PosixSocket : public NativeSocket {
|
||||
int sockopt_so_connecttimeo = 0;
|
||||
int sockopt_so_reuseport = 0;
|
||||
int sockopt_so_onesbcast = 0;
|
||||
@ -105,18 +153,14 @@ struct PosixSocket : public Socket {
|
||||
int sockopt_ip_ttlchk = 0;
|
||||
int sockopt_ip_maxttl = 0;
|
||||
int sockopt_tcp_mss_to_advertise = 0;
|
||||
int socket_type;
|
||||
|
||||
explicit PosixSocket(int domain, int type, int protocol)
|
||||
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {
|
||||
socket_type = type;
|
||||
}
|
||||
explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {}
|
||||
bool IsValid() const override;
|
||||
int Close() override;
|
||||
: NativeSocket(domain, type, protocol) {}
|
||||
explicit PosixSocket(net_socket sock) : NativeSocket(sock) {}
|
||||
|
||||
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;
|
||||
@ -126,55 +170,32 @@ struct PosixSocket : public Socket {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
struct P2PSocket : public Socket {
|
||||
net_socket sock;
|
||||
int sockopt_so_nbio = 0;
|
||||
int socket_type;
|
||||
struct P2PSocket : public PosixSocket {
|
||||
u16 vport = 0; // PS4 virtual port
|
||||
|
||||
explicit P2PSocket(int domain, int type, int protocol);
|
||||
~P2PSocket() override;
|
||||
bool IsValid() const override;
|
||||
int Close() override;
|
||||
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
|
||||
// Wrap an already-accepted fd. The PS4 type must be passed explicitly because
|
||||
// the OS only knows SOCK_STREAM/SOCK_DGRAM, not PS4-specific P2P socket types.
|
||||
P2PSocket(net_socket accepted_sock, int ps4_type, u16 parent_vport)
|
||||
: PosixSocket(accepted_sock), vport(parent_vport) {
|
||||
socket_type = ps4_type;
|
||||
}
|
||||
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;
|
||||
}
|
||||
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
|
||||
};
|
||||
|
||||
struct UnixSocket : public Socket {
|
||||
net_socket sock;
|
||||
int socket_type;
|
||||
struct UnixSocket : public NativeSocket {
|
||||
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;
|
||||
: NativeSocket(domain, type, protocol) {}
|
||||
explicit UnixSocket(net_socket sock) : NativeSocket(sock) {}
|
||||
|
||||
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;
|
||||
@ -184,10 +205,6 @@ struct UnixSocket : public Socket {
|
||||
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
|
||||
} // namespace Libraries::Net
|
||||
|
||||
@ -36,24 +36,6 @@ static void convertUnixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) {
|
||||
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;
|
||||
@ -61,11 +43,6 @@ int UnixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
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
|
||||
@ -87,7 +64,8 @@ int UnixSocket::SendMessage(const OrbisNetMsghdr* msg, int flags) {
|
||||
}
|
||||
return static_cast<int>(bytesSent);
|
||||
#else
|
||||
int res = sendmsg(sock, reinterpret_cast<const msghdr*>(msg), flags);
|
||||
msghdr native_msg = ConvertOrbisToNativeMsghdr(msg);
|
||||
int res = sendmsg(sock, &native_msg, flags);
|
||||
return ConvertReturnErrorCode(res);
|
||||
#endif
|
||||
}
|
||||
@ -126,7 +104,9 @@ int UnixSocket::ReceiveMessage(OrbisNetMsghdr* msg, int flags) {
|
||||
}
|
||||
return static_cast<int>(bytesReceived);
|
||||
#else
|
||||
int res = recvmsg(sock, reinterpret_cast<msghdr*>(msg), flags);
|
||||
msghdr native_msg = ConvertOrbisToNativeMsghdr(msg);
|
||||
int res = recvmsg(sock, &native_msg, flags);
|
||||
msg->msg_flags = native_msg.msg_flags;
|
||||
return ConvertReturnErrorCode(res);
|
||||
#endif
|
||||
}
|
||||
@ -256,21 +236,4 @@ int UnixSocket::GetPeerName(OrbisNetSockaddr* name, u32* namelen) {
|
||||
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
|
||||
} // namespace Libraries::Net
|
||||
|
||||
Loading…
Reference in New Issue
Block a user