mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
UDP P2P sockets
This commit is contained in:
+248
-66
@@ -14,10 +14,11 @@
|
|||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -41,8 +42,11 @@
|
|||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Libs::Network {
|
namespace Libs::Network {
|
||||||
@@ -844,9 +848,37 @@ using SocketLength = socklen_t;
|
|||||||
using SocketIoLength = size_t;
|
using SocketIoLength = size_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct SocketTransport {
|
||||||
|
explicit SocketTransport(NativeSocket value): socket(value) {}
|
||||||
|
~SocketTransport() { Close(); }
|
||||||
|
int Close() {
|
||||||
|
if (socket == INVALID_NATIVE_SOCKET) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto value = std::exchange(socket, INVALID_NATIVE_SOCKET);
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return closesocket(value);
|
||||||
|
#else
|
||||||
|
return ::close(value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
NativeSocket socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct P2pEndpoint {
|
||||||
|
bool bound = false;
|
||||||
|
uint32_t address = 0;
|
||||||
|
uint16_t port = 0;
|
||||||
|
uint16_t virtual_port = 0;
|
||||||
|
int nonblocking = 0;
|
||||||
|
int broadcast = 0;
|
||||||
|
int send_buffer = 9216;
|
||||||
|
int receive_buffer = 40 * 1024;
|
||||||
|
};
|
||||||
|
|
||||||
struct SocketSlot {
|
struct SocketSlot {
|
||||||
bool used = false;
|
std::shared_ptr<SocketTransport> transport;
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
std::optional<P2pEndpoint> p2p;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetTimeval {
|
struct NetTimeval {
|
||||||
@@ -998,6 +1030,16 @@ static int ConvertSocketOptionLevel(int level) {
|
|||||||
return (level == 0xffff ? SOL_SOCKET : level);
|
return (level == 0xffff ? SOL_SOCKET : level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int* P2pSocketOption(P2pEndpoint& endpoint, int option) {
|
||||||
|
switch (option) {
|
||||||
|
case 0x0020: return &endpoint.broadcast;
|
||||||
|
case 0x1001: return &endpoint.send_buffer;
|
||||||
|
case 0x1002: return &endpoint.receive_buffer;
|
||||||
|
case 0x1200: return &endpoint.nonblocking;
|
||||||
|
default: return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ConvertMessageFlags(int flags) {
|
static int ConvertMessageFlags(int flags) {
|
||||||
constexpr int guest_msg_peek = 0x00000002;
|
constexpr int guest_msg_peek = 0x00000002;
|
||||||
constexpr int guest_msg_dontroute = 0x00000004;
|
constexpr int guest_msg_dontroute = 0x00000004;
|
||||||
@@ -1104,19 +1146,30 @@ static int ConvertHostSockaddr(const sockaddr_storage* addr, SocketLength addrle
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetSocketBackend(int guest_fd, NativeSocket* out) {
|
static bool GetSocketBackend(int guest_fd, NativeSocket* out, SocketSlot* state = nullptr) {
|
||||||
EXIT_IF(out == nullptr);
|
EXIT_IF(out == nullptr);
|
||||||
|
|
||||||
if (guest_fd < 0 || guest_fd >= SOCKET_FD_MAX) {
|
if (guest_fd < 0 || guest_fd >= SOCKET_FD_MAX) {
|
||||||
|
SetGuestSocketError(Posix::POSIX_EBADF);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::LockGuard lock(g_socket_mutex);
|
Common::LockGuard lock(g_socket_mutex);
|
||||||
if (!g_sockets[static_cast<size_t>(guest_fd)].used) {
|
const auto& slot = g_sockets[static_cast<size_t>(guest_fd)];
|
||||||
|
if (!slot.transport) {
|
||||||
|
SetGuestSocketError(Posix::POSIX_EBADF);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Native-only operations cannot act on a transport shared by virtual ports.
|
||||||
|
if (slot.p2p && state == nullptr) {
|
||||||
|
SetGuestSocketError(Posix::POSIX_EOPNOTSUPP);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = g_sockets[static_cast<size_t>(guest_fd)].socket;
|
*out = slot.transport->socket;
|
||||||
|
if (state != nullptr) {
|
||||||
|
*state = slot;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,10 +1179,10 @@ bool KYTY_SYSV_ABI IsSocket(int s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Common::LockGuard lock(g_socket_mutex);
|
Common::LockGuard lock(g_socket_mutex);
|
||||||
return g_sockets[static_cast<size_t>(s)].used;
|
return g_sockets[static_cast<size_t>(s)].transport != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool TakeSocketBackend(int guest_fd, NativeSocket* out) {
|
static bool TakeSocketBackend(int guest_fd, SocketSlot* out) {
|
||||||
EXIT_IF(out == nullptr);
|
EXIT_IF(out == nullptr);
|
||||||
|
|
||||||
if (guest_fd < 0 || guest_fd >= SOCKET_FD_MAX) {
|
if (guest_fd < 0 || guest_fd >= SOCKET_FD_MAX) {
|
||||||
@@ -1138,22 +1191,24 @@ static bool TakeSocketBackend(int guest_fd, NativeSocket* out) {
|
|||||||
|
|
||||||
Common::LockGuard lock(g_socket_mutex);
|
Common::LockGuard lock(g_socket_mutex);
|
||||||
auto& slot = g_sockets[static_cast<size_t>(guest_fd)];
|
auto& slot = g_sockets[static_cast<size_t>(guest_fd)];
|
||||||
if (!slot.used) {
|
if (!slot.transport) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = slot.socket;
|
*out = std::move(slot);
|
||||||
slot = {};
|
slot = {};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int AllocSocketFd(NativeSocket socket) {
|
static int AllocSocketFd(const std::shared_ptr<SocketTransport>& transport, bool p2p = false) {
|
||||||
Common::LockGuard lock(g_socket_mutex);
|
Common::LockGuard lock(g_socket_mutex);
|
||||||
for (int fd = SOCKET_FD_MIN; fd < SOCKET_FD_MAX; fd++) {
|
for (int fd = SOCKET_FD_MIN; fd < SOCKET_FD_MAX; fd++) {
|
||||||
auto& slot = g_sockets[static_cast<size_t>(fd)];
|
auto& slot = g_sockets[static_cast<size_t>(fd)];
|
||||||
if (!slot.used) {
|
if (!slot.transport) {
|
||||||
slot.used = true;
|
slot.transport = transport;
|
||||||
slot.socket = socket;
|
if (p2p) {
|
||||||
|
slot.p2p.emplace();
|
||||||
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1528,10 +1583,10 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
struct HostRegistration {
|
struct HostRegistration {
|
||||||
EpollRegistration guest;
|
EpollRegistration guest;
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
|
SocketSlot state;
|
||||||
};
|
};
|
||||||
|
|
||||||
fd_set host_read {};
|
fd_set host_read {};
|
||||||
@@ -1543,14 +1598,23 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
|
|||||||
|
|
||||||
std::vector<HostRegistration> host_registrations;
|
std::vector<HostRegistration> host_registrations;
|
||||||
host_registrations.reserve(registrations.size());
|
host_registrations.reserve(registrations.size());
|
||||||
|
int host_nfds = 0;
|
||||||
for (const auto& registration: registrations) {
|
for (const auto& registration: registrations) {
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (!GetSocketBackend(registration.id, &socket)) {
|
SocketSlot state;
|
||||||
|
if (!GetSocketBackend(registration.id, &socket, &state)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#if defined(_WIN32)
|
||||||
if (host_registrations.size() >= FD_SETSIZE) {
|
if (host_registrations.size() >= FD_SETSIZE) {
|
||||||
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (socket >= FD_SETSIZE) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
host_nfds = std::max(host_nfds, socket + 1);
|
||||||
|
#endif
|
||||||
if ((registration.event.events & EPOLL_IN) != 0) {
|
if ((registration.event.events & EPOLL_IN) != 0) {
|
||||||
FD_SET(socket, &host_read);
|
FD_SET(socket, &host_read);
|
||||||
}
|
}
|
||||||
@@ -1558,7 +1622,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
|
|||||||
FD_SET(socket, &host_write);
|
FD_SET(socket, &host_write);
|
||||||
}
|
}
|
||||||
FD_SET(socket, &host_except);
|
FD_SET(socket, &host_except);
|
||||||
host_registrations.push_back({registration, socket});
|
host_registrations.push_back({registration, socket, std::move(state)});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host_registrations.empty()) {
|
if (host_registrations.empty()) {
|
||||||
@@ -1573,8 +1637,8 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
|
|||||||
host_timeout_ptr = &host_timeout;
|
host_timeout_ptr = &host_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int result = ::select(0, &host_read, &host_write, &host_except, host_timeout_ptr);
|
const int result = ::select(host_nfds, &host_read, &host_write, &host_except, host_timeout_ptr);
|
||||||
if (result == SOCKET_ERROR) {
|
if (result < 0) {
|
||||||
return SetHostSocketError();
|
return SetHostSocketError();
|
||||||
}
|
}
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
@@ -1584,10 +1648,15 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (const auto& registration: host_registrations) {
|
for (const auto& registration: host_registrations) {
|
||||||
uint32_t ready = 0;
|
uint32_t ready = 0;
|
||||||
if (FD_ISSET(registration.socket, &host_read)) {
|
if ((registration.guest.event.events & EPOLL_IN) != 0 &&
|
||||||
|
FD_ISSET(registration.socket, &host_read)) {
|
||||||
|
if (registration.state.p2p) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EOPNOTSUPP);
|
||||||
|
}
|
||||||
ready |= EPOLL_IN;
|
ready |= EPOLL_IN;
|
||||||
}
|
}
|
||||||
if (FD_ISSET(registration.socket, &host_write)) {
|
if ((registration.guest.event.events & EPOLL_OUT) != 0 &&
|
||||||
|
FD_ISSET(registration.socket, &host_write)) {
|
||||||
ready |= EPOLL_OUT;
|
ready |= EPOLL_OUT;
|
||||||
}
|
}
|
||||||
if (FD_ISSET(registration.socket, &host_except)) {
|
if (FD_ISSET(registration.socket, &host_except)) {
|
||||||
@@ -1607,10 +1676,6 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
#else
|
|
||||||
(void)timeout;
|
|
||||||
return SetGuestSocketError(Posix::POSIX_ENOSYS);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI EpollDestroy(int eid) {
|
int KYTY_SYSV_ABI EpollDestroy(int eid) {
|
||||||
@@ -1632,18 +1697,13 @@ int KYTY_SYSV_ABI SocketClose(int s) {
|
|||||||
|
|
||||||
LOGF("\t s = %d\n", s);
|
LOGF("\t s = %d\n", s);
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
SocketSlot slot;
|
||||||
if (!TakeSocketBackend(s, &socket)) {
|
if (!TakeSocketBackend(s, &slot)) {
|
||||||
return NET_ERROR_EBADF;
|
return NET_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
RemoveSocketFromEpolls(s);
|
RemoveSocketFromEpolls(s);
|
||||||
|
|
||||||
#if defined(_WIN32)
|
if (slot.transport.use_count() == 1 && slot.transport->Close() != 0) {
|
||||||
const int result = closesocket(socket);
|
|
||||||
#else
|
|
||||||
const int result = ::close(socket);
|
|
||||||
#endif
|
|
||||||
if (result != 0) {
|
|
||||||
return NET_ERROR_EBADF;
|
return NET_ERROR_EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1668,18 +1728,31 @@ int KYTY_SYSV_ABI Socket(int family, int type, int protocol) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeSocket socket = ::socket(host_family, type, protocol);
|
constexpr int socket_dgram_p2p = 6;
|
||||||
|
const bool p2p = type == socket_dgram_p2p;
|
||||||
|
if (p2p && (family != 2 || protocol != 0)) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EPROTONOSUPPORT);
|
||||||
|
}
|
||||||
|
NativeSocket socket = ::socket(host_family, p2p ? SOCK_DGRAM : type, protocol);
|
||||||
if (socket == INVALID_NATIVE_SOCKET) {
|
if (socket == INVALID_NATIVE_SOCKET) {
|
||||||
return SetHostSocketError();
|
return SetHostSocketError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int fd = AllocSocketFd(socket);
|
auto transport = std::make_shared<SocketTransport>(socket);
|
||||||
if (fd < 0) {
|
if (p2p) {
|
||||||
|
// Logical sockets keep their own blocking mode; the shared transport never blocks.
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
closesocket(socket);
|
u_long enabled = 1;
|
||||||
|
const int result = ioctlsocket(socket, FIONBIO, &enabled);
|
||||||
#else
|
#else
|
||||||
::close(socket);
|
const int result = ::fcntl(socket, F_SETFL, O_NONBLOCK);
|
||||||
#endif
|
#endif
|
||||||
|
if (result != 0) {
|
||||||
|
return SetHostSocketError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int fd = AllocSocketFd(transport, p2p);
|
||||||
|
if (fd < 0) {
|
||||||
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
|
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1697,8 +1770,11 @@ int KYTY_SYSV_ABI Bind(int s, const void* addr, uint32_t addrlen) {
|
|||||||
s, reinterpret_cast<uint64_t>(addr), addrlen);
|
s, reinterpret_cast<uint64_t>(addr), addrlen);
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (addr == nullptr || !GetSocketBackend(s, &socket)) {
|
SocketSlot state;
|
||||||
*Posix::GetErrorAddr() = (addr == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
|
if (addr == nullptr) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EFAULT);
|
||||||
|
}
|
||||||
|
if (!GetSocketBackend(s, &socket, &state)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1708,6 +1784,67 @@ int KYTY_SYSV_ABI Bind(int s, const void* addr, uint32_t addrlen) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.p2p) {
|
||||||
|
if (addrlen < 16) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
const auto& in = *reinterpret_cast<const sockaddr_in*>(&host_addr);
|
||||||
|
uint32_t address = 0;
|
||||||
|
std::memcpy(&address, &in.sin_addr, sizeof(address));
|
||||||
|
uint16_t virtual_port = 0;
|
||||||
|
std::memcpy(&virtual_port, static_cast<const uint8_t*>(addr) + 8, sizeof(virtual_port));
|
||||||
|
const auto requested_port = ntohs(virtual_port);
|
||||||
|
if (requested_port == 0) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
if (ntohs(in.sin_port) != 3658) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
if (requested_port == 5353 || requested_port >= 32768) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EACCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::LockGuard lock(g_socket_mutex);
|
||||||
|
auto& slot = g_sockets[static_cast<size_t>(s)];
|
||||||
|
if (slot.transport != state.transport) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EBADF);
|
||||||
|
}
|
||||||
|
auto& endpoint = *slot.p2p;
|
||||||
|
if (endpoint.bound) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
auto conflicts = [&](uint16_t port) {
|
||||||
|
return std::any_of(g_sockets.begin(), g_sockets.end(), [&](const auto& other) {
|
||||||
|
return other.p2p && other.p2p->bound && other.p2p->port == in.sin_port &&
|
||||||
|
other.p2p->address == address && other.p2p->virtual_port == port;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (conflicts(virtual_port)) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EADDRINUSE);
|
||||||
|
}
|
||||||
|
std::shared_ptr<SocketTransport> shared;
|
||||||
|
for (const auto& other: g_sockets) {
|
||||||
|
if (other.p2p && other.p2p->bound && other.p2p->port == in.sin_port &&
|
||||||
|
other.p2p->address == address) {
|
||||||
|
shared = other.transport;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shared) {
|
||||||
|
slot.transport = std::move(shared);
|
||||||
|
} else if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) !=
|
||||||
|
0) {
|
||||||
|
return SetHostSocketError();
|
||||||
|
}
|
||||||
|
endpoint.bound = true;
|
||||||
|
endpoint.address = address;
|
||||||
|
endpoint.port = in.sin_port;
|
||||||
|
endpoint.virtual_port = virtual_port;
|
||||||
|
LOGF("\t UDPP2P bound UDP port=%u virtual port=%u\n", ntohs(endpoint.port),
|
||||||
|
ntohs(endpoint.virtual_port));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) != 0) {
|
if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) != 0) {
|
||||||
return SetHostSocketError();
|
return SetHostSocketError();
|
||||||
}
|
}
|
||||||
@@ -1724,8 +1861,10 @@ int KYTY_SYSV_ABI Connect(int s, const void* addr, uint32_t addrlen) {
|
|||||||
s, reinterpret_cast<uint64_t>(addr), addrlen);
|
s, reinterpret_cast<uint64_t>(addr), addrlen);
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (addr == nullptr || !GetSocketBackend(s, &socket)) {
|
if (addr == nullptr) {
|
||||||
*Posix::GetErrorAddr() = (addr == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
|
return SetGuestSocketError(Posix::POSIX_EFAULT);
|
||||||
|
}
|
||||||
|
if (!GetSocketBackend(s, &socket)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1751,7 +1890,6 @@ int KYTY_SYSV_ABI Listen(int s, int backlog) {
|
|||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (!GetSocketBackend(s, &socket)) {
|
if (!GetSocketBackend(s, &socket)) {
|
||||||
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1772,7 +1910,6 @@ int KYTY_SYSV_ABI Accept(int s, void* addr, uint32_t* addrlen) {
|
|||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (!GetSocketBackend(s, &socket)) {
|
if (!GetSocketBackend(s, &socket)) {
|
||||||
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1784,13 +1921,9 @@ int KYTY_SYSV_ABI Accept(int s, void* addr, uint32_t* addrlen) {
|
|||||||
return SetHostSocketError();
|
return SetHostSocketError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int fd = AllocSocketFd(accepted);
|
auto transport = std::make_shared<SocketTransport>(accepted);
|
||||||
|
const int fd = AllocSocketFd(transport);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
#if defined(_WIN32)
|
|
||||||
closesocket(accepted);
|
|
||||||
#else
|
|
||||||
::close(accepted);
|
|
||||||
#endif
|
|
||||||
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
|
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1819,7 +1952,6 @@ int KYTY_SYSV_ABI Shutdown(int s, int how) {
|
|||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (!GetSocketBackend(s, &socket)) {
|
if (!GetSocketBackend(s, &socket)) {
|
||||||
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1848,12 +1980,14 @@ int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) {
|
|||||||
"\t addrlen = 0x%016" PRIx64 "\n",
|
"\t addrlen = 0x%016" PRIx64 "\n",
|
||||||
s, reinterpret_cast<uint64_t>(addr), reinterpret_cast<uint64_t>(addrlen));
|
s, reinterpret_cast<uint64_t>(addr), reinterpret_cast<uint64_t>(addrlen));
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
const bool socket_ok = GetSocketBackend(s, &socket);
|
SocketSlot state;
|
||||||
if (addr == nullptr || addrlen == nullptr || !socket_ok) {
|
if (!GetSocketBackend(s, &socket, &state)) {
|
||||||
*Posix::GetErrorAddr() = (!socket_ok ? Posix::POSIX_EBADF : Posix::POSIX_EFAULT);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (addr == nullptr || addrlen == nullptr) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
sockaddr_storage host_addr {};
|
sockaddr_storage host_addr {};
|
||||||
SocketLength host_addrlen = sizeof(host_addr);
|
SocketLength host_addrlen = sizeof(host_addr);
|
||||||
@@ -1861,7 +1995,11 @@ int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) {
|
|||||||
return SetHostSocketError();
|
return SetHostSocketError();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen);
|
const int result = ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen);
|
||||||
|
if (result == 0 && state.p2p) {
|
||||||
|
std::memcpy(static_cast<uint8_t*>(addr) + 8, &state.p2p->virtual_port, sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32_t* optlen) {
|
int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32_t* optlen) {
|
||||||
@@ -1872,12 +2010,26 @@ int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32
|
|||||||
"\t optname = 0x%08" PRIx32 "\n",
|
"\t optname = 0x%08" PRIx32 "\n",
|
||||||
s, static_cast<uint32_t>(level), static_cast<uint32_t>(optname));
|
s, static_cast<uint32_t>(level), static_cast<uint32_t>(optname));
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
const bool socket_ok = GetSocketBackend(s, &socket);
|
SocketSlot state;
|
||||||
if (optval == nullptr || optlen == nullptr || !socket_ok) {
|
if (!GetSocketBackend(s, &socket, &state)) {
|
||||||
*Posix::GetErrorAddr() = (!socket_ok ? Posix::POSIX_EBADF : Posix::POSIX_EFAULT);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (optval == nullptr || optlen == nullptr) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EFAULT);
|
||||||
|
}
|
||||||
|
if (state.p2p) {
|
||||||
|
const auto* value = level == 0xffff ? P2pSocketOption(*state.p2p, optname) : nullptr;
|
||||||
|
if (value == nullptr) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
if (*optlen < sizeof(int)) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
std::memcpy(optval, value, sizeof(int));
|
||||||
|
*optlen = sizeof(int);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Guest socket options: SOL_SOCKET=0xffff, SO_ERROR=0x1007.
|
// Guest socket options: SOL_SOCKET=0xffff, SO_ERROR=0x1007.
|
||||||
const bool socket_error = (level == 0xffff && optname == 0x1007);
|
const bool socket_error = (level == 0xffff && optname == 0x1007);
|
||||||
@@ -1912,10 +2064,38 @@ int KYTY_SYSV_ABI Setsockopt(int s, int level, int optname, const void* optval,
|
|||||||
s, static_cast<uint32_t>(level), static_cast<uint32_t>(optname), optlen);
|
s, static_cast<uint32_t>(level), static_cast<uint32_t>(optname), optlen);
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (optval == nullptr || !GetSocketBackend(s, &socket)) {
|
SocketSlot state;
|
||||||
*Posix::GetErrorAddr() = (optval == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
|
if (optval == nullptr) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EFAULT);
|
||||||
|
}
|
||||||
|
if (!GetSocketBackend(s, &socket, &state)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (state.p2p) {
|
||||||
|
Common::LockGuard lock(g_socket_mutex);
|
||||||
|
auto& slot = g_sockets[static_cast<size_t>(s)];
|
||||||
|
if (slot.transport != state.transport) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EBADF);
|
||||||
|
}
|
||||||
|
auto* option = level == 0xffff ? P2pSocketOption(*slot.p2p, optname) : nullptr;
|
||||||
|
if (option == nullptr) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
if (optlen != sizeof(int)) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
int value = 0;
|
||||||
|
std::memcpy(&value, optval, sizeof(value));
|
||||||
|
if (optname == 0x1001 || optname == 0x1002) {
|
||||||
|
if (value <= 0) {
|
||||||
|
return SetGuestSocketError(Posix::POSIX_EINVAL);
|
||||||
|
}
|
||||||
|
*option = optname == 0x1002 ? std::min(value, 512 * 1024) : value;
|
||||||
|
} else {
|
||||||
|
*option = value != 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
constexpr int ORBIS_SO_NBIO = 0x1200;
|
constexpr int ORBIS_SO_NBIO = 0x1200;
|
||||||
@@ -1962,8 +2142,11 @@ int64_t KYTY_SYSV_ABI Sendto(int s, const void* buf, uint64_t len, int flags, co
|
|||||||
reinterpret_cast<uint64_t>(addr), addrlen);
|
reinterpret_cast<uint64_t>(addr), addrlen);
|
||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (buf == nullptr || !GetSocketBackend(s, &socket)) {
|
if (buf == nullptr) {
|
||||||
*Posix::GetErrorAddr() = (buf == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
|
return SetGuestSocketError(Posix::POSIX_EFAULT);
|
||||||
|
}
|
||||||
|
// UDPP2P requires protocol framing; the native-only lookup rejects raw sends.
|
||||||
|
if (!GetSocketBackend(s, &socket)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2017,7 +2200,6 @@ int64_t KYTY_SYSV_ABI Recvfrom(int s, void* buf, uint64_t len, int flags, void*
|
|||||||
|
|
||||||
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
NativeSocket socket = INVALID_NATIVE_SOCKET;
|
||||||
if (!GetSocketBackend(s, &socket)) {
|
if (!GetSocketBackend(s, &socket)) {
|
||||||
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2107,7 +2289,7 @@ int KYTY_SYSV_ABI Select(int nfds, void* readfds, void* writefds, void* exceptfd
|
|||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (!GetSocketBackend(fd, &socket)) {
|
if (!GetSocketBackend(fd, &socket)) {
|
||||||
return SetGuestSocketError(Posix::POSIX_EBADF);
|
return -1;
|
||||||
}
|
}
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
if ((read && host_read.fd_count == FD_SETSIZE) ||
|
if ((read && host_read.fd_count == FD_SETSIZE) ||
|
||||||
|
|||||||
Reference in New Issue
Block a user