[9477] Implement glyph 45776
[getmangos.git] / src / realmd / Main.cpp
blob84f9ec0df9394dcbef17e2261480af7e1094cbff
1 /*
2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 /// \addtogroup realmd Realm Daemon
20 /// @{
21 /// \file
23 #include "Common.h"
24 #include "Database/DatabaseEnv.h"
25 #include "RealmList.h"
27 #include "Config/ConfigEnv.h"
28 #include "Log.h"
29 #include "sockets/ListenSocket.h"
30 #include "AuthSocket.h"
31 #include "SystemConfig.h"
32 #include "revision.h"
33 #include "revision_nr.h"
34 #include "revision_sql.h"
35 #include "Util.h"
36 #include <openssl/opensslv.h>
37 #include <openssl/crypto.h>
39 #ifdef WIN32
40 #include "ServiceWin32.h"
41 char serviceName[] = "realmd";
42 char serviceLongName[] = "MaNGOS realmd service";
43 char serviceDescription[] = "Massive Network Game Object Server";
45 * -1 - not in service mode
46 * 0 - stopped
47 * 1 - running
48 * 2 - paused
50 int m_ServiceStatus = -1;
51 #endif
53 bool StartDB();
54 void UnhookSignals();
55 void HookSignals();
57 bool stopEvent = false; ///< Setting it to true stops the server
59 DatabaseType loginDatabase; ///< Accessor to the realm server database
61 /// Print out the usage string for this program on the console.
62 void usage(const char *prog)
64 sLog.outString("Usage: \n %s [<options>]\n"
65 " --version print version and exist\n\r"
66 " -c config_file use config_file as configuration file\n\r"
67 #ifdef WIN32
68 " Running as service functions:\n\r"
69 " --service run as service\n\r"
70 " -s install install service\n\r"
71 " -s uninstall uninstall service\n\r"
72 #endif
73 ,prog);
76 /// Launch the realm server
77 extern int main(int argc, char **argv)
79 ///- Command line parsing to get the configuration file name
80 char const* cfg_file = _REALMD_CONFIG;
81 int c=1;
82 while( c < argc )
84 if( strcmp(argv[c],"-c") == 0)
86 if( ++c >= argc )
88 sLog.outError("Runtime-Error: -c option requires an input argument");
89 usage(argv[0]);
90 return 1;
92 else
93 cfg_file = argv[c];
96 if( strcmp(argv[c],"--version") == 0)
98 printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID));
99 return 0;
102 #ifdef WIN32
103 ////////////
104 //Services//
105 ////////////
106 if( strcmp(argv[c],"-s") == 0)
108 if( ++c >= argc )
110 sLog.outError("Runtime-Error: -s option requires an input argument");
111 usage(argv[0]);
112 return 1;
114 if( strcmp(argv[c],"install") == 0)
116 if (WinServiceInstall())
117 sLog.outString("Installing service");
118 return 1;
120 else if( strcmp(argv[c],"uninstall") == 0)
122 if(WinServiceUninstall())
123 sLog.outString("Uninstalling service");
124 return 1;
126 else
128 sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
129 usage(argv[0]);
130 return 1;
133 if( strcmp(argv[c],"--service") == 0)
135 WinServiceRun();
137 ////
138 #endif
139 ++c;
142 if (!sConfig.SetSource(cfg_file))
144 sLog.outError("Could not find configuration file %s.", cfg_file);
145 return 1;
147 sLog.Initialize();
149 sLog.outString( "%s [realm-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) );
150 sLog.outString( "<Ctrl-C> to stop.\n" );
151 sLog.outString("Using configuration file %s.", cfg_file);
153 ///- Check the version of the configuration file
154 uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
155 if (confVersion < _REALMDCONFVERSION)
157 sLog.outError("*****************************************************************************");
158 sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!");
159 sLog.outError(" Please check for updates, as your current default values may cause");
160 sLog.outError(" strange behavior.");
161 sLog.outError("*****************************************************************************");
162 clock_t pause = 3000 + clock();
164 while (pause > clock()) {}
167 sLog.outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
168 if (SSLeay() < 0x009080bfL )
170 sLog.outDetail("WARNING: Outdated version of OpenSSL lib. Logins to server may not work!");
171 sLog.outDetail("WARNING: Minimal required version [OpenSSL 0.9.8k]");
174 /// realmd PID file creation
175 std::string pidfile = sConfig.GetStringDefault("PidFile", "");
176 if(!pidfile.empty())
178 uint32 pid = CreatePIDFile(pidfile);
179 if( !pid )
181 sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() );
182 return 1;
185 sLog.outString( "Daemon PID: %u\n", pid );
188 ///- Initialize the database connection
189 if(!StartDB())
190 return 1;
192 ///- Get the list of realms for the server
193 sRealmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20));
194 if (sRealmList.size() == 0)
196 sLog.outError("No valid realms specified.");
197 return 1;
200 ///- Launch the listening network socket
201 port_t rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT );
202 std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0");
204 SocketHandler h;
205 ListenSocket<AuthSocket> authListenSocket(h);
206 if ( authListenSocket.Bind(bind_ip.c_str(),rmport))
208 sLog.outError( "MaNGOS realmd can not bind to %s:%d",bind_ip.c_str(), rmport );
209 return 1;
212 // cleanup query
213 //set expired bans to inactive
214 loginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
215 loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
217 h.Add(&authListenSocket);
219 ///- Catch termination signals
220 HookSignals();
222 ///- Handle affinity for multiple processors and process priority on Windows
223 #ifdef WIN32
225 HANDLE hProcess = GetCurrentProcess();
227 uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
228 if(Aff > 0)
230 ULONG_PTR appAff;
231 ULONG_PTR sysAff;
233 if(GetProcessAffinityMask(hProcess,&appAff,&sysAff))
235 ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
237 if(!curAff )
239 sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for realmd. Accessible processors bitmask (hex): %x",Aff,appAff);
241 else
243 if(SetProcessAffinityMask(hProcess,curAff))
244 sLog.outString("Using processors (bitmask, hex): %x", curAff);
245 else
246 sLog.outError("Can't set used processors (hex): %x", curAff);
249 sLog.outString();
252 bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
254 if(Prio)
256 if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS))
257 sLog.outString("realmd process priority class set to HIGH");
258 else
259 sLog.outError("ERROR: Can't set realmd process priority class.");
260 sLog.outString();
263 #endif
265 // maximum counter for next ping
266 uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000));
267 uint32 loopCounter = 0;
269 ///- Wait for termination signal
270 while (!stopEvent)
273 h.Select(0, 100000);
275 if( (++loopCounter) == numLoops )
277 loopCounter = 0;
278 sLog.outDetail("Ping MySQL to keep connection alive");
279 delete loginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1");
281 #ifdef WIN32
282 if (m_ServiceStatus == 0) stopEvent = true;
283 while (m_ServiceStatus == 2) Sleep(1000);
284 #endif
287 ///- Wait for the delay thread to exit
288 loginDatabase.HaltDelayThread();
290 ///- Remove signal handling before leaving
291 UnhookSignals();
293 sLog.outString( "Halting process..." );
294 return 0;
297 /// Handle termination signals
298 /** Put the global variable stopEvent to 'true' if a termination signal is caught **/
299 void OnSignal(int s)
301 switch (s)
303 case SIGINT:
304 case SIGTERM:
305 stopEvent = true;
306 break;
307 #ifdef _WIN32
308 case SIGBREAK:
309 stopEvent = true;
310 break;
311 #endif
314 signal(s, OnSignal);
317 /// Initialize connection to the database
318 bool StartDB()
320 std::string dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", "");
321 if(dbstring.empty())
323 sLog.outError("Database not specified");
324 return false;
327 sLog.outString("Database: %s", dbstring.c_str() );
328 if(!loginDatabase.Initialize(dbstring.c_str()))
330 sLog.outError("Cannot connect to database");
331 return false;
334 if(!loginDatabase.CheckRequiredField("realmd_db_version",REVISION_DB_REALMD))
336 ///- Wait for already started DB delay threads to end
337 loginDatabase.HaltDelayThread();
338 return false;
341 return true;
344 /// Define hook 'OnSignal' for all termination signals
345 void HookSignals()
347 signal(SIGINT, OnSignal);
348 signal(SIGTERM, OnSignal);
349 #ifdef _WIN32
350 signal(SIGBREAK, OnSignal);
351 #endif
354 /// Unhook the signals before leaving
355 void UnhookSignals()
357 signal(SIGINT, 0);
358 signal(SIGTERM, 0);
359 #ifdef _WIN32
360 signal(SIGBREAK, 0);
361 #endif
364 /// @}