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