sys_net: Use IDM, initialize networking on startup

This commit is contained in:
Raul Tambre 2016-04-18 10:06:22 +03:00
parent 31ec26a7a1
commit 2e5d20c315
No known key found for this signature in database
GPG key ID: FC357D4861AC031E
2 changed files with 106 additions and 71 deletions

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "sys_net.h"
@ -19,10 +20,14 @@
logs::channel libnet("libnet", logs::level::notice);
// We map host sockets to sequential IDs to return as FDs because syscalls using
// socketselect(), etc. expect socket FDs to be under 1024.
// We start at 1 because 0 is an invalid socket.
std::vector<s64> g_socketMap{ 0 };
namespace sys_net
{
#ifdef _WIN32
using socket_t = SOCKET;
#else
using socket_t = int;
#endif
}
// Auxiliary Functions
// FIXME: Use the variant from OS instead? Why do we even have such a custom function?
@ -76,6 +81,35 @@ int inet_pton(int af, const char *src, char *dst)
}
}
// Custom structure for sockets
// We map host sockets to sequential IDs to return as descriptors because syscalls expect socket IDs to be under 1024.
struct sys_net_socket final
{
using id_base = sys_net_socket;
static constexpr u32 id_min = 0; // Minimal valid socket number is 0 (not 1).
static constexpr u32 id_max = 1023;
sys_net::socket_t s = -1;
explicit sys_net_socket(s32 socket) : s(socket)
{
}
~sys_net_socket()
{
if (s != -1)
#ifdef _WIN32
::closesocket(s);
#else
::close(s);
#endif
}
sys_net_socket(sys_net_socket const &) = delete;
sys_net_socket& operator=(const sys_net_socket&) = delete;
};
void copy_fdset(fd_set* set, vm::ptr<sys_net::fd_set> src)
{
FD_ZERO(set);
@ -91,9 +125,9 @@ void copy_fdset(fd_set* set, vm::ptr<sys_net::fd_set> src)
{
if (src->fds_bits[i] & (1 << bit))
{
u32 sock = (i << 5) | bit;
sys_net::socket_t sock = idm::get<sys_net_socket>((i << 5) | bit)->s;
//libnet.error("setting: fd %d", sock);
FD_SET(g_socketMap[sock], set);
FD_SET(sock, set);
}
}
}
@ -147,40 +181,41 @@ namespace sys_net
s32 get_last_error()
{
// Convert the error code for socket functions to a one for sys_net
s32 result;
const char* name{};
#ifdef _WIN32
switch (WSAGetLastError())
{
case WSAEWOULDBLOCK:
return SYS_NET_EWOULDBLOCK;
default:
throw EXCEPTION("Unknown Win32 socket error: %d", WSAGetLastError());
}
switch (s32 code = WSAGetLastError())
#define ERROR_CASE(error) case WSA ## error: result = SYS_NET_ ## error; name = #error; break;
#else
switch (errno)
switch (s32 code = errno)
#define ERROR_CASE(error) case error: result = SYS_NET_ ## error; name = #error; break;
#endif
{
case EWOULDBLOCK:
return SYS_NET_EWOULDBLOCK;
default:
throw EXCEPTION("Unknown Unix socket error: %d", errno);
ERROR_CASE(EWOULDBLOCK);
default: throw fmt::exception("Unknown/illegal socket error: %d" HERE, code);
}
return errno;
#endif
if (name && result != SYS_NET_EWOULDBLOCK)
{
ppu_error_code::report(result, name);
}
return result;
#undef ERROR_CASE
}
// Functions
s32 accept(s32 s, vm::ptr<sockaddr> addr, vm::ptr<u32> paddrlen)
{
libnet.warning("accept(s=%d, family=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
s32 ret;
if (!addr)
{
ret = ::accept(s, nullptr, nullptr);
ret = ::accept(sock->s, nullptr, nullptr);
if (ret < 0)
{
@ -193,7 +228,7 @@ namespace sys_net
::sockaddr _addr;
::socklen_t _paddrlen = 16;
ret = ::accept(s, &_addr, &_paddrlen);
ret = ::accept(sock->s, &_addr, &_paddrlen);
if (ret < 0)
{
@ -207,21 +242,20 @@ namespace sys_net
memcpy(addr->sa_data, _addr.sa_data, addr->sa_len - 2);
}
g_socketMap.push_back(ret);
return g_socketMap.size() - 1;
return idm::make<sys_net_socket>(ret);
}
s32 bind(s32 s, vm::cptr<sockaddr> addr, u32 addrlen)
{
libnet.warning("bind(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
::sockaddr_in saddr;
memcpy(&saddr, addr.get_ptr(), sizeof(::sockaddr_in));
saddr.sin_family = addr->sa_family;
const char *ipaddr = ::inet_ntoa(saddr.sin_addr);
libnet.warning("binding to %s on port %d", ipaddr, ntohs(saddr.sin_port));
s32 ret = ::bind(s, (const ::sockaddr*)&saddr, addrlen);
s32 ret = ::bind(sock->s, (const ::sockaddr*)&saddr, addrlen);
if (ret != 0)
{
@ -235,14 +269,14 @@ namespace sys_net
s32 connect(s32 s, vm::ptr<sockaddr> addr, u32 addrlen)
{
libnet.warning("connect(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
::sockaddr_in saddr;
memcpy(&saddr, addr.get_ptr(), sizeof(::sockaddr_in));
saddr.sin_family = addr->sa_family;
libnet.warning("connecting to %s on port %d", ::inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
s32 ret = ::connect(s, (const ::sockaddr*)&saddr, addrlen);
s32 ret = ::connect(sock->s, (const ::sockaddr*)&saddr, addrlen);
if (ret != 0)
{
@ -359,9 +393,9 @@ namespace sys_net
s32 listen(s32 s, s32 backlog)
{
libnet.warning("listen(s=%d, backlog=%d)", s, backlog);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
s32 ret = ::listen(s, backlog);
s32 ret = ::listen(sock->s, backlog);
if (ret != 0)
{
@ -375,9 +409,9 @@ namespace sys_net
s32 recv(s32 s, vm::ptr<char> buf, u32 len, s32 flags)
{
libnet.warning("recv(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
s32 ret = ::recv(s, buf.get_ptr(), len, flags);
s32 ret = ::recv(sock->s, buf.get_ptr(), len, flags);
if (ret < 0)
{
@ -391,14 +425,14 @@ namespace sys_net
s32 recvfrom(s32 s, vm::ptr<char> buf, u32 len, s32 flags, vm::ptr<sockaddr> addr, vm::ptr<u32> paddrlen)
{
libnet.warning("recvfrom(s=%d, buf=*0x%x, len=%d, flags=0x%x, addr=*0x%x, paddrlen=*0x%x)", s, buf, len, flags, addr, paddrlen);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
::sockaddr _addr;
::socklen_t _paddrlen;
memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr));
_addr.sa_family = addr->sa_family;
s32 ret = ::recvfrom(s, buf.get_ptr(), len, flags, &_addr, &_paddrlen);
s32 ret = ::recvfrom(sock->s, buf.get_ptr(), len, flags, &_addr, &_paddrlen);
*paddrlen = _paddrlen;
if (ret < 0)
@ -419,9 +453,9 @@ namespace sys_net
s32 send(s32 s, vm::cptr<char> buf, u32 len, s32 flags)
{
libnet.warning("send(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
s32 ret = ::send(s, buf.get_ptr(), len, flags);
s32 ret = ::send(sock->s, buf.get_ptr(), len, flags);
if (ret < 0)
{
@ -441,12 +475,12 @@ namespace sys_net
s32 sendto(s32 s, vm::cptr<char> buf, u32 len, s32 flags, vm::ptr<sockaddr> addr, u32 addrlen)
{
libnet.warning("sendto(s=%d, buf=*0x%x, len=%d, flags=0x%x, addr=*0x%x, addrlen=%d)", s, buf, len, flags, addr, addrlen);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
::sockaddr _addr;
memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr));
_addr.sa_family = addr->sa_family;
s32 ret = ::sendto(s, buf.get_ptr(), len, flags, &_addr, addrlen);
s32 ret = ::sendto(sock->s, buf.get_ptr(), len, flags, &_addr, addrlen);
if (ret < 0)
{
@ -460,7 +494,7 @@ namespace sys_net
s32 setsockopt(s32 s, s32 level, s32 optname, vm::cptr<void> optval, u32 optlen)
{
libnet.warning("setsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=%d)", s, level, optname, optval, optlen);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
if (level != SOL_SOCKET && level != IPPROTO_TCP)
{
@ -477,7 +511,7 @@ namespace sys_net
case OP_SO_NBIO:
{
unsigned long mode = *(unsigned long*)optval.get_ptr();
ret = ioctlsocket(s, FIONBIO, &mode);
ret = ioctlsocket(sock->s, FIONBIO, &mode);
break;
}
@ -492,7 +526,7 @@ namespace sys_net
case OP_TCP_NODELAY:
{
const char delay = *(char*)optval.get_ptr();
ret = ::setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &delay, sizeof(delay));
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, sizeof(delay));
break;
}
@ -525,7 +559,7 @@ namespace sys_net
flags = mode ? (flags &~O_NONBLOCK) : (flags | O_NONBLOCK);
// Re-set the flags
ret = fcntl(s, F_SETFL, flags);
ret = fcntl(sock->s, F_SETFL, flags);
break;
}
@ -540,14 +574,14 @@ namespace sys_net
case OP_TCP_NODELAY:
{
u32 delay = *(u32*)optval.get_ptr();
ret = ::setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &delay, optlen);
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, optlen);
break;
}
case OP_TCP_MAXSEG:
{
u32 maxseg = *(u32*)optval.get_ptr();
ret = ::setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &maxseg, optlen);
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_MAXSEG, &maxseg, optlen);
break;
}
@ -569,10 +603,15 @@ namespace sys_net
s32 shutdown(s32 s, s32 how)
{
libnet.warning("shutdown(s=%d, how=%d)", s, how);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
s32 ret = ::shutdown(s, how);
get_errno() = get_last_error();
s32 ret = ::shutdown(sock->s, how);
if (ret != 0)
{
libnet.error("shutdown(): error %d", get_errno() = get_last_error());
return -1;
}
return ret;
}
@ -591,14 +630,16 @@ namespace sys_net
// But what's the usage of it anyways?
if (type == SOCK_STREAM_P2P)
{
libnet.warning("SOCK_STREAM_P2P is not properly implemented.");
type = SOCK_STREAM;
}
else if (type == SOCK_DGRAM_P2P)
{
libnet.warning("SOCK_DGRAM_P2P is not properly implemented.");
type = SOCK_DGRAM;
}
s32 sock = ::socket(family, type, protocol);
socket_t sock = ::socket(family, type, protocol);
if (sock < 0)
{
@ -606,19 +647,18 @@ namespace sys_net
return -1;
}
g_socketMap.push_back(sock);
return g_socketMap.size() - 1;
return idm::make<sys_net_socket>(sock);
}
s32 socketclose(s32 s)
{
libnet.warning("socketclose(s=%d)", s);
s = g_socketMap[s];
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
#ifdef _WIN32
s32 ret = ::closesocket(s);
s32 ret = ::closesocket(sock->s);
#else
s32 ret = ::close(s);
s32 ret = ::close(sock->s);
#endif
if (ret != 0)
@ -627,6 +667,9 @@ namespace sys_net
return -1;
}
idm::get<sys_net_socket>(s)->s = -1;
idm::remove<sys_net_socket>(s);
return ret;
}
@ -670,7 +713,8 @@ namespace sys_net
}
#endif
s32 ret = ::select(g_socketMap[nfds], &_readfds, &_writefds, &_exceptfds, timeout ? &_timeout : nullptr);
// There's no good way to determine nfds and it shouldn't be too slow, so let's let it check the whole set. It also isn't used on Windows.
s32 ret = ::select(FD_SETSIZE, &_readfds, &_writefds, &_exceptfds, timeout ? &_timeout : nullptr);
if (ret < 0)
{
@ -685,16 +729,6 @@ namespace sys_net
{
libnet.warning("sys_net_initialize_network_ex(param=*0x%x)", param);
#ifdef _WIN32
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)
{
throw EXCEPTION("sys_net: WSAStartup unsuccessful");
}
#endif
// Errno is set to 0 upon initialization
get_errno() = 0;
@ -825,10 +859,6 @@ namespace sys_net
{
libnet.warning("sys_net_finalize_network()");
#ifdef _WIN32
WSACleanup();
#endif
// Errno is set to SYS_NET_EBUSY after finalization
get_errno() = SYS_NET_EBUSY;

View file

@ -254,9 +254,14 @@ Rpcs3App::Rpcs3App()
#ifdef _WIN32
timeBeginPeriod(1);
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
std::atexit([]
{
timeEndPeriod(1);
WSACleanup();
});
#endif