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