|
|
@ -312,7 +312,7 @@ void BSD::Listen(HLERequestContext& ctx) { |
|
|
void BSD::Fcntl(HLERequestContext& ctx) { |
|
|
void BSD::Fcntl(HLERequestContext& ctx) { |
|
|
IPC::RequestParser rp{ctx}; |
|
|
IPC::RequestParser rp{ctx}; |
|
|
const s32 fd = rp.Pop<s32>(); |
|
|
const s32 fd = rp.Pop<s32>(); |
|
|
const s32 cmd = rp.Pop<s32>(); |
|
|
|
|
|
|
|
|
const u32 cmd = rp.Pop<u32>(); |
|
|
const s32 arg = rp.Pop<s32>(); |
|
|
const s32 arg = rp.Pop<s32>(); |
|
|
|
|
|
|
|
|
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg); |
|
|
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg); |
|
|
@ -627,23 +627,41 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { |
|
|
|
|
|
|
|
|
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { |
|
|
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { |
|
|
if (!IsFileDescriptorValid(fd)) { |
|
|
if (!IsFileDescriptorValid(fd)) { |
|
|
|
|
|
LOG_ERROR(Service, "Bind failed: Invalid fd={}", fd); |
|
|
return Errno::BADF; |
|
|
return Errno::BADF; |
|
|
} |
|
|
} |
|
|
ASSERT(addr.size() == sizeof(SockAddrIn)); |
|
|
ASSERT(addr.size() == sizeof(SockAddrIn)); |
|
|
auto addr_in = GetValue<SockAddrIn>(addr); |
|
|
auto addr_in = GetValue<SockAddrIn>(addr); |
|
|
|
|
|
|
|
|
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); |
|
|
|
|
|
|
|
|
LOG_INFO(Service, "Bind fd={} to {}:{}", fd, Network::IPv4AddressToString(addr_in.ip), |
|
|
|
|
|
addr_in.portno); |
|
|
|
|
|
|
|
|
|
|
|
const auto result = Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); |
|
|
|
|
|
if (result != Errno::SUCCESS) { |
|
|
|
|
|
LOG_ERROR(Service, "Bind fd={} failed with errno={}", fd, static_cast<int>(result)); |
|
|
|
|
|
} |
|
|
|
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { |
|
|
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { |
|
|
if (!IsFileDescriptorValid(fd)) { |
|
|
if (!IsFileDescriptorValid(fd)) { |
|
|
|
|
|
LOG_ERROR(Service, "Connect failed: Invalid fd={}", fd); |
|
|
return Errno::BADF; |
|
|
return Errno::BADF; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); |
|
|
UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); |
|
|
auto addr_in = GetValue<SockAddrIn>(addr); |
|
|
auto addr_in = GetValue<SockAddrIn>(addr); |
|
|
|
|
|
|
|
|
return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); |
|
|
|
|
|
|
|
|
LOG_INFO(Service, "Connect fd={} to {}:{}", fd, Network::IPv4AddressToString(addr_in.ip), |
|
|
|
|
|
addr_in.portno); |
|
|
|
|
|
|
|
|
|
|
|
const auto result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); |
|
|
|
|
|
if (result != Errno::SUCCESS) { |
|
|
|
|
|
LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast<int>(result)); |
|
|
|
|
|
} else { |
|
|
|
|
|
LOG_INFO(Service, "Connect fd={} succeeded", fd); |
|
|
|
|
|
} |
|
|
|
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { |
|
|
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { |
|
|
@ -719,8 +737,8 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (level != static_cast<u32>(SocketLevel::SOCKET)) { |
|
|
if (level != static_cast<u32>(SocketLevel::SOCKET)) { |
|
|
UNIMPLEMENTED_MSG("Unknown getsockopt level"); |
|
|
|
|
|
return Errno::SUCCESS; |
|
|
|
|
|
|
|
|
LOG_WARNING(Service, "(STUBBED) Unknown getsockopt level={}, returning INVAL", level); |
|
|
|
|
|
return Errno::INVAL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); |
|
|
Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); |
|
|
@ -750,32 +768,52 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (level != static_cast<u32>(SocketLevel::SOCKET)) { |
|
|
if (level != static_cast<u32>(SocketLevel::SOCKET)) { |
|
|
UNIMPLEMENTED_MSG("Unknown setsockopt level"); |
|
|
|
|
|
return Errno::SUCCESS; |
|
|
|
|
|
|
|
|
LOG_WARNING(Service, "(STUBBED) Unknown setsockopt level={}, returning INVAL", level); |
|
|
|
|
|
return Errno::INVAL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); |
|
|
Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); |
|
|
|
|
|
|
|
|
if (optname == OptName::LINGER) { |
|
|
if (optname == OptName::LINGER) { |
|
|
ASSERT(optval.size() == sizeof(Linger)); |
|
|
|
|
|
|
|
|
if (optval.size() != sizeof(Linger)) { |
|
|
|
|
|
LOG_WARNING(Service, "LINGER optval size mismatch: expected {}, got {}", sizeof(Linger), |
|
|
|
|
|
optval.size()); |
|
|
|
|
|
return Errno::INVAL; |
|
|
|
|
|
} |
|
|
auto linger = GetValue<Linger>(optval); |
|
|
auto linger = GetValue<Linger>(optval); |
|
|
ASSERT(linger.onoff == 0 || linger.onoff == 1); |
|
|
|
|
|
|
|
|
if (linger.onoff != 0 && linger.onoff != 1) { |
|
|
|
|
|
LOG_WARNING(Service, "Invalid LINGER onoff value: {}", linger.onoff); |
|
|
|
|
|
return Errno::INVAL; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); |
|
|
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASSERT(optval.size() == sizeof(u32)); |
|
|
|
|
|
|
|
|
if (optval.size() != sizeof(u32)) { |
|
|
|
|
|
LOG_WARNING(Service, "optval size mismatch: expected {}, got {} for optname={}", sizeof(u32), |
|
|
|
|
|
optval.size(), static_cast<u32>(optname)); |
|
|
|
|
|
return Errno::INVAL; |
|
|
|
|
|
} |
|
|
auto value = GetValue<u32>(optval); |
|
|
auto value = GetValue<u32>(optval); |
|
|
|
|
|
|
|
|
switch (optname) { |
|
|
switch (optname) { |
|
|
case OptName::REUSEADDR: |
|
|
case OptName::REUSEADDR: |
|
|
ASSERT(value == 0 || value == 1); |
|
|
|
|
|
|
|
|
if (value != 0 && value != 1) { |
|
|
|
|
|
LOG_WARNING(Service, "Invalid REUSEADDR value: {}", value); |
|
|
|
|
|
return Errno::INVAL; |
|
|
|
|
|
} |
|
|
return Translate(socket->SetReuseAddr(value != 0)); |
|
|
return Translate(socket->SetReuseAddr(value != 0)); |
|
|
case OptName::KEEPALIVE: |
|
|
case OptName::KEEPALIVE: |
|
|
ASSERT(value == 0 || value == 1); |
|
|
|
|
|
|
|
|
if (value != 0 && value != 1) { |
|
|
|
|
|
LOG_WARNING(Service, "Invalid KEEPALIVE value: {}", value); |
|
|
|
|
|
return Errno::INVAL; |
|
|
|
|
|
} |
|
|
return Translate(socket->SetKeepAlive(value != 0)); |
|
|
return Translate(socket->SetKeepAlive(value != 0)); |
|
|
case OptName::BROADCAST: |
|
|
case OptName::BROADCAST: |
|
|
ASSERT(value == 0 || value == 1); |
|
|
|
|
|
|
|
|
if (value != 0 && value != 1) { |
|
|
|
|
|
LOG_WARNING(Service, "Invalid BROADCAST value: {}", value); |
|
|
|
|
|
return Errno::INVAL; |
|
|
|
|
|
} |
|
|
return Translate(socket->SetBroadcast(value != 0)); |
|
|
return Translate(socket->SetBroadcast(value != 0)); |
|
|
case OptName::SNDBUF: |
|
|
case OptName::SNDBUF: |
|
|
return Translate(socket->SetSndBuf(value)); |
|
|
return Translate(socket->SetSndBuf(value)); |
|
|
@ -789,8 +827,9 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8 |
|
|
LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value); |
|
|
LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value); |
|
|
return Errno::SUCCESS; |
|
|
return Errno::SUCCESS; |
|
|
default: |
|
|
default: |
|
|
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname); |
|
|
|
|
|
return Errno::SUCCESS; |
|
|
|
|
|
|
|
|
LOG_WARNING(Service, "(STUBBED) Unimplemented optname={} (0x{:x}), returning INVAL", |
|
|
|
|
|
static_cast<u32>(optname), static_cast<u32>(optname)); |
|
|
|
|
|
return Errno::INVAL; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|