Socket: Abort pending operations on shutdown

This commit is contained in:
Sepalani 2020-04-22 22:41:19 +04:00
parent fb32f1ab88
commit c63ac38c83
3 changed files with 86 additions and 9 deletions

View File

@ -402,13 +402,19 @@ IPCCommandResult NetIPTop::HandleDoSockRequest(const IOCtlRequest& request)
IPCCommandResult NetIPTop::HandleShutdownRequest(const IOCtlRequest& request)
{
request.Log(GetDeviceName(), Common::Log::IOS_WC24);
if (request.buffer_in == 0 || request.buffer_in_size < 8)
{
ERROR_LOG(IOS_NET, "IOCTL_SO_SHUTDOWN = EINVAL, BufferIn: (%08x, %i)", request.buffer_in,
request.buffer_in_size);
return GetDefaultReply(-SO_EINVAL);
}
u32 fd = Memory::Read_U32(request.buffer_in);
u32 how = Memory::Read_U32(request.buffer_in + 4);
int ret = shutdown(WiiSockMan::GetInstance().GetHostSocket(fd), how);
return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false));
const u32 fd = Memory::Read_U32(request.buffer_in);
const u32 how = Memory::Read_U32(request.buffer_in + 4);
WiiSockMan& sm = WiiSockMan::GetInstance();
const s32 return_value = sm.ShutdownSocket(fd, how);
INFO_LOG(IOS_NET, "IOCTL_SO_SHUTDOWN(fd=%d, how=%d) = %d", fd, how, return_value);
return GetDefaultReply(return_value);
}
IPCCommandResult NetIPTop::HandleListenRequest(const IOCtlRequest& request)

View File

@ -156,6 +156,54 @@ void WiiSocket::SetWiiFd(s32 s)
wii_fd = s;
}
s32 WiiSocket::Shutdown(u32 how)
{
if (how > 2)
return -SO_EINVAL;
// The Wii does nothing and returns 0 for IP_PROTO_UDP
int so_type;
socklen_t opt_len = sizeof(so_type);
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, reinterpret_cast<char*>(&so_type), &opt_len) != 0 ||
(so_type != SOCK_STREAM && so_type != SOCK_DGRAM))
return -SO_EBADF;
if (so_type == SOCK_DGRAM)
return SO_SUCCESS;
// Adjust pending operations
// Values based on https://dolp.in/pr8758 hwtest
const s32 ret = WiiSockMan::GetNetErrorCode(shutdown(fd, how), "SO_SHUTDOWN", false);
const bool shut_read = how == 0 || how == 2;
const bool shut_write = how == 1 || how == 2;
for (auto& op : pending_sockops)
{
// TODO: Create hwtest for SSL
if (op.is_ssl)
continue;
switch (op.net_type)
{
case IOCTL_SO_ACCEPT:
if (shut_write)
op.Abort(-SO_EINVAL);
break;
case IOCTL_SO_CONNECT:
if (shut_write && !nonBlock)
op.Abort(-SO_ENETUNREACH);
break;
case IOCTLV_SO_RECVFROM:
if (shut_read)
op.Abort(-SO_ENOTCONN);
break;
case IOCTLV_SO_SENDTO:
if (shut_write)
op.Abort(-SO_ENOTCONN);
break;
}
}
return ret;
}
s32 WiiSocket::CloseFd()
{
s32 ReturnValue = 0;
@ -586,6 +634,12 @@ void WiiSocket::Update(bool read, bool write, bool except)
}
}
if (it->is_aborted)
{
it = pending_sockops.erase(it);
continue;
}
if (nonBlock || forceNonBlock ||
(!it->is_ssl && ReturnValue != -SO_EAGAIN && ReturnValue != -SO_EINPROGRESS &&
ReturnValue != -SO_EALREADY) ||
@ -679,10 +733,18 @@ s32 WiiSockMan::GetHostSocket(s32 wii_fd) const
return -EBADF;
}
s32 WiiSockMan::DeleteSocket(s32 s)
s32 WiiSockMan::ShutdownSocket(s32 wii_fd, u32 how)
{
auto socket_entry = WiiSockets.find(wii_fd);
if (socket_entry != WiiSockets.end())
return socket_entry->second.Shutdown(how);
return -SO_EBADF;
}
s32 WiiSockMan::DeleteSocket(s32 wii_fd)
{
s32 ReturnValue = -SO_EBADF;
auto socket_entry = WiiSockets.find(s);
auto socket_entry = WiiSockets.find(wii_fd);
if (socket_entry != WiiSockets.end())
{
ReturnValue = socket_entry->second.CloseFd();
@ -913,6 +975,11 @@ void WiiSockMan::UpdateWantDeterminism(bool want)
Clean();
}
void WiiSocket::sockop::Abort(s32 value)
{
is_aborted = true;
GetIOS()->EnqueueIPCReply(request, value);
}
#undef ERRORCODE
#undef EITHER
} // namespace IOS::HLE

View File

@ -186,16 +186,19 @@ private:
{
Request request;
bool is_ssl;
bool is_aborted = false;
union
{
NET_IOCTL net_type;
SSL_IOCTL ssl_type;
};
void Abort(s32 value);
};
friend class WiiSockMan;
void SetFd(s32 s);
void SetWiiFd(s32 s);
s32 Shutdown(u32 how);
s32 CloseFd();
s32 FCntl(u32 cmd, u32 arg);
@ -246,7 +249,8 @@ public:
s32 AddSocket(s32 fd, bool is_rw);
bool IsSocketBlocking(s32 wii_fd) const;
s32 GetHostSocket(s32 wii_fd) const;
s32 DeleteSocket(s32 s);
s32 ShutdownSocket(s32 wii_fd, u32 how);
s32 DeleteSocket(s32 wii_fd);
s32 GetLastNetError() const { return errno_last; }
void SetLastNetError(s32 error) { errno_last = error; }
void Clean() { WiiSockets.clear(); }