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