Skip to content

Commit 2eb226f

Browse files
committed
Fix emulator hanging on game closure
1 parent bbca356 commit 2eb226f

6 files changed

Lines changed: 118 additions & 148 deletions

File tree

‎include/nn/socket.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,14 @@ class Config;
2929
u32 Listen(s32 socket, s32 backlog);
3030
u32 Accept(s32 socket, sockaddr* addrOut, u32* addrLenOut);
3131
s32 Close(s32 socket);
32+
s32 Shutdown(s32 socket, s32 how);
33+
34+
struct PollFd {
35+
s32 fd;
36+
s16 events;
37+
s16 revents;
38+
};
39+
40+
s32 Poll(PollFd* fds, u64 nfds, s32 timeout);
3241
}; // namespace socket
3342
}; // namespace nn
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#pragma once
22

3-
#include <string>
4-
53
#include <arpa/inet.h>
64

75
#include "alloc.h"
@@ -12,13 +10,28 @@
1210
#include "skyline/inlinehook/And64InlineHook.hpp"
1311
#include "skyline/logger/Logger.hpp"
1412

13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
#include "skyline/nx/kernel/svc.h"
18+
19+
#ifdef __cplusplus
20+
}
21+
#endif
22+
1523
namespace skyline::logger {
24+
25+
// Logger that sends to both svcOutputDebugString and a TCP socket
1626
class DualLogger : public Logger {
1727
public:
18-
DualLogger(std::string);
19-
2028
virtual void Initialize();
29+
virtual bool ShouldFlush() override;
2130
virtual void SendRaw(void*, size_t);
2231
virtual std::string FriendlyName() { return "DualLogger"; }
2332
};
24-
}; // namespace skyline::logger
33+
34+
void setup_socket_hooks();
35+
void skyline_socket_init();
36+
void start_listen_thread();
37+
}; // namespace skyline::logger

‎include/skyline/logger/TcpLogger.hpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class TcpLogger : public Logger {
2222

2323
void setup_socket_hooks();
2424
void skyline_socket_init();
25+
void skyline_socket_finalize();
2526
void start_listen_thread();
2627
}; // namespace skyline::logger
2728

‎source/main.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "main.hpp"
22

3-
#include "skyline/logger/TcpLogger.hpp"
3+
#include "skyline/logger/DualLogger.hpp"
44
#include "skyline/utils/ipc.hpp"
55
#include "skyline/utils/cpputils.hpp"
66
#include "skyline/utils/utils.h"
@@ -104,7 +104,7 @@ void skyline_main() {
104104

105105
// initialize logger
106106
nn::fs::MountSdCardForDebug("sd");
107-
skyline::logger::s_Instance = new skyline::logger::TcpLogger();
107+
skyline::logger::s_Instance = new skyline::logger::DualLogger();
108108
skyline::logger::s_Instance->StartThread();
109109
skyline::logger::s_Instance->Log("[skyline_main] Beginning initialization.\n");
110110

Lines changed: 88 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,121 @@
1-
21
#include "skyline/logger/DualLogger.hpp"
2+
3+
#include <atomic>
4+
35
#include "skyline/utils/cpputils.hpp"
4-
#include "nn/fs.h"
56

67
#define PORT 6969
8+
#define POLLIN 0x01
79

8-
extern "C" void skyline_dual_send_raw(char* data, size_t size) __attribute__((visibility("default")));
10+
extern "C" void skyline_tcp_send_raw(char* data, size_t size) __attribute__((visibility("default")));
911

10-
void skyline_dual_send_raw(char* data, u64 size) { skyline::logger::s_Instance->Log(data, size); }
12+
void skyline_tcp_send_raw(char* data, u64 size) { skyline::logger::s_Instance->Log(data, size); }
1113

1214
namespace skyline::logger {
13-
nn::fs::FileHandle dualfileHandle;
14-
s64 Dualoffset;
15-
int g_dualtcpSocket;
16-
17-
DualLogger::DualLogger(std::string path) {
18-
nn::fs::DirectoryEntryType type;
19-
Result rc = nn::fs::GetEntryType(&type, path.c_str());
20-
21-
if (rc == 0x202) { // Path does not exist
22-
rc = nn::fs::CreateFile(path.c_str(), 0);
23-
} else if (R_FAILED(rc))
24-
return;
25-
26-
if (type == nn::fs::DirectoryEntryType_Directory) return;
27-
28-
R_ERRORONFAIL(nn::fs::OpenFile(&dualfileHandle, path.c_str(), nn::fs::OpenMode_ReadWrite | nn::fs::OpenMode_Append));
29-
}
15+
int g_tcpSocket = -1;
16+
static std::atomic<bool> g_loggerInit{false};
3017

31-
void DualLogger::Initialize() {
32-
// Sockets are already initialized by skyline_socket_init() in TcpLogger.cpp.
33-
// Just set up the TCP accept for this logger's socket.
18+
Result stub() { return 0; };
3419

20+
void init_socket_thing(void*) {
3521
struct sockaddr_in serverAddr;
36-
g_dualtcpSocket = nn::socket::Socket(AF_INET, SOCK_STREAM, 0);
37-
if (g_dualtcpSocket < 0) return;
22+
s32 listenSocket = nn::socket::Socket(AF_INET, SOCK_STREAM, 0);
23+
if (listenSocket < 0) return;
3824

3925
int flags = 1;
40-
nn::socket::SetSockOpt(g_dualtcpSocket, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
26+
nn::socket::SetSockOpt(listenSocket, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
4127

4228
serverAddr.sin_family = AF_INET;
4329
serverAddr.sin_addr.s_addr = INADDR_ANY;
4430
serverAddr.sin_port = nn::socket::InetHtons(PORT);
4531

46-
int rval = nn::socket::Bind(g_dualtcpSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
32+
int rval = nn::socket::Bind(listenSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
4733
if (rval < 0) {
48-
nn::socket::Close(g_dualtcpSocket);
34+
nn::socket::Close(listenSocket);
4935
return;
5036
}
5137

52-
rval = nn::socket::Listen(g_dualtcpSocket, 1);
38+
rval = nn::socket::Listen(listenSocket, 1);
5339
if (rval < 0) {
54-
nn::socket::Close(g_dualtcpSocket);
40+
nn::socket::Close(listenSocket);
5541
return;
5642
}
5743

58-
u32 addrLen = sizeof(serverAddr);
59-
s32 listenSocket = g_dualtcpSocket;
60-
g_dualtcpSocket = nn::socket::Accept(listenSocket, (struct sockaddr*)&serverAddr, &addrLen);
44+
// Poll with a 1-second timeout to let the thread exit cleanly on emulator
45+
s32 clientSocket = -1;
46+
while (true) {
47+
nn::socket::PollFd pfd;
48+
pfd.fd = listenSocket;
49+
pfd.events = POLLIN;
50+
pfd.revents = 0;
51+
52+
s32 pollResult = nn::socket::Poll(&pfd, 1, 1000);
53+
if (pollResult > 0 && (pfd.revents & POLLIN)) {
54+
u32 addrLen = sizeof(serverAddr);
55+
clientSocket = nn::socket::Accept(listenSocket, (struct sockaddr*)&serverAddr, &addrLen);
56+
break;
57+
}
58+
}
59+
6160
nn::socket::Close(listenSocket);
61+
62+
if (clientSocket < 0) return;
63+
g_tcpSocket = clientSocket;
64+
65+
char* message = "TCP Socket Connected.\n";
66+
nn::socket::Send(g_tcpSocket, (void*)message, strlen(message), 0);
6267
}
6368

64-
void DualLogger::SendRaw(void* data, size_t size) {
65-
nn::fs::SetFileSize(dualfileHandle, Dualoffset + size);
69+
void skyline_socket_init() {
70+
const size_t poolSize = 0x600000;
71+
void* socketPool = memalign(0x4000, poolSize);
72+
nn::socket::Initialize(socketPool, poolSize, 0x20000, 14);
73+
74+
g_loggerInit.store(true, std::memory_order_release);
75+
}
6676

67-
nn::socket::Send(g_dualtcpSocket, data, size, 0);
77+
void start_listen_thread() {
78+
const size_t stackSize = 0x4000;
79+
void* threadStack = memalign(0x1000, stackSize);
6880

69-
nn::fs::WriteFile(dualfileHandle, Dualoffset, data, size,
70-
nn::fs::WriteOption::CreateOption(nn::fs::WriteOptionFlag_Flush));
81+
nn::os::ThreadType* thread = new nn::os::ThreadType;
82+
nn::os::CreateThread(thread, init_socket_thing, nullptr, threadStack, stackSize, 16, 0);
83+
nn::os::StartThread(thread);
84+
}
85+
86+
Result init_normal(void* arg1, ulong arg2, ulong arg3, int arg4) {
87+
return 0;
88+
}
89+
90+
Result init_config(nn::socket::Config const& config) {
91+
return 0;
92+
}
93+
94+
void setup_socket_hooks() {
95+
Result (*socketInitWithPool)(void*, ulong, ulong, int) = nn::socket::Initialize;
96+
A64HookFunction(reinterpret_cast<void*>(socketInitWithPool), reinterpret_cast<void*>(init_normal),
97+
NULL);
98+
99+
Result (*socketInitWithConfig)(nn::socket::Config const&) = nn::socket::Initialize;
100+
A64HookFunction(reinterpret_cast<void*>(socketInitWithConfig), reinterpret_cast<void*>(init_config),
101+
NULL);
102+
103+
A64HookFunction(reinterpret_cast<void*>(nn::socket::Finalize), reinterpret_cast<void*>(stub),
104+
NULL);
105+
}
106+
107+
void DualLogger::Initialize() {}
108+
109+
bool DualLogger::ShouldFlush() {
110+
return true;
111+
}
71112

72-
Dualoffset += size;
73-
};
113+
void DualLogger::SendRaw(void* data, size_t size) {
114+
svcOutputDebugString((const char*)data, size);
115+
116+
// Also send to TCP if a client is connected
117+
if (g_loggerInit.load(std::memory_order_acquire) && g_tcpSocket != -1) {
118+
nn::socket::Send(g_tcpSocket, data, size, 0);
119+
}
120+
}
74121
}; // namespace skyline::logger

‎source/skyline/logger/TcpLogger.cpp‎

Lines changed: 0 additions & 100 deletions
This file was deleted.

0 commit comments

Comments
 (0)