1#include "local_server.h"
2
3#include <game/client/gameclient.h>
4#include <game/localization.h>
5
6#if defined(CONF_PLATFORM_ANDROID)
7#include <android/android_main.h>
8#endif
9
10void CLocalServer::RunServer(const std::vector<const char *> &vpArguments)
11{
12 secure_random_password(buffer: m_aRconPassword, length: sizeof(m_aRconPassword), pw_length: 16);
13 char aAuthCommand[64 + sizeof(m_aRconPassword)];
14 str_format(buffer: aAuthCommand, buffer_size: sizeof(aAuthCommand), format: "auth_add %s admin %s", DEFAULT_SAVED_RCON_USER, m_aRconPassword);
15
16 std::vector<const char *> vpArgumentsWithAuth = vpArguments;
17 vpArgumentsWithAuth.push_back(x: aAuthCommand);
18
19#if defined(CONF_PLATFORM_ANDROID)
20 if(StartAndroidServer(vpArgumentsWithAuth.data(), vpArgumentsWithAuth.size()))
21 {
22 GameClient()->m_Menus.ForceRefreshLanPage();
23 }
24 else
25 {
26 Client()->AddWarning(SWarning(Localize("Server could not be started. Make sure to grant the notification permission in the app settings so the server can run in the background.")));
27 mem_zero(m_aRconPassword, sizeof(m_aRconPassword));
28 }
29#else
30 char aBuf[IO_MAX_PATH_LENGTH];
31 Storage()->GetBinaryPath(PLAT_SERVER_EXEC, pBuffer: aBuf, BufferSize: sizeof(aBuf));
32 // No / in binary path means to search in $PATH, so it is expected that the file can't be opened. Just try executing anyway.
33 if(str_find(haystack: aBuf, needle: "/") == nullptr || fs_is_file(path: aBuf))
34 {
35 m_Process = shell_execute(file: aBuf, window_state: EShellExecuteWindowState::BACKGROUND, arguments: vpArgumentsWithAuth.data(), num_arguments: vpArgumentsWithAuth.size());
36 if(m_Process != INVALID_PROCESS)
37 {
38 GameClient()->m_Menus.ForceRefreshLanPage();
39 }
40 else
41 {
42 Client()->AddWarning(Warning: SWarning(Localize(pStr: "Server could not be started")));
43 mem_zero(block: m_aRconPassword, size: sizeof(m_aRconPassword));
44 }
45 }
46 else
47 {
48 Client()->AddWarning(Warning: SWarning(Localize(pStr: "Server executable not found, can't run server")));
49 mem_zero(block: m_aRconPassword, size: sizeof(m_aRconPassword));
50 }
51#endif
52}
53
54void CLocalServer::KillServer()
55{
56#if defined(CONF_PLATFORM_ANDROID)
57 ExecuteAndroidServerCommand("shutdown");
58 GameClient()->m_Menus.ForceRefreshLanPage();
59#else
60 if(m_Process != INVALID_PROCESS && kill_process(process: m_Process))
61 {
62 m_Process = INVALID_PROCESS;
63 GameClient()->m_Menus.ForceRefreshLanPage();
64 }
65#endif
66 mem_zero(block: m_aRconPassword, size: sizeof(m_aRconPassword));
67}
68
69bool CLocalServer::IsServerRunning()
70{
71#if defined(CONF_PLATFORM_ANDROID)
72 return IsAndroidServerRunning();
73#else
74 if(m_Process != INVALID_PROCESS && !is_process_alive(process: m_Process))
75 {
76 KillServer();
77 }
78 return m_Process != INVALID_PROCESS;
79#endif
80}
81
82void CLocalServer::RconAuthIfPossible()
83{
84 if(!IsServerRunning() ||
85 m_aRconPassword[0] == '\0' ||
86 !net_addr_is_local(addr: &Client()->ServerAddress()))
87 {
88 return;
89 }
90 Client()->RconAuth(pUsername: DEFAULT_SAVED_RCON_USER, pPassword: m_aRconPassword, Dummy: g_Config.m_ClDummy);
91}
92