|
1 | | - |
2 | 1 | #include "skyline/logger/DualLogger.hpp" |
| 2 | + |
| 3 | +#include <atomic> |
| 4 | + |
3 | 5 | #include "skyline/utils/cpputils.hpp" |
4 | | -#include "nn/fs.h" |
5 | 6 |
|
6 | 7 | #define PORT 6969 |
| 8 | +#define POLLIN 0x01 |
7 | 9 |
|
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"))); |
9 | 11 |
|
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); } |
11 | 13 |
|
12 | 14 | 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}; |
30 | 17 |
|
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; }; |
34 | 19 |
|
| 20 | +void init_socket_thing(void*) { |
35 | 21 | 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; |
38 | 24 |
|
39 | 25 | 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)); |
41 | 27 |
|
42 | 28 | serverAddr.sin_family = AF_INET; |
43 | 29 | serverAddr.sin_addr.s_addr = INADDR_ANY; |
44 | 30 | serverAddr.sin_port = nn::socket::InetHtons(PORT); |
45 | 31 |
|
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)); |
47 | 33 | if (rval < 0) { |
48 | | - nn::socket::Close(g_dualtcpSocket); |
| 34 | + nn::socket::Close(listenSocket); |
49 | 35 | return; |
50 | 36 | } |
51 | 37 |
|
52 | | - rval = nn::socket::Listen(g_dualtcpSocket, 1); |
| 38 | + rval = nn::socket::Listen(listenSocket, 1); |
53 | 39 | if (rval < 0) { |
54 | | - nn::socket::Close(g_dualtcpSocket); |
| 40 | + nn::socket::Close(listenSocket); |
55 | 41 | return; |
56 | 42 | } |
57 | 43 |
|
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 | + |
61 | 60 | 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); |
62 | 67 | } |
63 | 68 |
|
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 | +} |
66 | 76 |
|
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); |
68 | 80 |
|
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 | +} |
71 | 112 |
|
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 | +} |
74 | 121 | }; // namespace skyline::logger |
0 commit comments