summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorSepalani <sepalani@hotmail.fr>2020-04-22 22:41:19 +0400
committerSepalani <sepalani@hotmail.fr>2020-09-01 19:26:44 +0400
commitc63ac38c83137fe418cabfdedcc18abe94b6ebb5 (patch)
tree7faf3ac5ad46bc95302cab61bb75ff800299a89a /Source/Core
parentfb32f1ab88291cbf70e8decf990a64665b241bf0 (diff)
Socket: Abort pending operations on shutdown
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/IOS/Network/IP/Top.cpp18
-rw-r--r--Source/Core/Core/IOS/Network/Socket.cpp71
-rw-r--r--Source/Core/Core/IOS/Network/Socket.h6
3 files changed, 86 insertions, 9 deletions
diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp
index 2cd38142fd..fb6a96bd1f 100644
--- a/Source/Core/Core/IOS/Network/IP/Top.cpp
+++ b/Source/Core/Core/IOS/Network/IP/Top.cpp
@@ -402,13 +402,19 @@ IPCCommandResult NetIPTop::HandleDoSockRequest(const IOCtlRequest& request)
IPCCommandResult NetIPTop::HandleShutdownRequest(const IOCtlRequest& request)
{
- request.Log(GetDeviceName(), Common::Log::IOS_WC24);
-
- 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);
+ 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);
+ }
- 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)
diff --git a/Source/Core/Core/IOS/Network/Socket.cpp b/Source/Core/Core/IOS/Network/Socket.cpp
index ae8f2b08e3..1c59232607 100644
--- a/Source/Core/Core/IOS/Network/Socket.cpp
+++ b/Source/Core/Core/IOS/Network/Socket.cpp
@@ -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
diff --git a/Source/Core/Core/IOS/Network/Socket.h b/Source/Core/Core/IOS/Network/Socket.h
index 946130de53..01cb7745b9 100644
--- a/Source/Core/Core/IOS/Network/Socket.h
+++ b/Source/Core/Core/IOS/Network/Socket.h
@@ -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(); }