diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp index 2cb5fb0164..cd25283e1a 100644 --- a/Source/Core/Core/IOS/Network/IP/Top.cpp +++ b/Source/Core/Core/IOS/Network/IP/Top.cpp @@ -290,7 +290,7 @@ IPCCommandResult NetIPTop::HandleShutdownRequest(const IOCtlRequest& request) u32 fd = Memory::Read_U32(request.buffer_in); u32 how = Memory::Read_U32(request.buffer_in + 4); - int ret = shutdown(fd, how); + int ret = shutdown(WiiSockMan::GetInstance().GetHostSocket(fd), how); return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false)); } @@ -299,7 +299,7 @@ IPCCommandResult NetIPTop::HandleListenRequest(const IOCtlRequest& request) { u32 fd = Memory::Read_U32(request.buffer_in); u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04); - u32 ret = listen(fd, BACKLOG); + u32 ret = listen(WiiSockMan::GetInstance().GetHostSocket(fd), BACKLOG); request.Log(GetDeviceName(), LogTypes::IOS_WC24); return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false)); @@ -320,7 +320,8 @@ IPCCommandResult NetIPTop::HandleGetSockOptRequest(const IOCtlRequest& request) u8 optval[20]; u32 optlen = 4; - int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen); + int ret = getsockopt(WiiSockMan::GetInstance().GetHostSocket(fd), nat_level, nat_optname, + (char*)&optval, (socklen_t*)&optlen); const s32 return_value = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false); Memory::Write_U32(optlen, request.buffer_out + 0xC); @@ -366,7 +367,8 @@ IPCCommandResult NetIPTop::HandleSetSockOptRequest(const IOCtlRequest& request) int nat_level = MapWiiSockOptLevelToNative(level); int nat_optname = MapWiiSockOptNameToNative(optname); - int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen); + int ret = setsockopt(WiiSockMan::GetInstance().GetHostSocket(fd), nat_level, nat_optname, + (char*)optval, optlen); return GetDefaultReply(WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false)); } @@ -378,7 +380,7 @@ IPCCommandResult NetIPTop::HandleGetSockNameRequest(const IOCtlRequest& request) sockaddr sa; socklen_t sa_len = sizeof(sa); - int ret = getsockname(fd, &sa, &sa_len); + int ret = getsockname(WiiSockMan::GetInstance().GetHostSocket(fd), &sa, &sa_len); if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) WARN_LOG(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating"); @@ -402,7 +404,7 @@ IPCCommandResult NetIPTop::HandleGetPeerNameRequest(const IOCtlRequest& request) sockaddr sa; socklen_t sa_len = sizeof(sa); - int ret = getpeername(fd, &sa, &sa_len); + int ret = getpeername(WiiSockMan::GetInstance().GetHostSocket(fd), &sa, &sa_len); if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) WARN_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating"); @@ -555,7 +557,8 @@ IPCCommandResult NetIPTop::HandlePollRequest(const IOCtlRequest& request) for (int i = 0; i < nfds; ++i) { - ufds[i].fd = Memory::Read_U32(request.buffer_out + 0xc * i); // fd + s32 wii_fd = Memory::Read_U32(request.buffer_out + 0xc * i); + ufds[i].fd = WiiSockMan::GetInstance().GetHostSocket(wii_fd); // fd int events = Memory::Read_U32(request.buffer_out + 0xc * i + 4); // events ufds[i].revents = Memory::Read_U32(request.buffer_out + 0xc * i + 8); // revents @@ -571,7 +574,7 @@ IPCCommandResult NetIPTop::HandlePollRequest(const IOCtlRequest& request) DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL(%d) " "Sock: %08x, Unknown: %08x, Events: %08x, " "NativeEvents: %08x", - i, ufds[i].fd, unknown, events, ufds[i].events); + i, wii_fd, unknown, events, ufds[i].events); // Do not pass return-only events to the native poll ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL); @@ -1009,10 +1012,11 @@ IPCCommandResult NetIPTop::HandleICMPPingRequest(const IOCtlVRequest& request) icmp_length = 22; } - int ret = icmp_echo_req(fd, &addr, data, icmp_length); + int ret = icmp_echo_req(WiiSockMan::GetInstance().GetHostSocket(fd), &addr, data, icmp_length); if (ret == icmp_length) { - ret = icmp_echo_rep(fd, &addr, (u32)timeout, icmp_length); + ret = icmp_echo_rep(WiiSockMan::GetInstance().GetHostSocket(fd), &addr, + static_cast(timeout), icmp_length); } // TODO proper error codes diff --git a/Source/Core/Core/IOS/Network/SSL.cpp b/Source/Core/Core/IOS/Network/SSL.cpp index ca3160bee8..ef826a7a58 100644 --- a/Source/Core/Core/IOS/Network/SSL.cpp +++ b/Source/Core/Core/IOS/Network/SSL.cpp @@ -424,8 +424,10 @@ IPCCommandResult NetSSL::IOCtlV(const IOCtlVRequest& request) WII_SSL* ssl = &_SSL[sslID]; mbedtls_ssl_setup(&ssl->ctx, &ssl->config); ssl->sockfd = Memory::Read_U32(BufferOut2); + WiiSockMan& sm = WiiSockMan::GetInstance(); + ssl->hostfd = sm.GetHostSocket(ssl->sockfd); INFO_LOG(IOS_SSL, "IOCTLV_NET_SSL_CONNECT socket = %d", ssl->sockfd); - mbedtls_ssl_set_bio(&ssl->ctx, &ssl->sockfd, mbedtls_net_send, mbedtls_net_recv, nullptr); + mbedtls_ssl_set_bio(&ssl->ctx, &ssl->hostfd, mbedtls_net_send, mbedtls_net_recv, nullptr); Memory::Write_U32(SSL_OK, BufferIn); } else diff --git a/Source/Core/Core/IOS/Network/SSL.h b/Source/Core/Core/IOS/Network/SSL.h index f1f9f4c611..c1253e8189 100644 --- a/Source/Core/Core/IOS/Network/SSL.h +++ b/Source/Core/Core/IOS/Network/SSL.h @@ -81,6 +81,7 @@ struct WII_SSL mbedtls_x509_crt clicert; mbedtls_pk_context pk; int sockfd; + int hostfd; std::string hostname; bool active; }; diff --git a/Source/Core/Core/IOS/Network/Socket.cpp b/Source/Core/Core/IOS/Network/Socket.cpp index 1698eed629..02ea7126d4 100644 --- a/Source/Core/Core/IOS/Network/Socket.cpp +++ b/Source/Core/Core/IOS/Network/Socket.cpp @@ -25,12 +25,15 @@ #else #define ERRORCODE(name) name #define EITHER(win32, posix) posix +#define closesocket close #endif namespace IOS { namespace HLE { +constexpr int WII_SOCKET_FD_MAX = 24; + char* WiiSockMan::DecodeError(s32 ErrorCode) { #ifdef _WIN32 @@ -77,6 +80,11 @@ static s32 TranslateErrorCode(s32 native_error, bool isRW) return -SO_ENETUNREACH; case ERRORCODE(EHOSTUNREACH): return -SO_EHOSTUNREACH; + case ENOMEM: // See man (7) ip + case ERRORCODE(ENOBUFS): + return -SO_ENOMEM; + case ERRORCODE(ENETRESET): + return -SO_ENETRESET; case EITHER(WSAEWOULDBLOCK, EAGAIN): if (isRW) { @@ -143,16 +151,17 @@ void WiiSocket::SetFd(s32 s) #endif } +void WiiSocket::SetWiiFd(s32 s) +{ + wii_fd = s; +} + s32 WiiSocket::CloseFd() { s32 ReturnValue = 0; if (fd >= 0) { -#ifdef _WIN32 s32 ret = closesocket(fd); -#else - s32 ret = close(fd); -#endif ReturnValue = WiiSockMan::GetNetErrorCode(ret, "CloseFd", false); } else @@ -186,7 +195,7 @@ s32 WiiSocket::FCntl(u32 cmd, u32 arg) ERROR_LOG(IOS_NET, "SO_FCNTL unknown command"); } - INFO_LOG(IOS_NET, "IOCTL_SO_FCNTL(%08x, %08X, %08X)", fd, cmd, arg); + INFO_LOG(IOS_NET, "IOCTL_SO_FCNTL(%08x, %08X, %08X)", wii_fd, cmd, arg); return ret; } @@ -220,8 +229,8 @@ void WiiSocket::Update(bool read, bool write, bool except) int ret = bind(fd, (sockaddr*)&local_name, sizeof(local_name)); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_BIND", false); - INFO_LOG(IOS_NET, "IOCTL_SO_BIND (%08X %s:%d) = %d", fd, inet_ntoa(local_name.sin_addr), - Common::swap16(local_name.sin_port), ret); + INFO_LOG(IOS_NET, "IOCTL_SO_BIND (%08X, %s:%d) = %d", wii_fd, + inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port), ret); break; } case IOCTL_SO_CONNECT: @@ -233,12 +242,13 @@ void WiiSocket::Update(bool read, bool write, bool except) int ret = connect(fd, (sockaddr*)&local_name, sizeof(local_name)); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_CONNECT", false); - INFO_LOG(IOS_NET, "IOCTL_SO_CONNECT (%08x, %s:%d) = %d", fd, inet_ntoa(local_name.sin_addr), - Common::swap16(local_name.sin_port), ret); + INFO_LOG(IOS_NET, "IOCTL_SO_CONNECT (%08x, %s:%d) = %d", wii_fd, + inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port), ret); break; } case IOCTL_SO_ACCEPT: { + s32 ret; if (ioctl.buffer_out_size > 0) { sockaddr_in local_name; @@ -246,18 +256,16 @@ void WiiSocket::Update(bool read, bool write, bool except) WiiSockMan::Convert(*wii_name, local_name); socklen_t addrlen = sizeof(sockaddr_in); - int ret = (s32)accept(fd, (sockaddr*)&local_name, &addrlen); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); + ret = static_cast(accept(fd, (sockaddr*)&local_name, &addrlen)); WiiSockMan::Convert(local_name, *wii_name, addrlen); } else { - int ret = (s32)accept(fd, nullptr, nullptr); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); + ret = static_cast(accept(fd, nullptr, nullptr)); } - WiiSockMan::GetInstance().AddSocket(ReturnValue); + ReturnValue = WiiSockMan::GetInstance().AddSocket(ret, true); ioctl.Log("IOCTL_SO_ACCEPT", LogTypes::IOS_NET); break; @@ -382,9 +390,10 @@ void WiiSocket::Update(bool read, bool write, bool except) } } - INFO_LOG(IOS_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", + INFO_LOG(IOS_SSL, + "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", ret, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); break; @@ -506,7 +515,7 @@ void WiiSocket::Update(bool read, bool write, bool except) DEBUG_LOG( IOS_NET, "%s = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u", - has_destaddr ? "IOCTLV_SO_SENDTO " : "IOCTLV_SO_SEND ", ReturnValue, fd, BufferIn, + has_destaddr ? "IOCTLV_SO_SENDTO " : "IOCTLV_SO_SEND ", ReturnValue, wii_fd, BufferIn, BufferInSize, BufferIn2, BufferInSize2, local_name.sin_addr.s_addr & 0xFF, (local_name.sin_addr.s_addr >> 8) & 0xFF, (local_name.sin_addr.s_addr >> 16) & 0xFF, (local_name.sin_addr.s_addr >> 24) & 0xFF); @@ -549,11 +558,12 @@ void WiiSocket::Update(bool read, bool write, bool except) ReturnValue = WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true); - INFO_LOG(IOS_NET, "%s(%d, %p) Socket: %08X, Flags: %08X, " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", + INFO_LOG(IOS_NET, + "%s(%d, %p) Socket: %08X, Flags: %08X, " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", BufferOutSize2 ? "IOCTLV_SO_RECVFROM " : "IOCTLV_SO_RECV ", ReturnValue, data, - fd, flags, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, + wii_fd, flags, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); if (BufferOutSize2 != 0) @@ -575,8 +585,8 @@ void WiiSocket::Update(bool read, bool write, bool except) (it->is_ssl && ReturnValue != SSL_ERR_WAGAIN && ReturnValue != SSL_ERR_RAGAIN)) { DEBUG_LOG(IOS_NET, - "IOCTL(V) Sock: %08x ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d", fd, - it->is_ssl ? (int)it->ssl_type : (int)it->net_type, ReturnValue, nonBlock, + "IOCTL(V) Sock: %08x ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d", + wii_fd, it->is_ssl ? (int)it->ssl_type : (int)it->net_type, ReturnValue, nonBlock, forceNonBlock); // TODO: remove the dependency on a running IOS instance. @@ -604,26 +614,61 @@ void WiiSocket::DoSock(Request request, SSL_IOCTL type) pending_sockops.push_back(so); } -void WiiSockMan::AddSocket(s32 fd) +s32 WiiSockMan::AddSocket(s32 fd, bool is_rw) { - if (fd >= 0) + const char* caller = is_rw ? "SO_ACCEPT" : "NewSocket"; + + if (fd < 0) + return GetNetErrorCode(fd, caller, is_rw); + + s32 wii_fd; + for (wii_fd = 0; wii_fd < WII_SOCKET_FD_MAX; ++wii_fd) { - WiiSocket& sock = WiiSockets[fd]; - sock.SetFd(fd); + // Find an available socket fd + if (WiiSockets.count(wii_fd) == 0) + break; } + + if (wii_fd == WII_SOCKET_FD_MAX) + { + // Close host socket + closesocket(fd); + wii_fd = -SO_EMFILE; + ERROR_LOG(IOS_NET, "%s failed: Too many open sockets, ret=%d", caller, wii_fd); + } + else + { + WiiSocket& sock = WiiSockets[wii_fd]; + sock.SetFd(fd); + sock.SetWiiFd(wii_fd); + } + + SetLastNetError(wii_fd); + return wii_fd; } s32 WiiSockMan::NewSocket(s32 af, s32 type, s32 protocol) { - s32 fd = (s32)socket(af, type, protocol); - s32 ret = GetNetErrorCode(fd, "NewSocket", false); - AddSocket(ret); - return ret; + if (af != 2 && af != 23) // AF_INET && AF_INET6 + return -SO_EAFNOSUPPORT; + if (protocol != 0) // IPPROTO_IP + return -SO_EPROTONOSUPPORT; + if (type != 1 && type != 2) // SOCK_STREAM && SOCK_DGRAM + return -SO_EPROTOTYPE; + s32 fd = static_cast(socket(af, type, protocol)); + return AddSocket(fd, false); +} + +s32 WiiSockMan::GetHostSocket(s32 wii_fd) const +{ + if (WiiSockets.count(wii_fd) > 0) + return WiiSockets.at(wii_fd).fd; + return -EBADF; } s32 WiiSockMan::DeleteSocket(s32 s) { - s32 ReturnValue = EBADF; + s32 ReturnValue = -SO_EBADF; auto socket_entry = WiiSockets.find(s); if (socket_entry != WiiSockets.end()) { @@ -694,7 +739,7 @@ void WiiSockMan::Convert(sockaddr_in const& from, WiiSockAddrIn& to, s32 addrlen to.addr.addr = from.sin_addr.s_addr; to.family = from.sin_family & 0xFF; to.port = from.sin_port; - if (addrlen < 0 || addrlen > (s32)sizeof(WiiSockAddrIn)) + if (addrlen < 0 || addrlen > static_cast(sizeof(WiiSockAddrIn))) to.len = sizeof(WiiSockAddrIn); else to.len = addrlen; diff --git a/Source/Core/Core/IOS/Network/Socket.h b/Source/Core/Core/IOS/Network/Socket.h index de9d4b4761..aa503c1f75 100644 --- a/Source/Core/Core/IOS/Network/Socket.h +++ b/Source/Core/Core/IOS/Network/Socket.h @@ -187,11 +187,13 @@ class WiiSocket private: s32 fd; + s32 wii_fd; bool nonBlock; std::list pending_sockops; friend class WiiSockMan; void SetFd(s32 s); + void SetWiiFd(s32 s); s32 CloseFd(); s32 FCntl(u32 cmd, u32 arg); @@ -221,7 +223,8 @@ public: static void Convert(sockaddr_in const& from, WiiSockAddrIn& to, s32 addrlen = -1); // NON-BLOCKING FUNCTIONS s32 NewSocket(s32 af, s32 type, s32 protocol); - void AddSocket(s32 fd); + s32 AddSocket(s32 fd, bool is_rw); + s32 GetHostSocket(s32 wii_fd) const; s32 DeleteSocket(s32 s); s32 GetLastNetError() const { return errno_last; } void SetLastNetError(s32 error) { errno_last = error; }