summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar liamwhite2023-09-13 15:40:58 -0400
committerGravatar GitHub2023-09-13 15:40:58 -0400
commit8fb9f78e834349f62dcf4ed72d9e960a31bed949 (patch)
tree0cc3e5ab846b27b1569596a5368c998aca5728bc
parentMerge pull request #11486 from liamwhite/system-verification (diff)
parentinternal_network: log error on interrupt pipe read failure (diff)
downloadyuzu-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.cpp2
-rw-r--r--src/core/internal_network/network.cpp89
-rw-r--r--src/core/internal_network/network.h3
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
49using socklen_t = int; 49using socklen_t = int;
50 50
51SOCKET interrupt_socket = static_cast<SOCKET>(-1);
52
53void InterruptSocketOperations() {
54 closesocket(interrupt_socket);
55}
56
57void AcknowledgeInterrupt() {
58 interrupt_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
59}
60
51void Initialize() { 61void 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
56void Finalize() { 68void Finalize() {
69 InterruptSocketOperations();
57 WSACleanup(); 70 WSACleanup();
58} 71}
59 72
73SOCKET GetInterruptSocket() {
74 return interrupt_socket;
75}
76
60sockaddr TranslateFromSockAddrIn(SockAddrIn input) { 77sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
61 sockaddr_in result; 78 sockaddr_in result;
62 79
@@ -157,9 +174,42 @@ constexpr int SD_RECEIVE = SHUT_RD;
157constexpr int SD_SEND = SHUT_WR; 174constexpr int SD_SEND = SHUT_WR;
158constexpr int SD_BOTH = SHUT_RDWR; 175constexpr int SD_BOTH = SHUT_RDWR;
159 176
160void Initialize() {} 177int interrupt_pipe_fd[2] = {-1, -1};
161 178
162void Finalize() {} 179void 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
188void 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
197void InterruptSocketOperations() {
198 u8 value = 0;
199 ASSERT(write(interrupt_pipe_fd[1], &value, sizeof(value)) == 1);
200}
201
202void 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
210SOCKET GetInterruptSocket() {
211 return interrupt_pipe_fd[0];
212}
163 213
164sockaddr TranslateFromSockAddrIn(SockAddrIn input) { 214sockaddr 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
543void CancelPendingSocketOperations() {
544 InterruptSocketOperations();
545}
546
547void RestartSocketOperations() {
548 AcknowledgeInterrupt();
549}
550
493std::optional<IPv4Address> GetHostIPv4Address() { 551std::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) {
627std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { 692std::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
99void CancelPendingSocketOperations();
100void RestartSocketOperations();
101
99#ifdef _WIN32 102#ifdef _WIN32
100constexpr IPv4Address TranslateIPv4(in_addr addr) { 103constexpr IPv4Address TranslateIPv4(in_addr addr) {
101 auto& bytes = addr.S_un.S_un_b; 104 auto& bytes = addr.S_un.S_un_b;