diff options
| author | 2023-09-13 15:40:58 -0400 | |
|---|---|---|
| committer | 2023-09-13 15:40:58 -0400 | |
| commit | 8fb9f78e834349f62dcf4ed72d9e960a31bed949 (patch) | |
| tree | 0cc3e5ab846b27b1569596a5368c998aca5728bc | |
| parent | Merge pull request #11486 from liamwhite/system-verification (diff) | |
| parent | internal_network: log error on interrupt pipe read failure (diff) | |
| download | yuzu-8fb9f78e834349f62dcf4ed72d9e960a31bed949.tar.gz yuzu-8fb9f78e834349f62dcf4ed72d9e960a31bed949.tar.xz yuzu-8fb9f78e834349f62dcf4ed72d9e960a31bed949.zip | |
Merge pull request #11385 from liamwhite/acceptcancel
internal_network: cancel pending socket operations on application process termination
| -rw-r--r-- | src/core/core.cpp | 2 | ||||
| -rw-r--r-- | src/core/internal_network/network.cpp | 89 | ||||
| -rw-r--r-- | src/core/internal_network/network.h | 3 |
3 files changed, 91 insertions, 3 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index f075ae7fa..2d6e61398 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -406,6 +406,7 @@ struct System::Impl { | |||
| 406 | gpu_core->NotifyShutdown(); | 406 | gpu_core->NotifyShutdown(); |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | Network::CancelPendingSocketOperations(); | ||
| 409 | kernel.SuspendApplication(true); | 410 | kernel.SuspendApplication(true); |
| 410 | if (services) { | 411 | if (services) { |
| 411 | services->KillNVNFlinger(); | 412 | services->KillNVNFlinger(); |
| @@ -427,6 +428,7 @@ struct System::Impl { | |||
| 427 | debugger.reset(); | 428 | debugger.reset(); |
| 428 | kernel.Shutdown(); | 429 | kernel.Shutdown(); |
| 429 | memory.Reset(); | 430 | memory.Reset(); |
| 431 | Network::RestartSocketOperations(); | ||
| 430 | 432 | ||
| 431 | if (auto room_member = room_network.GetRoomMember().lock()) { | 433 | if (auto room_member = room_network.GetRoomMember().lock()) { |
| 432 | Network::GameInfo game_info{}; | 434 | Network::GameInfo game_info{}; |
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 5d28300e6..a983f23ea 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp | |||
| @@ -48,15 +48,32 @@ enum class CallType { | |||
| 48 | 48 | ||
| 49 | using socklen_t = int; | 49 | using socklen_t = int; |
| 50 | 50 | ||
| 51 | SOCKET interrupt_socket = static_cast<SOCKET>(-1); | ||
| 52 | |||
| 53 | void InterruptSocketOperations() { | ||
| 54 | closesocket(interrupt_socket); | ||
| 55 | } | ||
| 56 | |||
| 57 | void AcknowledgeInterrupt() { | ||
| 58 | interrupt_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | ||
| 59 | } | ||
| 60 | |||
| 51 | void Initialize() { | 61 | void Initialize() { |
| 52 | WSADATA wsa_data; | 62 | WSADATA wsa_data; |
| 53 | (void)WSAStartup(MAKEWORD(2, 2), &wsa_data); | 63 | (void)WSAStartup(MAKEWORD(2, 2), &wsa_data); |
| 64 | |||
| 65 | AcknowledgeInterrupt(); | ||
| 54 | } | 66 | } |
| 55 | 67 | ||
| 56 | void Finalize() { | 68 | void Finalize() { |
| 69 | InterruptSocketOperations(); | ||
| 57 | WSACleanup(); | 70 | WSACleanup(); |
| 58 | } | 71 | } |
| 59 | 72 | ||
| 73 | SOCKET GetInterruptSocket() { | ||
| 74 | return interrupt_socket; | ||
| 75 | } | ||
| 76 | |||
| 60 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | 77 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { |
| 61 | sockaddr_in result; | 78 | sockaddr_in result; |
| 62 | 79 | ||
| @@ -157,9 +174,42 @@ constexpr int SD_RECEIVE = SHUT_RD; | |||
| 157 | constexpr int SD_SEND = SHUT_WR; | 174 | constexpr int SD_SEND = SHUT_WR; |
| 158 | constexpr int SD_BOTH = SHUT_RDWR; | 175 | constexpr int SD_BOTH = SHUT_RDWR; |
| 159 | 176 | ||
| 160 | void Initialize() {} | 177 | int interrupt_pipe_fd[2] = {-1, -1}; |
| 161 | 178 | ||
| 162 | void Finalize() {} | 179 | void Initialize() { |
| 180 | if (pipe(interrupt_pipe_fd) != 0) { | ||
| 181 | LOG_ERROR(Network, "Failed to create interrupt pipe!"); | ||
| 182 | } | ||
| 183 | int flags = fcntl(interrupt_pipe_fd[0], F_GETFL); | ||
| 184 | ASSERT_MSG(fcntl(interrupt_pipe_fd[0], F_SETFL, flags | O_NONBLOCK) == 0, | ||
| 185 | "Failed to set nonblocking state for interrupt pipe"); | ||
| 186 | } | ||
| 187 | |||
| 188 | void Finalize() { | ||
| 189 | if (interrupt_pipe_fd[0] >= 0) { | ||
| 190 | close(interrupt_pipe_fd[0]); | ||
| 191 | } | ||
| 192 | if (interrupt_pipe_fd[1] >= 0) { | ||
| 193 | close(interrupt_pipe_fd[1]); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | void InterruptSocketOperations() { | ||
| 198 | u8 value = 0; | ||
| 199 | ASSERT(write(interrupt_pipe_fd[1], &value, sizeof(value)) == 1); | ||
| 200 | } | ||
| 201 | |||
| 202 | void AcknowledgeInterrupt() { | ||
| 203 | u8 value = 0; | ||
| 204 | ssize_t ret = read(interrupt_pipe_fd[0], &value, sizeof(value)); | ||
| 205 | if (ret != 1 && errno != EAGAIN && errno != EWOULDBLOCK) { | ||
| 206 | LOG_ERROR(Network, "Failed to acknowledge interrupt on shutdown"); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | SOCKET GetInterruptSocket() { | ||
| 211 | return interrupt_pipe_fd[0]; | ||
| 212 | } | ||
| 163 | 213 | ||
| 164 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | 214 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { |
| 165 | sockaddr_in result; | 215 | sockaddr_in result; |
| @@ -490,6 +540,14 @@ NetworkInstance::~NetworkInstance() { | |||
| 490 | Finalize(); | 540 | Finalize(); |
| 491 | } | 541 | } |
| 492 | 542 | ||
| 543 | void CancelPendingSocketOperations() { | ||
| 544 | InterruptSocketOperations(); | ||
| 545 | } | ||
| 546 | |||
| 547 | void RestartSocketOperations() { | ||
| 548 | AcknowledgeInterrupt(); | ||
| 549 | } | ||
| 550 | |||
| 493 | std::optional<IPv4Address> GetHostIPv4Address() { | 551 | std::optional<IPv4Address> GetHostIPv4Address() { |
| 494 | const auto network_interface = Network::GetSelectedNetworkInterface(); | 552 | const auto network_interface = Network::GetSelectedNetworkInterface(); |
| 495 | if (!network_interface.has_value()) { | 553 | if (!network_interface.has_value()) { |
| @@ -560,7 +618,14 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { | |||
| 560 | return result; | 618 | return result; |
| 561 | }); | 619 | }); |
| 562 | 620 | ||
| 563 | const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout); | 621 | host_pollfds.push_back(WSAPOLLFD{ |
| 622 | .fd = GetInterruptSocket(), | ||
| 623 | .events = POLLIN, | ||
| 624 | .revents = 0, | ||
| 625 | }); | ||
| 626 | |||
| 627 | const int result = | ||
| 628 | WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), timeout); | ||
| 564 | if (result == 0) { | 629 | if (result == 0) { |
| 565 | ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(), | 630 | ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(), |
| 566 | [](WSAPOLLFD fd) { return fd.revents == 0; })); | 631 | [](WSAPOLLFD fd) { return fd.revents == 0; })); |
| @@ -627,6 +692,24 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { | |||
| 627 | std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { | 692 | std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { |
| 628 | sockaddr_in addr; | 693 | sockaddr_in addr; |
| 629 | socklen_t addrlen = sizeof(addr); | 694 | socklen_t addrlen = sizeof(addr); |
| 695 | |||
| 696 | std::vector<WSAPOLLFD> host_pollfds{ | ||
| 697 | WSAPOLLFD{fd, POLLIN, 0}, | ||
| 698 | WSAPOLLFD{GetInterruptSocket(), POLLIN, 0}, | ||
| 699 | }; | ||
| 700 | |||
| 701 | while (true) { | ||
| 702 | const int pollres = | ||
| 703 | WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1); | ||
| 704 | if (host_pollfds[1].revents != 0) { | ||
| 705 | // Interrupt signaled before a client could be accepted, break | ||
| 706 | return {AcceptResult{}, Errno::AGAIN}; | ||
| 707 | } | ||
| 708 | if (pollres > 0) { | ||
| 709 | break; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | |||
| 630 | const SOCKET new_socket = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen); | 713 | const SOCKET new_socket = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen); |
| 631 | 714 | ||
| 632 | if (new_socket == INVALID_SOCKET) { | 715 | if (new_socket == INVALID_SOCKET) { |
diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h index c7e20ae34..b7b7d773a 100644 --- a/src/core/internal_network/network.h +++ b/src/core/internal_network/network.h | |||
| @@ -96,6 +96,9 @@ public: | |||
| 96 | ~NetworkInstance(); | 96 | ~NetworkInstance(); |
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | void CancelPendingSocketOperations(); | ||
| 100 | void RestartSocketOperations(); | ||
| 101 | |||
| 99 | #ifdef _WIN32 | 102 | #ifdef _WIN32 |
| 100 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | 103 | constexpr IPv4Address TranslateIPv4(in_addr addr) { |
| 101 | auto& bytes = addr.S_un.S_un_b; | 104 | auto& bytes = addr.S_un.S_un_b; |