diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp index 53fd9b2699..dfad83a9c7 100644 --- a/Source/Core/Core/IOS/Network/IP/Top.cpp +++ b/Source/Core/Core/IOS/Network/IP/Top.cpp @@ -404,13 +404,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) diff --git a/Source/Core/Core/IOS/Network/Socket.cpp b/Source/Core/Core/IOS/Network/Socket.cpp index 410db2db5a..184608f090 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(&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) || @@ -685,10 +739,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(); @@ -919,6 +981,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(); }