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