Browse Source

allow configure socket level

lizzie/refactor-networking-12
lizzie 1 month ago
parent
commit
f4ab8fa3d8
  1. 33
      src/core/hle/service/sockets/bsd.cpp
  2. 4
      src/core/hle/service/sockets/bsd.h
  3. 152
      src/core/internal_network/network.cpp
  4. 2
      src/core/internal_network/socket_proxy.cpp
  5. 2
      src/core/internal_network/socket_proxy.h
  6. 4
      src/core/internal_network/socket_types.h
  7. 4
      src/core/internal_network/sockets.h

33
src/core/hle/service/sockets/bsd.cpp

@ -274,14 +274,12 @@ void BSD::GetSockName(HLERequestContext& ctx) {
void BSD::GetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>();
const auto optname = static_cast<Network::OptName>(rp.Pop<u32>());
const auto level = Network::SocketLevel(rp.Pop<u32>());
const auto optname = Network::OptName(rp.Pop<u32>());
std::vector<u8> optval(ctx.GetWriteBufferSize());
LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} len=0x{:x}", fd, level, optname,
optval.size());
LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} len=0x{:x}", fd, level, optname, optval.size());
const Network::Errno err = GetSockOptImpl(fd, level, optname, optval);
ctx.WriteBuffer(optval);
@ -323,7 +321,7 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>();
const Network::SocketLevel level = Network::SocketLevel(rp.Pop<u32>());
const Network::OptName optname = Network::OptName(rp.Pop<u32>());
const auto optval = ctx.ReadBuffer();
@ -526,7 +524,7 @@ std::pair<s32, Network::Errno> BSD::SocketImpl(Network::Domain domain, Network::
file_descriptors[fd].reset();
return {-1, Network::Errno::NOTCONN};
}
if (descriptor.socket->fd < 0) {
if (descriptor.socket->fd == Network::Socket::INVALID_SOCKET) {
file_descriptors[fd].reset();
return {-1, bsd_errno};
}
@ -741,7 +739,7 @@ std::pair<s32, Network::Errno> BSD::FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32
}
}
Network::Errno BSD::GetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::vector<u8>& optval) {
Network::Errno BSD::GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval) {
if (!IsFileDescriptorValid(fd)) {
return Network::Errno::BADF;
}
@ -750,9 +748,8 @@ Network::Errno BSD::GetSockOptImpl(s32 fd, u32 level, Network::OptName optname,
return Network::Errno::BADF;
}
if (level != static_cast<u32>(Network::SocketLevel::SOCKET)) {
UNIMPLEMENTED_MSG("Unknown getsockopt level");
return Network::Errno::SUCCESS;
if (level != Network::SocketLevel::SOCKET) {
LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname);
}
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
@ -775,7 +772,8 @@ Network::Errno BSD::GetSockOptImpl(s32 fd, u32 level, Network::OptName optname,
}
}
Network::Errno BSD::SetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::span<const u8> optval) {
Network::Errno BSD::SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
LOG_DEBUG(Service, "fd={},level={},optname={}", fd, level, optname);
if (!IsFileDescriptorValid(fd)) {
return Network::Errno::BADF;
}
@ -784,14 +782,11 @@ Network::Errno BSD::SetSockOptImpl(s32 fd, u32 level, Network::OptName optname,
return Network::Errno::BADF;
}
if (level != u32(Network::SocketLevel::SOCKET)) {
LOG_WARNING(Service, "(STUBBED) setsockopt with level={}, optname={}", level, optname);
return Network::Errno::SUCCESS;
}
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
ASSERT(optval.size() == sizeof(u32));
return socket->SetSockOpt(fd, optname, optval);
if (level != Network::SocketLevel::SOCKET) {
LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname);
}
return socket->SetSockOpt(fd, level, optname, optval);
}
Network::Errno BSD::ShutdownImpl(s32 fd, s32 how) {

4
src/core/hle/service/sockets/bsd.h

@ -164,8 +164,8 @@ private:
Network::Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
Network::Errno ListenImpl(s32 fd, s32 backlog);
std::pair<s32, Network::Errno> FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg);
Network::Errno GetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::vector<u8>& optval);
Network::Errno SetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::span<const u8> optval);
Network::Errno GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval);
Network::Errno SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval);
Network::Errno ShutdownImpl(s32 fd, s32 how);
std::pair<s32, Network::Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
std::pair<s32, Network::Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,

152
src/core/internal_network/network.cpp

@ -129,48 +129,30 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) {
} else {
return Errno::CONNABORTED;
}
case WSAEBADF:
return Errno::BADF;
case WSAEINVAL:
return Errno::INVAL;
case WSAEMFILE:
return Errno::MFILE;
case WSAENOTCONN:
return Errno::NOTCONN;
case WSAEWOULDBLOCK:
return Errno::AGAIN;
case WSAECONNREFUSED:
return Errno::CONNREFUSED;
case WSAECONNRESET:
return Errno::CONNRESET;
case WSAEHOSTUNREACH:
return Errno::HOSTUNREACH;
case WSAENETDOWN:
return Errno::NETDOWN;
case WSAENETUNREACH:
return Errno::NETUNREACH;
case WSAEMSGSIZE:
return Errno::MSGSIZE;
case WSAETIMEDOUT:
return Errno::TIMEDOUT;
case WSAEINPROGRESS:
return Errno::INPROGRESS;
case WSAEISCONN:
return Errno::ISCONN;
case WSAEADDRINUSE:
return Errno::ADDRINUSE;
case WSAEADDRNOTAVAIL:
return Errno::ADDRNOTAVAIL;
case WSAEPROTOTYPE:
return Errno::PROTOTYPE;
case WSAENOPROTOOPT:
return Errno::NOPROTOOPT;
case WSAEPROTONOSUPPORT:
return Errno::PROTONOSUPPORT;
case WSAESOCKTNOSUPPORT:
return Errno::SOCKTNOSUPPORT;
case WSAENOTSUP:
return Errno::NOTSUP;
case WSAEBADF: return Errno::BADF;
case WSAEINVAL: return Errno::INVAL;
case WSAEMFILE: return Errno::MFILE;
case WSAENOTCONN: return Errno::NOTCONN;
case WSAEWOULDBLOCK: return Errno::AGAIN;
case WSAECONNREFUSED: return Errno::CONNREFUSED;
case WSAECONNRESET: return Errno::CONNRESET;
case WSAEHOSTUNREACH: return Errno::HOSTUNREACH;
case WSAENETDOWN: return Errno::NETDOWN;
case WSAENETUNREACH: return Errno::NETUNREACH;
case WSAEMSGSIZE: return Errno::MSGSIZE;
case WSAETIMEDOUT: return Errno::TIMEDOUT;
case WSAEINPROGRESS: return Errno::INPROGRESS;
case WSAEISCONN: return Errno::ISCONN;
case WSAEADDRINUSE: return Errno::ADDRINUSE;
case WSAEADDRNOTAVAIL: return Errno::ADDRNOTAVAIL;
case WSAEPROTOTYPE: return Errno::PROTOTYPE;
case WSAENOPROTOOPT: return Errno::NOPROTOOPT;
case WSAEPROTONOSUPPORT: return Errno::PROTONOSUPPORT;
case WSAESOCKTNOSUPPORT: return Errno::SOCKTNOSUPPORT;
#ifdef WSAENOTSUP
// Not defined by fucking MSVC because MSVC is stupid as shitfuckery
case WSAENOTSUP: return Errno::NOTSUP;
#endif
default:
UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
return Errno::OTHER;
@ -257,7 +239,7 @@ int closesocket(SOCKET fd) {
}
linger MakeLinger(bool enable, u32 linger_value) {
linger value;
linger value{};
value.l_onoff = enable ? 1 : 0;
value.l_linger = linger_value;
return value;
@ -302,7 +284,8 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) {
NETWORK_ERROR_ELEM(SOCKTNOSUPPORT) \
NETWORK_ERROR_ELEM(NOTSUP) \
NETWORK_ERROR_ELEM(ADDRINUSE) \
NETWORK_ERROR_ELEM(ADDRNOTAVAIL)
NETWORK_ERROR_ELEM(ADDRNOTAVAIL) \
NETWORK_ERROR_ELEM(NOTSOCK)
#define NETWORK_ERROR_ELEM(name) case E##name: return Errno::name;
NETWORK_ERROR_LIST
#undef NETWORK_ERROR_ELEM
@ -945,35 +928,30 @@ std::pair<T, Errno> Socket::GetSockOpt(SOCKET fd_so, int option) {
static s32 TranslateOptNameToNative(Network::OptName optname) {
switch (optname) {
case Network::OptName::LINGER:
return SO_LINGER;
case Network::OptName::REUSEADDR:
return SO_REUSEADDR;
case Network::OptName::KEEPALIVE:
return SO_KEEPALIVE;
case Network::OptName::BROADCAST:
return SO_BROADCAST;
case Network::OptName::SNDBUF:
return SO_SNDBUF;
case Network::OptName::RCVBUF:
return SO_RCVBUF;
case Network::OptName::SNDTIMEO:
return SO_SNDTIMEO;
case Network::OptName::RCVTIMEO:
return SO_RCVTIMEO;
case Network::OptName::NOSIGPIPE:
return SO_NOSIGPIPE;
// managarm doesn't like these
#ifdef SO_DEBUG
case Network::OptName::DEBUG: return SO_DEBUG;
#endif
#ifdef SO_ACCEPTCONN
case Network::OptName::ACCEPTCONN: return SO_ACCEPTCONN;
#endif
case Network::OptName::LINGER: return SO_LINGER;
case Network::OptName::REUSEADDR: return SO_REUSEADDR;
case Network::OptName::KEEPALIVE: return SO_KEEPALIVE;
case Network::OptName::BROADCAST: return SO_BROADCAST;
case Network::OptName::SNDBUF: return SO_SNDBUF;
case Network::OptName::RCVBUF: return SO_RCVBUF;
case Network::OptName::SNDTIMEO: return SO_SNDTIMEO;
case Network::OptName::RCVTIMEO: return SO_RCVTIMEO;
case Network::OptName::NOSIGPIPE: return SO_NOSIGPIPE;
#ifdef SO_REUSEPORT
case Network::OptName::REUSEPORT:
return SO_REUSEPORT;
case Network::OptName::REUSEPORT: return SO_REUSEPORT;
#endif
#ifdef SO_ACCEPTFILTER
case Network::OptName::ACCEPTFILTER:
return SO_ACCEPTFILTER;
case Network::OptName::ACCEPTFILTER: return SO_ACCEPTFILTER;
#endif
#ifdef SO_TIMESTAMP
case Network::OptName::TIMESTAMP:
return SO_TIMESTAMP;
case Network::OptName::TIMESTAMP: return SO_TIMESTAMP;
#endif
default:
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
@ -981,6 +959,30 @@ static s32 TranslateOptNameToNative(Network::OptName optname) {
}
}
static s32 TranslateSocketLevelToNative(Network::SocketLevel level) {
switch (level) {
case Network::SocketLevel::SOCKET: return SOL_SOCKET;
// FreeBSD doesn't define below but Linux does :-(
#ifdef SOL_IP
case Network::SocketLevel::IP: return SOL_IP;
#endif
#ifdef SOL_ICMP
case Network::SocketLevel::ICMP: return SOL_ICMP;
#endif
#ifdef SOL_TCP
case Network::SocketLevel::TCP: return SOL_TCP;
#endif
#ifdef SOL_UDP
case Network::SocketLevel::UDP: return SOL_UDP;
#endif
#ifdef SOL_CONFIG
case Network::SocketLevel::CONFIG: return SOL_CONFIG;
#endif
default:
UNIMPLEMENTED_MSG("Unimplemented level={}", level);
return SOL_SOCKET;
}
}
Errno Socket::SetNonBlock(bool enable) {
if (EnableNonBlock(fd, enable)) {
@ -990,29 +992,27 @@ Errno Socket::SetNonBlock(bool enable) {
return GetAndLogLastError();
}
Errno Socket::SetSockOpt(SOCKET fd_so, Network::OptName optname, std::span<const u8> optval) {
Errno Socket::SetSockOpt(SOCKET fd_so, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
auto const native_level = TranslateSocketLevelToNative(level);
auto const native_optname = TranslateOptNameToNative(optname);
// TODO: is it >= or ==? for sizes
if (optname == Network::OptName::LINGER) {
if (optval.size() >= sizeof(Network::Linger)) {
Network::Linger linger{};
std::memcpy(&linger, optval.data(), sizeof(linger));
auto const linkger_optval = MakeLinger(bool(linger.onoff), linger.linger);
return setsockopt(fd_so, SOL_SOCKET, TranslateOptNameToNative(optname), reinterpret_cast<const char*>(linkger_optval.data()), socklen_t(linkger_optval.size())) != SOCKET_ERROR
auto const linger_optval = MakeLinger(bool(linger.onoff), linger.linger);
return setsockopt(fd_so, native_level, native_optname, reinterpret_cast<const char*>(&linger_optval), sizeof(linger_optval)) != SOCKET_ERROR
? Errno::SUCCESS
: GetAndLogLastError();
}
return Errno::INVAL;
}
return setsockopt(fd_so, SOL_SOCKET, TranslateOptNameToNative(optname), reinterpret_cast<const char*>(optval.data()), socklen_t(optval.size())) != SOCKET_ERROR
return setsockopt(fd_so, native_level, native_optname, reinterpret_cast<const char*>(optval.data()), socklen_t(optval.size())) != SOCKET_ERROR
? Errno::SUCCESS
: GetAndLogLastError();
}
Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
if (type == Type::STREAM && protocol == Protocol::UDP) {
LOG_WARNING(Network, "UDP used with STREAM");
type = Type::DGRAM;
}
fd = socket(TranslateDomainToNative(domain), TranslateTypeToNative(type), TranslateProtocolToNative(protocol));
if (fd != INVALID_SOCKET)
return Errno::SUCCESS;

2
src/core/internal_network/socket_proxy.cpp

@ -52,7 +52,7 @@ Errno ProxySocket::SetNonBlock(bool enable) {
return Errno::SUCCESS;
}
Errno ProxySocket::SetSockOpt(SOCKET fd_, Network::OptName option, std::span<const u8> optval) {
Errno ProxySocket::SetSockOpt(SOCKET fd_, Network::SocketLevel level, Network::OptName option, std::span<const u8> optval) {
LOG_DEBUG(Network, "(stubbed) called");
// numeric values?
if (optval.size() >= sizeof(u32)) {

2
src/core/internal_network/socket_proxy.h

@ -57,7 +57,7 @@ public:
Errno SetNonBlock(bool enable) override;
Errno SetSockOpt(SOCKET fd, Network::OptName option, std::span<const u8> value) override;
Errno SetSockOpt(SOCKET fd, Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
std::pair<Errno, Errno> GetPendingError() override;

4
src/core/internal_network/socket_types.h

@ -25,6 +25,7 @@ enum class Errno : u32 {
INVAL = 22,
MFILE = 24,
PIPE = 32,
NOTSOCK = 88,
MSGSIZE = 90,
PROTOTYPE = 91,
NOPROTOOPT = 92,
@ -234,7 +235,10 @@ enum class Protocol : u32 {
enum class SocketLevel : u32 {
IP = 0,
ICMP = 1,
TCP = 6,
UDP = 17,
CONFIG = 0xfffe,
SOCKET = 0xffff, // i.e. SOL_SOCKET
};

4
src/core/internal_network/sockets.h

@ -68,7 +68,7 @@ public:
virtual Errno SetNonBlock(bool enable) = 0;
virtual Errno SetSockOpt(SOCKET fd, Network::OptName option, std::span<const u8> value) = 0;
virtual Errno SetSockOpt(SOCKET fd, Network::SocketLevel level, Network::OptName option, std::span<const u8> value) = 0;
virtual std::pair<Errno, Errno> GetPendingError() = 0;
@ -120,7 +120,7 @@ public:
Errno SetNonBlock(bool enable) override;
Errno SetSockOpt(SOCKET fd, Network::OptName option, std::span<const u8> value) override;
Errno SetSockOpt(SOCKET fd, Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
std::pair<Errno, Errno> GetPendingError() override;

Loading…
Cancel
Save