Commit | Line | Data |
---|---|---|
d9177dd1 | 1 | /* |
5039dede | 2 | ** NetXMS - Network Management System |
302bb0af | 3 | ** Copyright (C) 2003-2017 Raden Solutions |
5039dede AK |
4 | ** |
5 | ** This program is free software; you can redistribute it and/or modify | |
6 | ** it under the terms of the GNU General Public License as published by | |
7 | ** the Free Software Foundation; either version 2 of the License, or | |
8 | ** (at your option) any later version. | |
9 | ** | |
10 | ** This program is distributed in the hope that it will be useful, | |
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | ** GNU General Public License for more details. | |
14 | ** | |
15 | ** You should have received a copy of the GNU General Public License | |
16 | ** along with this program; if not, write to the Free Software | |
17 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | ** | |
19 | ** File: main.cpp | |
20 | ** | |
21 | **/ | |
22 | ||
23 | #include "nxcore.h" | |
24 | #include <netxmsdb.h> | |
fdbee7f8 | 25 | #include <netxms_mt.h> |
6fad8870 | 26 | #include <hdlink.h> |
5039dede | 27 | |
b847803c | 28 | #if !defined(_WIN32) && HAVE_READLINE_READLINE_H && HAVE_READLINE && !defined(UNICODE) |
0322eed7 VK |
29 | #include <readline/readline.h> |
30 | #include <readline/history.h> | |
31 | #define USE_READLINE 1 | |
5039dede AK |
32 | #endif |
33 | ||
34 | #ifdef _WIN32 | |
a23d8e0d VK |
35 | #include <errno.h> |
36 | #include <psapi.h> | |
7bdb43c3 | 37 | #include <conio.h> |
5039dede | 38 | #else |
a23d8e0d VK |
39 | #include <signal.h> |
40 | #include <sys/wait.h> | |
5039dede AK |
41 | #endif |
42 | ||
4ef60905 AK |
43 | #ifdef WITH_ZMQ |
44 | #include "zeromq.h" | |
45 | #endif | |
46 | ||
3a82d5ae VK |
47 | /** |
48 | * Messages generated by mc.pl (for UNIX version only) | |
49 | */ | |
5039dede AK |
50 | #ifndef _WIN32 |
51 | extern unsigned int g_dwNumMessages; | |
52 | extern const TCHAR *g_szMessages[]; | |
53 | #endif | |
54 | ||
8f99849c VK |
55 | /** |
56 | * Shutdown reasons | |
57 | */ | |
030a0779 VK |
58 | #define SHUTDOWN_DEFAULT 0 |
59 | #define SHUTDOWN_FROM_CONSOLE 1 | |
60 | #define SHUTDOWN_BY_SIGNAL 2 | |
5039dede | 61 | |
8f99849c VK |
62 | /** |
63 | * Externals | |
64 | */ | |
d140955e | 65 | extern Queue g_dciCacheLoaderQueue; |
5039dede | 66 | |
36e44abe | 67 | void InitClientListeners(); |
534e1b83 | 68 | void InitMobileDeviceListeners(); |
36e44abe | 69 | void InitCertificates(); |
cce82c3a | 70 | bool LoadServerCertificate(RSA **serverKey); |
ab185583 VK |
71 | void InitUsers(); |
72 | void CleanupUsers(); | |
8fd95c92 | 73 | void LoadPerfDataStorageDrivers(); |
03b96461 | 74 | void ImportLocalConfiguration(); |
288a0046 | 75 | void RegisterPredictionEngines(); |
cf4260a7 | 76 | void ExecuteStartupScripts(); |
bf306af3 | 77 | void CloseAgentTunnels(); |
ec13a467 VK |
78 | |
79 | void ExecuteScheduledScript(const ScheduledTaskParameters *param); | |
80 | void MaintenanceModeEnter(const ScheduledTaskParameters *params); | |
81 | void MaintenanceModeLeave(const ScheduledTaskParameters *params); | |
82deb2d7 TD |
82 | void ScheduleDeployPolicy(const ScheduledTaskParameters *params); |
83 | void ScheduleUninstallPolicy(const ScheduledTaskParameters * params); | |
058bf6fc | 84 | |
0de31ec3 VK |
85 | void InitCountryList(); |
86 | void InitCurrencyList(); | |
87 | ||
058bf6fc | 88 | #if XMPP_SUPPORTED |
098ef635 | 89 | void StartXMPPConnector(); |
244c65ef | 90 | void StopXMPPConnector(); |
058bf6fc | 91 | #endif |
5039dede | 92 | |
534e1b83 | 93 | /** |
af4a09df VK |
94 | * Syslog server control |
95 | */ | |
96 | void StartSyslogServer(); | |
97 | void StopSyslogServer(); | |
98 | ||
99 | /** | |
534e1b83 VK |
100 | * Thread functions |
101 | */ | |
534e1b83 VK |
102 | THREAD_RESULT THREAD_CALL Syncer(void *); |
103 | THREAD_RESULT THREAD_CALL NodePoller(void *); | |
104 | THREAD_RESULT THREAD_CALL PollManager(void *); | |
105 | THREAD_RESULT THREAD_CALL EventProcessor(void *); | |
106 | THREAD_RESULT THREAD_CALL WatchdogThread(void *); | |
107 | THREAD_RESULT THREAD_CALL ClientListener(void *); | |
108 | THREAD_RESULT THREAD_CALL ClientListenerIPv6(void *); | |
109 | THREAD_RESULT THREAD_CALL MobileDeviceListener(void *); | |
110 | THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *); | |
111 | THREAD_RESULT THREAD_CALL ISCListener(void *); | |
112 | THREAD_RESULT THREAD_CALL LocalAdminListener(void *); | |
113 | THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *); | |
534e1b83 VK |
114 | THREAD_RESULT THREAD_CALL BeaconPoller(void *); |
115 | THREAD_RESULT THREAD_CALL JobManagerThread(void *); | |
116 | THREAD_RESULT THREAD_CALL UptimeCalculator(void *); | |
d75003e1 | 117 | THREAD_RESULT THREAD_CALL ReportingServerConnector(void *); |
bf306af3 | 118 | THREAD_RESULT THREAD_CALL TunnelListener(void *arg); |
058bf6fc | 119 | |
534e1b83 VK |
120 | /** |
121 | * Global variables | |
122 | */ | |
1039d7ee | 123 | TCHAR NXCORE_EXPORTABLE g_szConfigFile[MAX_PATH] = _T("{search}"); |
5039dede | 124 | TCHAR NXCORE_EXPORTABLE g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE; |
458b5d2b VK |
125 | UINT32 g_logRotationMode = NXLOG_ROTATION_BY_SIZE; |
126 | UINT64 g_maxLogSize = 16384 * 1024; | |
127 | UINT32 g_logHistorySize = 4; | |
4f8998ca | 128 | TCHAR g_szDailyLogFileSuffix[64] = _T(""); |
5039dede | 129 | TCHAR NXCORE_EXPORTABLE g_szDumpDir[MAX_PATH] = DEFAULT_DUMP_DIR; |
29dc8792 | 130 | char g_szCodePage[256] = ICONV_DEFAULT_CODEPAGE; |
5f6e8d09 | 131 | TCHAR NXCORE_EXPORTABLE g_szListenAddress[MAX_PATH] = _T("*"); |
5039dede | 132 | #ifndef _WIN32 |
b07c50cc | 133 | TCHAR NXCORE_EXPORTABLE g_szPIDFile[MAX_PATH] = _T("/var/run/netxmsd.pid"); |
5039dede | 134 | #endif |
967893bb VK |
135 | UINT32 g_dwDiscoveryPollingInterval; |
136 | UINT32 g_dwStatusPollingInterval; | |
137 | UINT32 g_dwConfigurationPollingInterval; | |
138 | UINT32 g_dwRoutingTableUpdateInterval; | |
139 | UINT32 g_dwTopologyPollingInterval; | |
140 | UINT32 g_dwConditionPollingInterval; | |
805171de | 141 | UINT32 g_instancePollingInterval; |
c59466d2 VK |
142 | UINT32 g_icmpPingSize; |
143 | UINT32 g_icmpPingTimeout = 1500; // ICMP ping timeout (milliseconds) | |
144 | UINT32 g_auditFlags; | |
145 | UINT32 g_slmPollingInterval; | |
f6456d80 | 146 | UINT32 g_offlineDataRelevanceTime = 86400; |
db6a6b45 VK |
147 | TCHAR NXCORE_EXPORTABLE g_netxmsdDataDir[MAX_PATH] = _T(""); |
148 | TCHAR NXCORE_EXPORTABLE g_netxmsdLibDir[MAX_PATH] = _T(""); | |
2a964810 | 149 | int g_dbSyntax = DB_SYNTAX_UNKNOWN; |
967893bb | 150 | UINT32 NXCORE_EXPORTABLE g_processAffinityMask = DEFAULT_AFFINITY_MASK; |
e9902466 | 151 | UINT64 g_serverId = 0; |
5039dede | 152 | RSA *g_pServerKey = NULL; |
c59466d2 VK |
153 | time_t g_serverStartTime = 0; |
154 | UINT32 g_lockTimeout = 60000; // Default timeout for acquiring mutex | |
155 | UINT32 g_agentCommandTimeout = 4000; // Default timeout for requests to agent | |
156 | UINT32 g_thresholdRepeatInterval = 0; // Disabled by default | |
157 | int g_requiredPolls = 1; | |
b8c1ec69 | 158 | DB_DRIVER g_dbDriver = NULL; |
1ef6170e | 159 | ThreadPool NXCORE_EXPORTABLE *g_mainThreadPool = NULL; |
9708eff4 | 160 | INT16 g_defaultAgentCacheMode = AGENT_CACHE_OFF; |
fbd0079b | 161 | InetAddressList g_peerNodeAddrList; |
4a64a795 | 162 | Condition g_dbPasswordReady(true); |
5039dede | 163 | |
f375019e VK |
164 | /** |
165 | * Static data | |
166 | */ | |
5039dede AK |
167 | static CONDITION m_condShutdown = INVALID_CONDITION_HANDLE; |
168 | static THREAD m_thPollManager = INVALID_THREAD_HANDLE; | |
5039dede | 169 | static THREAD m_thSyncer = INVALID_THREAD_HANDLE; |
bf306af3 | 170 | static THREAD s_tunnelListenerThread = INVALID_THREAD_HANDLE; |
5039dede | 171 | static int m_nShutdownReason = SHUTDOWN_DEFAULT; |
4fd0b7ca | 172 | static StringSet s_components; |
5039dede AK |
173 | |
174 | #ifndef _WIN32 | |
175 | static pthread_t m_signalHandlerThread; | |
176 | #endif | |
177 | ||
496390c2 | 178 | /** |
4fd0b7ca VK |
179 | * Register component |
180 | */ | |
181 | void NXCORE_EXPORTABLE RegisterComponent(const TCHAR *id) | |
182 | { | |
183 | s_components.add(id); | |
184 | } | |
185 | ||
186 | /** | |
187 | * Check if component with given ID is registered | |
188 | */ | |
189 | bool NXCORE_EXPORTABLE IsComponentRegistered(const TCHAR *id) | |
190 | { | |
191 | return s_components.contains(id); | |
192 | } | |
193 | ||
194 | /** | |
195 | * Fill NXCP message with components data | |
196 | */ | |
197 | void FillComponentsMessage(NXCPMessage *msg) | |
198 | { | |
199 | msg->setField(VID_NUM_COMPONENTS, (INT32)s_components.size()); | |
200 | UINT32 fieldId = VID_COMPONENT_LIST_BASE; | |
201 | Iterator<const TCHAR> *it = s_components.iterator(); | |
202 | while(it->hasNext()) | |
203 | { | |
204 | msg->setField(fieldId++, it->next()); | |
205 | } | |
206 | delete it; | |
207 | } | |
208 | ||
209 | /** | |
496390c2 VK |
210 | * Sleep for specified number of seconds or until system shutdown arrives |
211 | * Function will return TRUE if shutdown event occurs | |
212 | * | |
213 | * @param seconds seconds to sleep | |
214 | * @return true if server is shutting down | |
215 | */ | |
400e55c4 | 216 | bool NXCORE_EXPORTABLE SleepAndCheckForShutdown(int seconds) |
5039dede | 217 | { |
496390c2 | 218 | return ConditionWait(m_condShutdown, seconds * 1000); |
5039dede AK |
219 | } |
220 | ||
496390c2 VK |
221 | /** |
222 | * Disconnect from database (exportable function for startup module) | |
223 | */ | |
73869331 | 224 | void NXCORE_EXPORTABLE ShutdownDB() |
5039dede | 225 | { |
9bd1bace | 226 | DBConnectionPoolShutdown(); |
b8c1ec69 | 227 | DBUnloadDriver(g_dbDriver); |
5039dede AK |
228 | } |
229 | ||
496390c2 VK |
230 | /** |
231 | * Check data directory for existence | |
232 | */ | |
35f836fe | 233 | static BOOL CheckDataDir() |
5039dede | 234 | { |
35f836fe | 235 | TCHAR szBuffer[MAX_PATH]; |
5039dede | 236 | |
db6a6b45 | 237 | if (_tchdir(g_netxmsdDataDir) == -1) |
5039dede | 238 | { |
db6a6b45 | 239 | nxlog_write(MSG_INVALID_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", g_netxmsdDataDir); |
5039dede AK |
240 | return FALSE; |
241 | } | |
242 | ||
243 | #ifdef _WIN32 | |
35f836fe | 244 | #define MKDIR(name) _tmkdir(name) |
5039dede | 245 | #else |
35f836fe | 246 | #define MKDIR(name) _tmkdir(name, 0700) |
5039dede AK |
247 | #endif |
248 | ||
5039dede | 249 | // Create directory for package files if it doesn't exist |
db6a6b45 | 250 | _tcscpy(szBuffer, g_netxmsdDataDir); |
35f836fe | 251 | _tcscat(szBuffer, DDIR_PACKAGES); |
5039dede AK |
252 | if (MKDIR(szBuffer) == -1) |
253 | if (errno != EEXIST) | |
254 | { | |
255 | nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer); | |
256 | return FALSE; | |
257 | } | |
258 | ||
4d0c32f3 | 259 | // Create directory for map background images if it doesn't exist |
db6a6b45 | 260 | _tcscpy(szBuffer, g_netxmsdDataDir); |
35f836fe | 261 | _tcscat(szBuffer, DDIR_BACKGROUNDS); |
4d0c32f3 VK |
262 | if (MKDIR(szBuffer) == -1) |
263 | if (errno != EEXIST) | |
264 | { | |
265 | nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer); | |
266 | return FALSE; | |
267 | } | |
268 | ||
e6b9439a | 269 | // Create directory for image library is if does't exists |
db6a6b45 | 270 | _tcscpy(szBuffer, g_netxmsdDataDir); |
e6b9439a AK |
271 | _tcscat(szBuffer, DDIR_IMAGES); |
272 | if (MKDIR(szBuffer) == -1) | |
273 | { | |
274 | if (errno != EEXIST) | |
275 | { | |
276 | nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer); | |
277 | return FALSE; | |
278 | } | |
279 | } | |
280 | ||
619e5c9b | 281 | // Create directory for file store if does't exists |
db6a6b45 | 282 | _tcscpy(szBuffer, g_netxmsdDataDir); |
619e5c9b VK |
283 | _tcscat(szBuffer, DDIR_FILES); |
284 | if (MKDIR(szBuffer) == -1) | |
285 | { | |
286 | if (errno != EEXIST) | |
287 | { | |
288 | nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer); | |
57fef75c VK |
289 | return FALSE; |
290 | } | |
291 | } | |
292 | ||
5039dede AK |
293 | #undef MKDIR |
294 | ||
295 | return TRUE; | |
296 | } | |
297 | ||
496390c2 VK |
298 | /** |
299 | * Load global configuration parameters | |
300 | */ | |
5039dede AK |
301 | static void LoadGlobalConfig() |
302 | { | |
35f836fe VK |
303 | g_dwDiscoveryPollingInterval = ConfigReadInt(_T("DiscoveryPollingInterval"), 900); |
304 | g_dwStatusPollingInterval = ConfigReadInt(_T("StatusPollingInterval"), 60); | |
305 | g_dwConfigurationPollingInterval = ConfigReadInt(_T("ConfigurationPollingInterval"), 3600); | |
805171de | 306 | g_instancePollingInterval = ConfigReadInt(_T("InstancePollingInterval"), 600); |
35f836fe | 307 | g_dwRoutingTableUpdateInterval = ConfigReadInt(_T("RoutingTableUpdateInterval"), 300); |
040c45fa | 308 | g_dwTopologyPollingInterval = ConfigReadInt(_T("TopologyPollingInterval"), 1800); |
35f836fe | 309 | g_dwConditionPollingInterval = ConfigReadInt(_T("ConditionPollingInterval"), 60); |
c59466d2 | 310 | g_slmPollingInterval = ConfigReadInt(_T("SlmPollingInterval"), 60); |
90e3031f VK |
311 | DCObject::m_defaultPollingInterval = ConfigReadInt(_T("DefaultDCIPollingInterval"), 60); |
312 | DCObject::m_defaultRetentionTime = ConfigReadInt(_T("DefaultDCIRetentionTime"), 30); | |
9708eff4 | 313 | g_defaultAgentCacheMode = (INT16)ConfigReadInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF); |
e9902466 VK |
314 | if ((g_defaultAgentCacheMode != AGENT_CACHE_ON) && (g_defaultAgentCacheMode != AGENT_CACHE_OFF)) |
315 | { | |
316 | DbgPrintf(1, _T("Invalid value %d of DefaultAgentCacheMode: reset to %d (OFF)"), g_defaultAgentCacheMode, AGENT_CACHE_OFF); | |
317 | ConfigWriteInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF, true, true, true); | |
c1f07289 | 318 | g_defaultAgentCacheMode = AGENT_CACHE_OFF; |
e9902466 | 319 | } |
35f836fe | 320 | if (ConfigReadInt(_T("DeleteEmptySubnets"), 1)) |
c8076b19 | 321 | g_flags |= AF_DELETE_EMPTY_SUBNETS; |
35f836fe | 322 | if (ConfigReadInt(_T("EnableSNMPTraps"), 1)) |
c8076b19 VK |
323 | g_flags |= AF_ENABLE_SNMP_TRAPD; |
324 | if (ConfigReadInt(_T("ProcessTrapsFromUnmanagedNodes"), 0)) | |
325 | g_flags |= AF_TRAPS_FROM_UNMANAGED_NODES; | |
35f836fe | 326 | if (ConfigReadInt(_T("EnableZoning"), 0)) |
c8076b19 | 327 | g_flags |= AF_ENABLE_ZONING; |
549f48b3 | 328 | if (ConfigReadInt(_T("EnableObjectTransactions"), 0)) |
c8076b19 | 329 | g_flags |= AF_ENABLE_OBJECT_TRANSACTIONS; |
35f836fe | 330 | if (ConfigReadInt(_T("RunNetworkDiscovery"), 0)) |
c8076b19 | 331 | g_flags |= AF_ENABLE_NETWORK_DISCOVERY; |
35f836fe | 332 | if (ConfigReadInt(_T("ActiveNetworkDiscovery"), 0)) |
c8076b19 | 333 | g_flags |= AF_ACTIVE_NETWORK_DISCOVERY; |
e02953a4 | 334 | if (ConfigReadInt(_T("UseSNMPTrapsForDiscovery"), 0)) |
c8076b19 | 335 | g_flags |= AF_SNMP_TRAP_DISCOVERY; |
727b90ff VK |
336 | if (ConfigReadInt(_T("UseSyslogForDiscovery"), 0)) |
337 | g_flags |= AF_SYSLOG_DISCOVERY; | |
35f836fe | 338 | if (ConfigReadInt(_T("ResolveNodeNames"), 1)) |
c8076b19 | 339 | g_flags |= AF_RESOLVE_NODE_NAMES; |
35f836fe | 340 | if (ConfigReadInt(_T("SyncNodeNamesWithDNS"), 0)) |
c8076b19 | 341 | g_flags |= AF_SYNC_NODE_NAMES_WITH_DNS; |
35f836fe | 342 | if (ConfigReadInt(_T("CheckTrustedNodes"), 1)) |
c8076b19 | 343 | g_flags |= AF_CHECK_TRUSTED_NODES; |
3bbc7435 | 344 | if (ConfigReadInt(_T("EnableNXSLContainerFunctions"), 1)) |
c8076b19 | 345 | g_flags |= AF_ENABLE_NXSL_CONTAINER_FUNCS; |
f31c22b3 | 346 | if (ConfigReadInt(_T("UseFQDNForNodeNames"), 1)) |
c8076b19 | 347 | g_flags |= AF_USE_FQDN_FOR_NODE_NAMES; |
098ef635 | 348 | if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 1)) |
c8076b19 | 349 | g_flags |= AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE; |
4553d424 | 350 | if (ConfigReadInt(_T("ResolveDNSToIPOnStatusPoll"), 0)) |
385b1f20 | 351 | g_flags |= AF_RESOLVE_IP_FOR_EACH_STATUS_POLL; |
8a1519ce VK |
352 | if (ConfigReadInt(_T("CaseInsensitiveLoginNames"), 0)) |
353 | g_flags |= AF_CASE_INSENSITIVE_LOGINS; | |
0eff2ce4 VK |
354 | if (ConfigReadInt(_T("TrapSourcesInAllZones"), 0)) |
355 | g_flags |= AF_TRAP_SOURCES_IN_ALL_ZONES; | |
fc958888 | 356 | |
db6a6b45 | 357 | if (g_netxmsdDataDir[0] == 0) |
f31c22b3 | 358 | { |
1039d7ee VK |
359 | GetNetXMSDirectory(nxDirData, g_netxmsdDataDir); |
360 | DbgPrintf(1, _T("Data directory set to %s"), g_netxmsdDataDir); | |
f31c22b3 VK |
361 | } |
362 | else | |
363 | { | |
db6a6b45 | 364 | DbgPrintf(1, _T("Using data directory %s"), g_netxmsdDataDir); |
f31c22b3 | 365 | } |
d96bd4c7 | 366 | |
c59466d2 VK |
367 | g_icmpPingTimeout = ConfigReadInt(_T("IcmpPingTimeout"), 1500); |
368 | g_icmpPingSize = ConfigReadInt(_T("IcmpPingSize"), 46); | |
369 | g_lockTimeout = ConfigReadInt(_T("LockTimeout"), 60000); | |
c59466d2 VK |
370 | g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000); |
371 | g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0); | |
372 | g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1); | |
f6456d80 | 373 | g_offlineDataRelevanceTime = ConfigReadInt(_T("OfflineDataRelevanceTime"), 86400); |
296ae03d | 374 | |
014fbefc | 375 | UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 1500); |
296ae03d | 376 | SnmpSetDefaultTimeout(snmpTimeout); |
5039dede AK |
377 | } |
378 | ||
fdbee7f8 VK |
379 | /** |
380 | * Initialize cryptografic functions | |
381 | */ | |
cce82c3a | 382 | static bool InitCryptografy() |
5039dede AK |
383 | { |
384 | #ifdef _WITH_ENCRYPTION | |
cce82c3a | 385 | bool success = false; |
5039dede | 386 | |
2df047f4 | 387 | if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F))) |
5039dede | 388 | return FALSE; |
2df047f4 | 389 | nxlog_debug(4, _T("Supported ciphers: %s"), (const TCHAR *)NXCPGetSupportedCiphersAsText()); |
5039dede | 390 | |
958a9397 | 391 | SSL_library_init(); |
0fd5c0a1 | 392 | SSL_load_error_strings(); |
958a9397 | 393 | |
cce82c3a VK |
394 | if (LoadServerCertificate(&g_pServerKey)) |
395 | { | |
396 | nxlog_debug(1, _T("Server certificate loaded")); | |
397 | } | |
398 | if (g_pServerKey != NULL) | |
399 | { | |
400 | nxlog_debug(1, _T("Using server certificate key")); | |
401 | success = true; | |
402 | } | |
403 | else | |
404 | { | |
405 | TCHAR szKeyFile[MAX_PATH]; | |
406 | _tcscpy(szKeyFile, g_netxmsdDataDir); | |
407 | _tcscat(szKeyFile, DFILE_KEYS); | |
408 | g_pServerKey = LoadRSAKeys(szKeyFile); | |
409 | if (g_pServerKey == NULL) | |
410 | { | |
411 | nxlog_debug(1, _T("Generating RSA key pair...")); | |
3b89a4c1 | 412 | g_pServerKey = RSA_generate_key(NETXMS_RSA_KEYLEN, 17, NULL, NULL); |
cce82c3a VK |
413 | if (g_pServerKey != NULL) |
414 | { | |
415 | int fd = _topen(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600); | |
416 | if (fd != -1) | |
417 | { | |
418 | UINT32 dwLen = i2d_RSAPublicKey(g_pServerKey, NULL); | |
419 | dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL); | |
420 | BYTE *pKeyBuffer = (BYTE *)malloc(dwLen); | |
421 | ||
422 | BYTE *pBufPos = pKeyBuffer; | |
423 | i2d_RSAPublicKey(g_pServerKey, &pBufPos); | |
424 | i2d_RSAPrivateKey(g_pServerKey, &pBufPos); | |
425 | _write(fd, &dwLen, sizeof(UINT32)); | |
426 | _write(fd, pKeyBuffer, dwLen); | |
427 | ||
428 | BYTE hash[SHA1_DIGEST_SIZE]; | |
429 | CalculateSHA1Hash(pKeyBuffer, dwLen, hash); | |
430 | _write(fd, hash, SHA1_DIGEST_SIZE); | |
431 | ||
432 | _close(fd); | |
433 | free(pKeyBuffer); | |
434 | success = true; | |
435 | } | |
436 | else | |
437 | { | |
438 | nxlog_debug(0, _T("Failed to open %s for writing"), szKeyFile); | |
439 | } | |
440 | } | |
2df047f4 VK |
441 | else |
442 | { | |
cce82c3a | 443 | nxlog_debug(0, _T("Failed to generate RSA key")); |
2df047f4 | 444 | } |
cce82c3a | 445 | } |
c578be51 AK |
446 | else |
447 | { | |
cce82c3a | 448 | success = true; |
c578be51 | 449 | } |
cce82c3a | 450 | } |
5039dede | 451 | |
a3ef278b | 452 | int iPolicy = ConfigReadInt(_T("DefaultEncryptionPolicy"), 1); |
5039dede AK |
453 | if ((iPolicy < 0) || (iPolicy > 3)) |
454 | iPolicy = 1; | |
455 | SetAgentDEP(iPolicy); | |
456 | ||
cce82c3a | 457 | return success; |
5039dede AK |
458 | #else |
459 | return TRUE; | |
460 | #endif | |
461 | } | |
462 | ||
496390c2 VK |
463 | /** |
464 | * Check if process with given PID exists and is a NetXMS server process | |
465 | */ | |
fbd0079b | 466 | static bool IsNetxmsdProcess(UINT32 pid) |
5039dede AK |
467 | { |
468 | #ifdef _WIN32 | |
fbd0079b VK |
469 | bool result = false; |
470 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); | |
5039dede AK |
471 | if (hProcess != NULL) |
472 | { | |
fbd0079b | 473 | TCHAR szExtModule[MAX_PATH], szIntModule[MAX_PATH]; |
5039dede | 474 | if ((GetModuleBaseName(hProcess, NULL, szExtModule, MAX_PATH) > 0) && |
fbd0079b | 475 | (GetModuleBaseName(GetCurrentProcess(), NULL, szIntModule, MAX_PATH) > 0)) |
5039dede | 476 | { |
fbd0079b | 477 | result = (_tcsicmp(szExtModule, szIntModule) == 0); |
5039dede AK |
478 | } |
479 | else | |
480 | { | |
481 | // Cannot read process name, for safety assume that it's a server process | |
fbd0079b | 482 | result = true; |
5039dede AK |
483 | } |
484 | CloseHandle(hProcess); | |
485 | } | |
fbd0079b | 486 | return result; |
5039dede | 487 | #else |
fbd0079b | 488 | return kill((pid_t)pid, 0) != -1; |
5039dede AK |
489 | #endif |
490 | } | |
491 | ||
496390c2 | 492 | /** |
fbd0079b VK |
493 | * Check if remote netxmsd is running |
494 | */ | |
495 | static bool PeerNodeIsRunning(const InetAddress& addr) | |
496 | { | |
497 | bool result = false; | |
498 | ||
499 | TCHAR keyFile[MAX_PATH]; | |
500 | _tcscpy(keyFile, g_netxmsdDataDir); | |
501 | _tcscat(keyFile, DFILE_KEYS); | |
502 | RSA *key = LoadRSAKeys(keyFile); | |
503 | ||
504 | AgentConnection *ac = new AgentConnection(addr); | |
505 | if (ac->connect(key)) | |
506 | { | |
507 | TCHAR result[MAX_RESULT_LENGTH]; | |
508 | #ifdef _WIN32 | |
509 | UINT32 rcc = ac->getParameter(_T("Process.Count(netxmsd.exe)"), MAX_RESULT_LENGTH, result); | |
510 | #else | |
511 | UINT32 rcc = ac->getParameter(_T("Process.Count(netxmsd)"), MAX_RESULT_LENGTH, result); | |
512 | #endif | |
513 | ac->decRefCount(); | |
514 | if (key != NULL) | |
515 | RSA_free(key); | |
516 | if (rcc == ERR_SUCCESS) | |
517 | { | |
518 | return _tcstol(result, NULL, 10) > 0; | |
519 | } | |
520 | } | |
521 | else | |
522 | { | |
523 | ac->decRefCount(); | |
524 | if (key != NULL) | |
525 | RSA_free(key); | |
526 | } | |
527 | ||
528 | UINT16 port = (UINT16)ConfigReadInt(_T("ClientListenerPort"), SERVER_LISTEN_PORT_FOR_CLIENTS); | |
529 | SOCKET s = ConnectToHost(addr, port, 5000); | |
530 | if (s != INVALID_SOCKET) | |
531 | { | |
532 | shutdown(s, SHUT_RDWR); | |
533 | closesocket(s); | |
534 | result = true; | |
535 | } | |
536 | return result; | |
537 | } | |
538 | ||
539 | /** | |
496390c2 VK |
540 | * Database event handler |
541 | */ | |
526ae8b8 | 542 | static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, bool connLost, void *userArg) |
5039dede | 543 | { |
c8076b19 | 544 | if (!(g_flags & AF_SERVER_INITIALIZED)) |
5039dede AK |
545 | return; // Don't try to do anything if server is not ready yet |
546 | ||
547 | switch(dwEvent) | |
548 | { | |
549 | case DBEVENT_CONNECTION_LOST: | |
550 | PostEvent(EVENT_DB_CONNECTION_LOST, g_dwMgmtNode, NULL); | |
c8076b19 | 551 | g_flags |= AF_DB_CONNECTION_LOST; |
5039dede AK |
552 | NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, FALSE); |
553 | break; | |
554 | case DBEVENT_CONNECTION_RESTORED: | |
555 | PostEvent(EVENT_DB_CONNECTION_RESTORED, g_dwMgmtNode, NULL); | |
c8076b19 | 556 | g_flags &= ~AF_DB_CONNECTION_LOST; |
5039dede AK |
557 | NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, TRUE); |
558 | break; | |
4d0c32f3 | 559 | case DBEVENT_QUERY_FAILED: |
526ae8b8 | 560 | PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uud", pszArg1, pszArg2, connLost ? 1 : 0); |
4d0c32f3 | 561 | break; |
5039dede AK |
562 | default: |
563 | break; | |
564 | } | |
565 | } | |
566 | ||
496390c2 VK |
567 | /** |
568 | * Send console message to session with open console | |
569 | */ | |
f669df41 VK |
570 | static void SendConsoleMessage(ClientSession *session, void *arg) |
571 | { | |
572 | if (session->isConsoleOpen()) | |
573 | { | |
b368969c | 574 | NXCPMessage msg; |
f669df41 | 575 | |
b368969c VK |
576 | msg.setCode(CMD_ADM_MESSAGE); |
577 | msg.setField(VID_MESSAGE, (TCHAR *)arg); | |
d3a7cf4c | 578 | session->postMessage(&msg); |
f669df41 VK |
579 | } |
580 | } | |
581 | ||
d6217efa VK |
582 | /** |
583 | * Console writer | |
584 | */ | |
f669df41 VK |
585 | static void LogConsoleWriter(const TCHAR *format, ...) |
586 | { | |
587 | TCHAR buffer[8192]; | |
588 | va_list args; | |
589 | ||
590 | va_start(args, format); | |
591 | _vsntprintf(buffer, 8192, format, args); | |
592 | buffer[8191] = 0; | |
593 | va_end(args); | |
594 | ||
595 | WriteToTerminal(buffer); | |
596 | ||
597 | EnumerateClientSessions(SendConsoleMessage, buffer); | |
598 | } | |
599 | ||
fdbee7f8 | 600 | /** |
b6aff59d VK |
601 | * Oracle session init callback |
602 | */ | |
603 | static void OracleSessionInitCallback(DB_HANDLE hdb) | |
604 | { | |
605 | DBQuery(hdb, _T("ALTER SESSION SET DDL_LOCK_TIMEOUT = 60")); | |
606 | } | |
607 | ||
608 | /** | |
4a64a795 VK |
609 | * Get database password |
610 | */ | |
611 | static void GetDatabasePassword() | |
612 | { | |
613 | if (_tcscmp(g_szDbPassword, _T("?"))) | |
614 | return; | |
615 | ||
616 | nxlog_write(MSG_WAITING_FOR_DB_PASSWORD, NXLOG_INFO, NULL); | |
617 | g_dbPasswordReady.wait(INFINITE); | |
618 | nxlog_debug(1, _T("Database password received")); | |
619 | } | |
620 | ||
621 | /** | |
fdbee7f8 VK |
622 | * Server initialization |
623 | */ | |
bc980b27 | 624 | BOOL NXCORE_EXPORTABLE Initialize() |
5039dede | 625 | { |
4fd0b7ca | 626 | s_components.add(_T("CORE")); |
5039dede | 627 | |
c59466d2 VK |
628 | g_serverStartTime = time(NULL); |
629 | srand((unsigned int)g_serverStartTime); | |
4f8998ca | 630 | |
c8076b19 | 631 | if (!(g_flags & AF_USE_SYSLOG)) |
4f8998ca | 632 | { |
458b5d2b | 633 | if (!nxlog_set_rotation_policy((int)g_logRotationMode, g_maxLogSize, (int)g_logHistorySize, g_szDailyLogFileSuffix)) |
c8076b19 | 634 | if (!(g_flags & AF_DAEMON)) |
4f8998ca VK |
635 | _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n")); |
636 | } | |
c8076b19 | 637 | if (!nxlog_open((g_flags & AF_USE_SYSLOG) ? NETXMSD_SYSLOG_NAME : g_szLogFile, |
2589cc10 | 638 | ((g_flags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) | |
639 | ((g_flags & AF_BACKGROUND_LOG_WRITER) ? NXLOG_BACKGROUND_WRITER : 0) | | |
4e0e77e6 | 640 | ((g_flags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT), |
9d381279 | 641 | _T("LIBNXSRV.DLL"), |
5039dede | 642 | #ifdef _WIN32 |
7615283c | 643 | 0, NULL, MSG_DEBUG, MSG_OTHER)) |
5039dede | 644 | #else |
90a9e65e | 645 | g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_OTHER)) |
5039dede | 646 | #endif |
9d381279 VK |
647 | { |
648 | _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n")); | |
649 | return FALSE; | |
650 | } | |
f669df41 | 651 | nxlog_set_console_writer(LogConsoleWriter); |
5039dede | 652 | |
2df047f4 VK |
653 | if (g_netxmsdLibDir[0] == 0) |
654 | { | |
655 | GetNetXMSDirectory(nxDirLib, g_netxmsdLibDir); | |
656 | nxlog_debug(1, _T("LIB directory set to %s"), g_netxmsdLibDir); | |
657 | } | |
658 | ||
5039dede AK |
659 | // Set code page |
660 | #ifndef _WIN32 | |
661 | if (SetDefaultCodepage(g_szCodePage)) | |
662 | { | |
f5797a09 | 663 | DbgPrintf(1, _T("Code page set to %hs"), g_szCodePage); |
5039dede AK |
664 | } |
665 | else | |
666 | { | |
f375019e | 667 | nxlog_write(MSG_CODEPAGE_ERROR, EVENTLOG_WARNING_TYPE, "m", g_szCodePage); |
5039dede AK |
668 | } |
669 | #endif | |
670 | ||
73869331 VK |
671 | // Set process affinity mask |
672 | if (g_processAffinityMask != DEFAULT_AFFINITY_MASK) | |
673 | { | |
674 | #ifdef _WIN32 | |
675 | if (SetProcessAffinityMask(GetCurrentProcess(), g_processAffinityMask)) | |
2df047f4 | 676 | nxlog_debug(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask); |
73869331 VK |
677 | #else |
678 | nxlog_write(MSG_SET_PROCESS_AFFINITY_NOT_SUPPORTED, EVENTLOG_WARNING_TYPE, NULL); | |
679 | #endif | |
680 | } | |
681 | ||
5039dede AK |
682 | #ifdef _WIN32 |
683 | WSADATA wsaData; | |
1ddf3f0c VK |
684 | int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData); |
685 | if (wrc != 0) | |
686 | { | |
687 | nxlog_write(MSG_WSASTARTUP_FAILED, EVENTLOG_ERROR_TYPE, "e", wrc); | |
688 | return FALSE; | |
689 | } | |
5039dede AK |
690 | #endif |
691 | ||
692 | InitLocalNetInfo(); | |
296ae03d | 693 | SnmpSetMessageIds(MSG_OID_PARSE_ERROR, MSG_SNMP_UNKNOWN_TYPE, MSG_SNMP_GET_ERROR); |
5039dede AK |
694 | |
695 | // Create queue for delayed SQL queries | |
76fcb995 VK |
696 | g_dbWriterQueue = new Queue(256, 64); |
697 | g_dciDataWriterQueue = new Queue(1024, 1024); | |
698 | g_dciRawDataWriterQueue = new Queue(1024, 1024); | |
5039dede AK |
699 | |
700 | // Initialize database driver and connect to database | |
c8076b19 | 701 | if (!DBInit(MSG_OTHER, (g_flags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0)) |
b8c1ec69 | 702 | return FALSE; |
2df047f4 | 703 | g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (nxlog_get_debug_level() >= 9), DBEventHandler, NULL); |
b8c1ec69 | 704 | if (g_dbDriver == NULL) |
5039dede AK |
705 | return FALSE; |
706 | ||
4a64a795 VK |
707 | // Start local administrative interface listener if required |
708 | if (g_flags & AF_ENABLE_LOCAL_CONSOLE) | |
709 | ThreadCreate(LocalAdminListener, 0, NULL); | |
710 | ||
711 | // Wait for database password if needed | |
712 | GetDatabasePassword(); | |
713 | ||
5039dede | 714 | // Connect to database |
9bd1bace | 715 | DB_HANDLE hdbBootstrap = NULL; |
465b3f2d | 716 | TCHAR errorText[DBDRV_MAX_ERROR_TEXT]; |
4fd0b7ca | 717 | for(int i = 0; ; i++) |
5039dede | 718 | { |
9bd1bace VK |
719 | hdbBootstrap = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText); |
720 | if ((hdbBootstrap != NULL) || (i == 5)) | |
5039dede AK |
721 | break; |
722 | ThreadSleep(5); | |
723 | } | |
9bd1bace | 724 | if (hdbBootstrap == NULL) |
5039dede | 725 | { |
465b3f2d | 726 | nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, "s", errorText); |
5039dede AK |
727 | return FALSE; |
728 | } | |
2df047f4 | 729 | nxlog_debug(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer); |
5039dede | 730 | |
4fd0b7ca VK |
731 | // Check database schema version |
732 | int schemaVersion = DBGetSchemaVersion(hdbBootstrap); | |
733 | if (schemaVersion != DB_FORMAT_VERSION) | |
5039dede | 734 | { |
4fd0b7ca | 735 | nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", schemaVersion, DB_FORMAT_VERSION); |
9bd1bace | 736 | DBDisconnect(hdbBootstrap); |
5039dede AK |
737 | return FALSE; |
738 | } | |
739 | ||
b6aff59d | 740 | // Read database syntax |
9bd1bace | 741 | g_dbSyntax = DBGetSyntax(hdbBootstrap); |
b6aff59d VK |
742 | if (g_dbSyntax == DB_SYNTAX_ORACLE) |
743 | { | |
744 | DBSetSessionInitCallback(OracleSessionInitCallback); | |
745 | } | |
746 | ||
9bd1bace VK |
747 | int baseSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolBaseSize"), 10); |
748 | int maxSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxSize"), 30); | |
749 | int cooldownTime = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolCooldownTime"), 300); | |
750 | int ttl = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxLifetime"), 14400); | |
751 | ||
752 | DBDisconnect(hdbBootstrap); | |
753 | ||
754 | if (!DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, ttl)) | |
755 | { | |
756 | nxlog_write(MSG_DBCONNPOOL_INIT_FAILED, EVENTLOG_ERROR_TYPE, NULL); | |
757 | return FALSE; | |
758 | } | |
f727d089 | 759 | |
58f1f627 VK |
760 | UINT32 lrt = ConfigReadULong(_T("LongRunningQueryThreshold"), 0); |
761 | if (lrt != 0) | |
762 | DBSetLongRunningThreshold(lrt); | |
763 | ||
0fdb37c6 VK |
764 | MetaDataPreLoad(); |
765 | ||
5039dede | 766 | // Read server ID |
4fd0b7ca VK |
767 | TCHAR buffer[256]; |
768 | MetaDataReadStr(_T("ServerID"), buffer, 256, _T("")); | |
769 | StrStrip(buffer); | |
770 | if (buffer[0] != 0) | |
5039dede | 771 | { |
4fd0b7ca | 772 | g_serverId = _tcstoull(buffer, NULL, 16); |
5039dede AK |
773 | } |
774 | else | |
775 | { | |
776 | // Generate new ID | |
e9902466 | 777 | g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF); |
4fd0b7ca VK |
778 | _sntprintf(buffer, 256, UINT64X_FMT(_T("016")), g_serverId); |
779 | MetaDataWriteStr(_T("ServerID"), buffer); | |
5039dede | 780 | } |
2df047f4 | 781 | nxlog_debug(1, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId); |
5039dede AK |
782 | |
783 | // Initialize locks | |
784 | retry_db_lock: | |
c30c0c0f | 785 | InetAddress addr; |
4fd0b7ca | 786 | if (!InitLocks(&addr, buffer)) |
5039dede | 787 | { |
fbd0079b | 788 | if (addr.isValidUnicast()) // Database already locked by another server instance |
5039dede AK |
789 | { |
790 | // Check for lock from crashed/terminated local process | |
c30c0c0f | 791 | if (GetLocalIpAddr().equals(addr)) |
5039dede | 792 | { |
fbd0079b VK |
793 | UINT32 pid = ConfigReadULong(_T("DBLockPID"), 0); |
794 | if (!IsNetxmsdProcess(pid) || (pid == GetCurrentProcessId())) | |
5039dede AK |
795 | { |
796 | UnlockDB(); | |
797 | nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL); | |
798 | goto retry_db_lock; | |
799 | } | |
800 | } | |
fbd0079b VK |
801 | else if (g_peerNodeAddrList.hasAddress(addr)) |
802 | { | |
803 | if (!PeerNodeIsRunning(addr)) | |
804 | { | |
805 | UnlockDB(); | |
806 | nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL); | |
807 | goto retry_db_lock; | |
808 | } | |
809 | } | |
d94ada36 | 810 | nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "Is", &addr, buffer); |
5039dede | 811 | } |
fbd0079b VK |
812 | else |
813 | { | |
814 | nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL); | |
815 | } | |
5039dede AK |
816 | return FALSE; |
817 | } | |
c8076b19 | 818 | g_flags |= AF_DB_LOCKED; |
5039dede AK |
819 | |
820 | // Load global configuration parameters | |
821 | LoadGlobalConfig(); | |
958a9397 | 822 | CASReadSettings(); |
2df047f4 | 823 | nxlog_debug(1, _T("Global configuration loaded")); |
5039dede AK |
824 | |
825 | // Check data directory | |
826 | if (!CheckDataDir()) | |
827 | return FALSE; | |
828 | ||
829 | // Initialize cryptografy | |
830 | if (!InitCryptografy()) | |
831 | { | |
832 | nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL); | |
833 | return FALSE; | |
834 | } | |
835 | ||
836 | // Initialize certificate store and CA | |
837 | InitCertificates(); | |
838 | ||
5039dede AK |
839 | // Create synchronization stuff |
840 | m_condShutdown = ConditionCreate(TRUE); | |
841 | ||
5d3459af | 842 | // Create thread pools |
2df047f4 | 843 | nxlog_debug(2, _T("Creating thread pools")); |
5d3459af | 844 | g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN")); |
1693f955 | 845 | g_agentConnectionThreadPool = ThreadPoolCreate(4, 256, _T("AGENT")); |
5d3459af | 846 | |
5039dede AK |
847 | // Setup unique identifiers table |
848 | if (!InitIdTable()) | |
849 | return FALSE; | |
2df047f4 | 850 | nxlog_debug(2, _T("ID table created")); |
5039dede | 851 | |
0de31ec3 VK |
852 | InitCountryList(); |
853 | InitCurrencyList(); | |
854 | ||
24dc5346 | 855 | // Update status for unfinished jobs in job history |
9bd1bace VK |
856 | DB_HANDLE hdb = DBConnectionPoolAcquireConnection(); |
857 | DBQuery(hdb, _T("UPDATE job_history SET status=4,failure_message='Aborted due to server shutdown or crash' WHERE status NOT IN (3,4,5)")); | |
858 | DBConnectionPoolReleaseConnection(hdb); | |
24dc5346 | 859 | |
5039dede AK |
860 | // Load and compile scripts |
861 | LoadScripts(); | |
862 | ||
00420032 | 863 | // Initialize persistent storage |
864 | PersistentStorageInit(); | |
865 | ||
f7e4c50e VK |
866 | // Initialize watchdog |
867 | WatchdogInit(); | |
868 | ||
53d2de79 | 869 | // Load modules |
890478d8 VK |
870 | if (!LoadNetXMSModules()) |
871 | return FALSE; // Mandatory module not loaded | |
288a0046 | 872 | RegisterPredictionEngines(); |
53d2de79 | 873 | |
5039dede AK |
874 | // Initialize mailer and SMS sender |
875 | InitMailer(); | |
876 | InitSMSSender(); | |
877 | ||
878 | // Load users from database | |
ab185583 | 879 | InitUsers(); |
5039dede AK |
880 | if (!LoadUsers()) |
881 | { | |
882 | nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL); | |
883 | return FALSE; | |
884 | } | |
2df047f4 | 885 | nxlog_debug(2, _T("User accounts loaded")); |
5039dede AK |
886 | |
887 | // Initialize audit | |
888 | InitAuditLog(); | |
889 | ||
da84c57a VK |
890 | // Initialize event handling subsystem |
891 | if (!InitEventSubsystem()) | |
892 | return FALSE; | |
893 | ||
894 | // Initialize alarms | |
e30c2442 | 895 | LoadAlarmCategories(); |
da84c57a VK |
896 | if (!InitAlarmManager()) |
897 | return FALSE; | |
898 | ||
5039dede | 899 | // Initialize objects infrastructure and load objects from database |
9796ce45 | 900 | LoadNetworkDeviceDrivers(); |
5039dede AK |
901 | ObjectsInit(); |
902 | if (!LoadObjects()) | |
903 | return FALSE; | |
2df047f4 | 904 | nxlog_debug(1, _T("Objects loaded and initialized")); |
d9177dd1 | 905 | |
5039dede AK |
906 | // Initialize and load event actions |
907 | if (!InitActions()) | |
908 | { | |
909 | nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL); | |
910 | return FALSE; | |
911 | } | |
912 | ||
6fad8870 VK |
913 | // Initialize helpdesk link |
914 | SetHDLinkEntryPoints(ResolveAlarmByHDRef, TerminateAlarmByHDRef); | |
915 | LoadHelpDeskLink(); | |
916 | ||
5039dede | 917 | // Initialize data collection subsystem |
8fd95c92 | 918 | LoadPerfDataStorageDrivers(); |
5039dede AK |
919 | if (!InitDataCollector()) |
920 | return FALSE; | |
921 | ||
e05b1945 | 922 | InitLogAccess(); |
d77baddd | 923 | FileUploadJob::init(); |
fdbee7f8 | 924 | InitMappingTables(); |
e05b1945 | 925 | |
03b96461 VK |
926 | InitClientListeners(); |
927 | if (ConfigReadInt(_T("ImportConfigurationOnStartup"), 1)) | |
928 | ImportLocalConfiguration(); | |
929 | ||
5039dede AK |
930 | // Check if management node object presented in database |
931 | CheckForMgmtNode(); | |
932 | if (g_dwMgmtNode == 0) | |
933 | { | |
934 | nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL); | |
935 | return FALSE; | |
936 | } | |
937 | ||
938 | // Start threads | |
939 | ThreadCreate(WatchdogThread, 0, NULL); | |
940 | ThreadCreate(NodePoller, 0, NULL); | |
3929b1ca | 941 | ThreadCreate(JobManagerThread, 0, NULL); |
5039dede | 942 | m_thSyncer = ThreadCreateEx(Syncer, 0, NULL); |
5039dede AK |
943 | m_thPollManager = ThreadCreateEx(PollManager, 0, NULL); |
944 | ||
a64c346b VK |
945 | StartHouseKeeper(); |
946 | ||
5039dede AK |
947 | // Start event processor |
948 | ThreadCreate(EventProcessor, 0, NULL); | |
949 | ||
950 | // Start SNMP trapper | |
951 | InitTraps(); | |
35f836fe | 952 | if (ConfigReadInt(_T("EnableSNMPTraps"), 1)) |
5039dede AK |
953 | ThreadCreate(SNMPTrapReceiver, 0, NULL); |
954 | ||
955 | // Start built-in syslog daemon | |
685508a7 | 956 | StartSyslogServer(); |
5039dede | 957 | |
35f836fe | 958 | // Start database _T("lazy") write thread |
5039dede AK |
959 | StartDBWriter(); |
960 | ||
5039dede AK |
961 | // Start beacon host poller |
962 | ThreadCreate(BeaconPoller, 0, NULL); | |
963 | ||
964 | // Start inter-server communication listener | |
35f836fe | 965 | if (ConfigReadInt(_T("EnableISCListener"), 0)) |
5039dede AK |
966 | ThreadCreate(ISCListener, 0, NULL); |
967 | ||
d75003e1 AK |
968 | // Start reporting server connector |
969 | if (ConfigReadInt(_T("EnableReportingServer"), 0)) | |
970 | ThreadCreate(ReportingServerConnector, 0, NULL); | |
971 | ||
d9177dd1 | 972 | //Start ldap synchronization |
973 | if (ConfigReadInt(_T("LdapSyncInterval"), 0)) | |
974 | ThreadCreate(SyncLDAPUsers, 0, NULL); | |
975 | ||
ec13a467 VK |
976 | RegisterSchedulerTaskHandler(_T("Execute.Script"), ExecuteScheduledScript, SYSTEM_ACCESS_SCHEDULE_SCRIPT); |
977 | RegisterSchedulerTaskHandler(_T("Maintenance.Enter"), MaintenanceModeEnter, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE); | |
978 | RegisterSchedulerTaskHandler(_T("Maintenance.Leave"), MaintenanceModeLeave, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE); | |
82deb2d7 TD |
979 | RegisterSchedulerTaskHandler(_T("Policy.Deploy"), ScheduleDeployPolicy, 0); //No access right beacause it will be used only by server |
980 | RegisterSchedulerTaskHandler(_T("Policy.Uninstall"), ScheduleUninstallPolicy, 0); //No access right beacause it will be used only by server | |
ed0a30ba | 981 | RegisterSchedulerTaskHandler(ALARM_SUMMARY_EMAIL_TASK_ID, SendAlarmSummaryEmail, 0); //No access right beacause it will be used only by server |
0a145c10 | 982 | InitializeTaskScheduler(); |
983 | ||
f14e669f EJ |
984 | // Send summary emails |
985 | if (ConfigReadInt(_T("EnableAlarmSummaryEmails"), 0)) | |
986 | EnableAlarmSummaryEmails(); | |
987 | else | |
ed0a30ba | 988 | RemoveScheduledTaskByHandlerId(ALARM_SUMMARY_EMAIL_TASK_ID); |
f14e669f | 989 | |
5039dede AK |
990 | // Allow clients to connect |
991 | ThreadCreate(ClientListener, 0, NULL); | |
36e44abe VK |
992 | #ifdef WITH_IPV6 |
993 | ThreadCreate(ClientListenerIPv6, 0, NULL); | |
994 | #endif | |
5039dede | 995 | |
534e1b83 VK |
996 | // Allow mobile devices to connect |
997 | InitMobileDeviceListeners(); | |
998 | ThreadCreate(MobileDeviceListener, 0, NULL); | |
999 | #ifdef WITH_IPV6 | |
1000 | ThreadCreate(MobileDeviceListenerIPv6, 0, NULL); | |
1001 | #endif | |
1002 | ||
bf306af3 VK |
1003 | // Agent tunnels |
1004 | s_tunnelListenerThread = ThreadCreateEx(TunnelListener, 0, NULL); | |
1005 | ||
86457857 AK |
1006 | // Start uptime calculator for SLM |
1007 | ThreadCreate(UptimeCalculator, 0, NULL); | |
1008 | ||
2df047f4 | 1009 | nxlog_debug(2, _T("LIBDIR: %s"), g_netxmsdLibDir); |
712dd47d | 1010 | |
1b42a673 | 1011 | // Call startup functions for the modules |
a0efa7b5 | 1012 | CALL_ALL_MODULES(pfServerStarted, ()); |
53d2de79 | 1013 | |
058bf6fc | 1014 | #if XMPP_SUPPORTED |
244c65ef VK |
1015 | if (ConfigReadInt(_T("EnableXMPPConnector"), 1)) |
1016 | { | |
098ef635 | 1017 | StartXMPPConnector(); |
244c65ef | 1018 | } |
058bf6fc | 1019 | #endif |
244c65ef | 1020 | |
9df36f62 AK |
1021 | #if WITH_ZMQ |
1022 | StartZMQConnector(); | |
1023 | #endif | |
1024 | ||
cf4260a7 VK |
1025 | ExecuteStartupScripts(); |
1026 | ||
c8076b19 | 1027 | g_flags |= AF_SERVER_INITIALIZED; |
2df047f4 | 1028 | nxlog_debug(1, _T("Server initialization completed")); |
5039dede AK |
1029 | return TRUE; |
1030 | } | |
1031 | ||
371d9c60 VK |
1032 | /** |
1033 | * Server shutdown | |
1034 | */ | |
035a4d73 | 1035 | void NXCORE_EXPORTABLE Shutdown() |
5039dede | 1036 | { |
5039dede AK |
1037 | // Notify clients |
1038 | NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0); | |
1039 | ||
1040 | nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL); | |
c8076b19 | 1041 | g_flags |= AF_SHUTDOWN; // Set shutdown flag |
5039dede AK |
1042 | ConditionSet(m_condShutdown); |
1043 | ||
0a145c10 | 1044 | CloseTaskScheduler(); |
1045 | ||
d140955e | 1046 | // Stop DCI cache loading thread |
19dbc8ef | 1047 | g_dciCacheLoaderQueue.setShutdownMode(); |
d140955e | 1048 | |
058bf6fc | 1049 | #if XMPP_SUPPORTED |
244c65ef | 1050 | StopXMPPConnector(); |
058bf6fc | 1051 | #endif |
244c65ef | 1052 | |
9df36f62 AK |
1053 | #if WITH_ZMQ |
1054 | StopZMQConnector(); | |
1055 | #endif | |
1056 | ||
19dbc8ef VK |
1057 | g_pEventQueue->clear(); |
1058 | g_pEventQueue->put(INVALID_POINTER_VALUE); | |
5039dede AK |
1059 | |
1060 | ShutdownMailer(); | |
1061 | ShutdownSMSSender(); | |
1062 | ||
1063 | ThreadSleep(1); // Give other threads a chance to terminate in a safe way | |
2df047f4 | 1064 | nxlog_debug(2, _T("All threads was notified, continue with shutdown")); |
5039dede | 1065 | |
af4a09df | 1066 | StopSyslogServer(); |
a64c346b | 1067 | StopHouseKeeper(); |
af4a09df | 1068 | |
5039dede | 1069 | // Wait for critical threads |
5039dede AK |
1070 | ThreadJoin(m_thPollManager); |
1071 | ThreadJoin(m_thSyncer); | |
bf306af3 VK |
1072 | ThreadJoin(s_tunnelListenerThread); |
1073 | ||
1074 | CloseAgentTunnels(); | |
5039dede | 1075 | |
a0efa7b5 VK |
1076 | // Call shutdown functions for the modules |
1077 | // CALL_ALL_MODULES cannot be used here because it checks for shutdown flag | |
1078 | for(UINT32 i = 0; i < g_dwNumModules; i++) | |
1079 | { | |
1080 | if (g_pModuleList[i].pfShutdown != NULL) | |
1081 | g_pModuleList[i].pfShutdown(); | |
1082 | } | |
1083 | ||
9bd1bace | 1084 | DB_HANDLE hdb = DBConnectionPoolAcquireConnection(); |
83b1c107 | 1085 | SaveObjects(hdb, INVALID_INDEX); |
2df047f4 | 1086 | nxlog_debug(2, _T("All objects saved to database")); |
83b1c107 | 1087 | SaveUsers(hdb, INVALID_INDEX); |
2df047f4 | 1088 | nxlog_debug(2, _T("All users saved to database")); |
76d77587 | 1089 | UpdatePStorageDatabase(hdb, INVALID_INDEX); |
1090 | nxlog_debug(2, _T("All persistent storage values saved")); | |
9bd1bace VK |
1091 | DBConnectionPoolReleaseConnection(hdb); |
1092 | ||
5039dede | 1093 | StopDBWriter(); |
2df047f4 | 1094 | nxlog_debug(1, _T("Database writer stopped")); |
5039dede | 1095 | |
ab185583 | 1096 | CleanupUsers(); |
7b45b90d | 1097 | PersistentStorageDestroy(); |
ab185583 | 1098 | |
5039dede AK |
1099 | // Remove database lock |
1100 | UnlockDB(); | |
1101 | ||
7a7dfb3e | 1102 | DBConnectionPoolShutdown(); |
b8c1ec69 | 1103 | DBUnloadDriver(g_dbDriver); |
2df047f4 | 1104 | nxlog_debug(1, _T("Database driver unloaded")); |
5039dede AK |
1105 | |
1106 | CleanupActions(); | |
1107 | ShutdownEventSubsystem(); | |
da84c57a | 1108 | ShutdownAlarmManager(); |
2df047f4 | 1109 | nxlog_debug(1, _T("Event processing stopped")); |
5039dede | 1110 | |
1693f955 | 1111 | ThreadPoolDestroy(g_agentConnectionThreadPool); |
5d3459af | 1112 | ThreadPoolDestroy(g_mainThreadPool); |
d87ddcc2 | 1113 | MsgWaitQueue::shutdown(); |
83b1c107 | 1114 | WatchdogShutdown(); |
5d3459af | 1115 | |
2df047f4 | 1116 | nxlog_debug(1, _T("Server shutdown complete")); |
5039dede AK |
1117 | nxlog_close(); |
1118 | ||
1119 | // Remove PID file | |
1120 | #ifndef _WIN32 | |
dda7c270 | 1121 | _tremove(g_szPIDFile); |
5039dede AK |
1122 | #endif |
1123 | ||
1124 | // Terminate process | |
1125 | #ifdef _WIN32 | |
c8076b19 | 1126 | if (!(g_flags & AF_DAEMON)) |
5039dede AK |
1127 | ExitProcess(0); |
1128 | #else | |
1129 | exit(0); | |
1130 | #endif | |
1131 | } | |
1132 | ||
371d9c60 VK |
1133 | /** |
1134 | * Fast server shutdown - normally called only by Windows service on system shutdown | |
1135 | */ | |
f669df41 | 1136 | void NXCORE_EXPORTABLE FastShutdown() |
5039dede | 1137 | { |
bc9263d1 VK |
1138 | DbgPrintf(1, _T("Using fast shutdown procedure")); |
1139 | ||
c8076b19 | 1140 | g_flags |= AF_SHUTDOWN; // Set shutdown flag |
5039dede AK |
1141 | ConditionSet(m_condShutdown); |
1142 | ||
9bd1bace | 1143 | DB_HANDLE hdb = DBConnectionPoolAcquireConnection(); |
83b1c107 | 1144 | SaveObjects(hdb, INVALID_INDEX); |
35f836fe | 1145 | DbgPrintf(2, _T("All objects saved to database")); |
83b1c107 | 1146 | SaveUsers(hdb, INVALID_INDEX); |
35f836fe | 1147 | DbgPrintf(2, _T("All users saved to database")); |
76d77587 | 1148 | UpdatePStorageDatabase(hdb, INVALID_INDEX); |
1149 | DbgPrintf(2, _T("All persistent storage values saved")); | |
9bd1bace | 1150 | DBConnectionPoolReleaseConnection(hdb); |
5039dede | 1151 | |
9bd1bace | 1152 | // Remove database lock first, because we have a chance to lose DB connection |
5039dede AK |
1153 | UnlockDB(); |
1154 | ||
1155 | // Stop database writers | |
1156 | StopDBWriter(); | |
35f836fe | 1157 | DbgPrintf(1, _T("Database writer stopped")); |
5039dede | 1158 | |
bc9263d1 | 1159 | DbgPrintf(1, _T("Server shutdown complete")); |
5039dede AK |
1160 | nxlog_close(); |
1161 | } | |
1162 | ||
fdbee7f8 | 1163 | /** |
fdbee7f8 VK |
1164 | * Signal handler for UNIX platforms |
1165 | */ | |
5039dede AK |
1166 | #ifndef _WIN32 |
1167 | ||
1168 | void SignalHandlerStub(int nSignal) | |
1169 | { | |
1170 | // should be unused, but JIC... | |
1171 | if (nSignal == SIGCHLD) | |
1172 | { | |
1173 | while (waitpid(-1, NULL, WNOHANG) > 0) | |
1174 | ; | |
1175 | } | |
1176 | } | |
1177 | ||
1178 | THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg) | |
1179 | { | |
1180 | sigset_t signals; | |
1181 | int nSignal; | |
5039dede AK |
1182 | |
1183 | m_signalHandlerThread = pthread_self(); | |
1184 | ||
1185 | // default for SIGCHLD: ignore | |
1186 | signal(SIGCHLD, &SignalHandlerStub); | |
1187 | ||
1188 | sigemptyset(&signals); | |
1189 | sigaddset(&signals, SIGTERM); | |
1190 | sigaddset(&signals, SIGINT); | |
5039dede AK |
1191 | sigaddset(&signals, SIGSEGV); |
1192 | sigaddset(&signals, SIGCHLD); | |
1193 | sigaddset(&signals, SIGHUP); | |
1194 | sigaddset(&signals, SIGUSR1); | |
1195 | sigaddset(&signals, SIGUSR2); | |
95e2329a VK |
1196 | #if !defined(__sun) && !defined(_AIX) && !defined(__hpux) |
1197 | sigaddset(&signals, SIGPIPE); | |
1198 | #endif | |
5039dede AK |
1199 | |
1200 | sigprocmask(SIG_BLOCK, &signals, NULL); | |
1201 | ||
1202 | while(1) | |
1203 | { | |
1204 | if (sigwait(&signals, &nSignal) == 0) | |
1205 | { | |
1206 | switch(nSignal) | |
1207 | { | |
1208 | case SIGTERM: | |
1209 | case SIGINT: | |
bc9263d1 VK |
1210 | // avoid repeat Shutdown() call |
1211 | if (!(g_flags & AF_SHUTDOWN)) | |
1212 | { | |
1213 | m_nShutdownReason = SHUTDOWN_BY_SIGNAL; | |
1214 | if (IsStandalone()) | |
1215 | Shutdown(); // will never return | |
1216 | else | |
1217 | ConditionSet(m_condShutdown); | |
1218 | } | |
1219 | break; | |
5039dede AK |
1220 | case SIGSEGV: |
1221 | abort(); | |
1222 | break; | |
1223 | case SIGCHLD: | |
1224 | while (waitpid(-1, NULL, WNOHANG) > 0) | |
1225 | ; | |
1226 | break; | |
1227 | case SIGUSR1: | |
c8076b19 | 1228 | if (g_flags & AF_SHUTDOWN) |
5039dede AK |
1229 | goto stop_handler; |
1230 | break; | |
1231 | default: | |
1232 | break; | |
1233 | } | |
1234 | } | |
1235 | else | |
1236 | { | |
1237 | ThreadSleepMs(100); | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | stop_handler: | |
1242 | sigprocmask(SIG_UNBLOCK, &signals, NULL); | |
5039dede AK |
1243 | return THREAD_OK; |
1244 | } | |
1245 | ||
1246 | #endif | |
1247 | ||
fdbee7f8 VK |
1248 | /** |
1249 | * Common main() | |
1250 | */ | |
5039dede AK |
1251 | THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg) |
1252 | { | |
1253 | nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL); | |
1254 | ||
7bdb43c3 VK |
1255 | if (IsStandalone()) |
1256 | { | |
c8076b19 | 1257 | if (!(g_flags & AF_DEBUG_CONSOLE_DISABLED)) |
7bdb43c3 VK |
1258 | { |
1259 | char *ptr, szCommand[256]; | |
1260 | struct __console_ctx ctx; | |
35f836fe | 1261 | #ifdef UNICODE |
7bdb43c3 | 1262 | WCHAR wcCommand[256]; |
35f836fe | 1263 | #endif |
5039dede | 1264 | |
7bdb43c3 VK |
1265 | ctx.hSocket = -1; |
1266 | ctx.socketMutex = INVALID_MUTEX_HANDLE; | |
1267 | ctx.pMsg = NULL; | |
1268 | ctx.session = NULL; | |
1269 | ctx.output = NULL; | |
8e17001f | 1270 | WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T(" Ready\n") |
7bdb43c3 VK |
1271 | _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n") |
1272 | _T("System Console\n\n")); | |
5039dede AK |
1273 | |
1274 | #if USE_READLINE | |
7bdb43c3 VK |
1275 | // Initialize readline library if we use it |
1276 | rl_bind_key('\t', RL_INSERT_CAST rl_insert); | |
5039dede AK |
1277 | #endif |
1278 | ||
7bdb43c3 VK |
1279 | while(1) |
1280 | { | |
5039dede | 1281 | #if USE_READLINE |
7bdb43c3 | 1282 | ptr = readline("\x1b[33mnetxmsd:\x1b[0m "); |
5039dede | 1283 | #else |
7bdb43c3 VK |
1284 | WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m ")); |
1285 | fflush(stdout); | |
1286 | if (fgets(szCommand, 255, stdin) == NULL) | |
1287 | break; // Error reading stdin | |
1288 | ptr = strchr(szCommand, '\n'); | |
1289 | if (ptr != NULL) | |
1290 | *ptr = 0; | |
1291 | ptr = szCommand; | |
5039dede AK |
1292 | #endif |
1293 | ||
7bdb43c3 VK |
1294 | if (ptr != NULL) |
1295 | { | |
35f836fe | 1296 | #ifdef UNICODE |
fe8ea784 VK |
1297 | #if HAVE_MBSTOWCS |
1298 | mbstowcs(wcCommand, ptr, 255); | |
1299 | #else | |
7bdb43c3 | 1300 | MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256); |
fe8ea784 | 1301 | #endif |
7bdb43c3 VK |
1302 | wcCommand[255] = 0; |
1303 | StrStrip(wcCommand); | |
1304 | if (wcCommand[0] != 0) | |
1305 | { | |
1306 | if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN) | |
35f836fe | 1307 | #else |
7bdb43c3 VK |
1308 | StrStrip(ptr); |
1309 | if (*ptr != 0) | |
1310 | { | |
1311 | if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN) | |
35f836fe | 1312 | #endif |
7bdb43c3 | 1313 | break; |
5039dede | 1314 | #if USE_READLINE |
7bdb43c3 | 1315 | add_history(ptr); |
5039dede | 1316 | #endif |
7bdb43c3 | 1317 | } |
5039dede | 1318 | #if USE_READLINE |
7bdb43c3 | 1319 | free(ptr); |
5039dede | 1320 | #endif |
7bdb43c3 VK |
1321 | } |
1322 | else | |
1323 | { | |
1324 | _tprintf(_T("\n")); | |
1325 | } | |
1326 | } | |
5039dede AK |
1327 | |
1328 | #if USE_READLINE | |
7bdb43c3 | 1329 | free(ptr); |
5039dede | 1330 | #endif |
bc9263d1 VK |
1331 | if (!(g_flags & AF_SHUTDOWN)) |
1332 | { | |
1333 | m_nShutdownReason = SHUTDOWN_FROM_CONSOLE; | |
1334 | Shutdown(); | |
1335 | } | |
7bdb43c3 VK |
1336 | } |
1337 | else | |
1338 | { | |
1339 | // standalone with debug console disabled | |
1340 | #ifdef _WIN32 | |
1341 | _tprintf(_T("Server running. Press ESC to shutdown.\n")); | |
1342 | while(1) | |
1343 | { | |
1344 | if (_getch() == 27) | |
1345 | break; | |
1346 | } | |
1347 | _tprintf(_T("Server shutting down...\n")); | |
1348 | Shutdown(); | |
1349 | #else | |
1350 | _tprintf(_T("Server running. Press Ctrl+C to shutdown.\n")); | |
1351 | // Shutdown will be called from signal handler | |
1352 | ConditionWait(m_condShutdown, INFINITE); | |
1353 | #endif | |
1354 | } | |
5039dede AK |
1355 | } |
1356 | else | |
1357 | { | |
1358 | ConditionWait(m_condShutdown, INFINITE); | |
1359 | // On Win32, Shutdown() will be called by service control handler | |
1360 | #ifndef _WIN32 | |
1361 | Shutdown(); | |
1362 | #endif | |
1363 | } | |
1364 | return THREAD_OK; | |
1365 | } | |
1366 | ||
fdbee7f8 VK |
1367 | /** |
1368 | * Initiate server shutdown | |
1369 | */ | |
035a4d73 | 1370 | void InitiateShutdown() |
5039dede AK |
1371 | { |
1372 | #ifdef _WIN32 | |
1373 | Shutdown(); | |
1374 | #else | |
1375 | if (IsStandalone()) | |
1376 | { | |
1377 | Shutdown(); | |
1378 | } | |
1379 | else | |
1380 | { | |
1381 | pthread_kill(m_signalHandlerThread, SIGTERM); | |
1382 | } | |
1383 | #endif | |
1384 | } | |
1385 | ||
fdbee7f8 VK |
1386 | /** |
1387 | *DLL Entry point | |
1388 | */ | |
5039dede AK |
1389 | #ifdef _WIN32 |
1390 | ||
1391 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) | |
1392 | { | |
1393 | if (dwReason == DLL_PROCESS_ATTACH) | |
1394 | DisableThreadLibraryCalls(hInstance); | |
1395 | return TRUE; | |
1396 | } | |
1397 | ||
1398 | #endif |