all pollers converted to single thread pool
[public/netxms.git] / src / server / core / main.cpp
CommitLineData
d9177dd1 1/*
5039dede 2** NetXMS - Network Management System
43a6f3ca 3** Copyright (C) 2003-2015 NetXMS Team
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
ea50bc33
VK
46/**
47 * Format string to show value of global flag
48 */
49#define SHOW_FLAG_VALUE(x) _T(" %-38s = %d\n"), _T(#x), (g_flags & x) ? 1 : 0
50
3a82d5ae
VK
51/**
52 * Messages generated by mc.pl (for UNIX version only)
53 */
5039dede
AK
54#ifndef _WIN32
55extern unsigned int g_dwNumMessages;
56extern const TCHAR *g_szMessages[];
57#endif
58
8f99849c
VK
59/**
60 * Shutdown reasons
61 */
030a0779
VK
62#define SHUTDOWN_DEFAULT 0
63#define SHUTDOWN_FROM_CONSOLE 1
64#define SHUTDOWN_BY_SIGNAL 2
5039dede 65
8f99849c
VK
66/**
67 * Externals
68 */
5039dede 69extern Queue g_nodePollerQueue;
d140955e
VK
70extern Queue g_dataCollectionQueue;
71extern Queue g_dciCacheLoaderQueue;
f1784ab6
VK
72extern Queue g_syslogProcessingQueue;
73extern Queue g_syslogWriteQueue;
208d7427 74extern ThreadPool *g_pollerThreadPool;
5039dede 75
36e44abe 76void InitClientListeners();
534e1b83 77void InitMobileDeviceListeners();
36e44abe 78void InitCertificates();
ab185583
VK
79void InitUsers();
80void CleanupUsers();
8fd95c92 81void LoadPerfDataStorageDrivers();
058bf6fc
VK
82
83#if XMPP_SUPPORTED
244c65ef 84void StopXMPPConnector();
058bf6fc 85#endif
5039dede 86
534e1b83
VK
87/**
88 * Thread functions
89 */
90THREAD_RESULT THREAD_CALL HouseKeeper(void *);
91THREAD_RESULT THREAD_CALL Syncer(void *);
92THREAD_RESULT THREAD_CALL NodePoller(void *);
93THREAD_RESULT THREAD_CALL PollManager(void *);
94THREAD_RESULT THREAD_CALL EventProcessor(void *);
95THREAD_RESULT THREAD_CALL WatchdogThread(void *);
96THREAD_RESULT THREAD_CALL ClientListener(void *);
97THREAD_RESULT THREAD_CALL ClientListenerIPv6(void *);
98THREAD_RESULT THREAD_CALL MobileDeviceListener(void *);
99THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *);
100THREAD_RESULT THREAD_CALL ISCListener(void *);
101THREAD_RESULT THREAD_CALL LocalAdminListener(void *);
102THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *);
103THREAD_RESULT THREAD_CALL SyslogDaemon(void *);
104THREAD_RESULT THREAD_CALL BeaconPoller(void *);
105THREAD_RESULT THREAD_CALL JobManagerThread(void *);
106THREAD_RESULT THREAD_CALL UptimeCalculator(void *);
d75003e1 107THREAD_RESULT THREAD_CALL ReportingServerConnector(void *);
058bf6fc
VK
108
109#if XMPP_SUPPORTED
244c65ef 110THREAD_RESULT THREAD_CALL XMPPConnectionManager(void *);
058bf6fc 111#endif
5039dede 112
534e1b83
VK
113/**
114 * Global variables
115 */
5039dede
AK
116TCHAR NXCORE_EXPORTABLE g_szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE;
117TCHAR NXCORE_EXPORTABLE g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
967893bb
VK
118UINT32 g_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
119UINT32 g_dwMaxLogSize = 16384 * 1024;
120UINT32 g_dwLogHistorySize = 4;
4f8998ca 121TCHAR g_szDailyLogFileSuffix[64] = _T("");
5039dede 122TCHAR NXCORE_EXPORTABLE g_szDumpDir[MAX_PATH] = DEFAULT_DUMP_DIR;
29dc8792 123char g_szCodePage[256] = ICONV_DEFAULT_CODEPAGE;
5f6e8d09 124TCHAR NXCORE_EXPORTABLE g_szListenAddress[MAX_PATH] = _T("*");
5039dede 125#ifndef _WIN32
b07c50cc 126TCHAR NXCORE_EXPORTABLE g_szPIDFile[MAX_PATH] = _T("/var/run/netxmsd.pid");
5039dede
AK
127#endif
128DB_HANDLE g_hCoreDB = 0;
967893bb
VK
129UINT32 g_dwDiscoveryPollingInterval;
130UINT32 g_dwStatusPollingInterval;
131UINT32 g_dwConfigurationPollingInterval;
132UINT32 g_dwRoutingTableUpdateInterval;
133UINT32 g_dwTopologyPollingInterval;
134UINT32 g_dwConditionPollingInterval;
805171de 135UINT32 g_instancePollingInterval;
c59466d2
VK
136UINT32 g_icmpPingSize;
137UINT32 g_icmpPingTimeout = 1500; // ICMP ping timeout (milliseconds)
138UINT32 g_auditFlags;
139UINT32 g_slmPollingInterval;
db6a6b45
VK
140TCHAR NXCORE_EXPORTABLE g_netxmsdDataDir[MAX_PATH] = _T("");
141TCHAR NXCORE_EXPORTABLE g_netxmsdLibDir[MAX_PATH] = _T("");
2a964810 142int g_dbSyntax = DB_SYNTAX_UNKNOWN;
967893bb 143UINT32 NXCORE_EXPORTABLE g_processAffinityMask = DEFAULT_AFFINITY_MASK;
e9902466 144UINT64 g_serverId = 0;
5039dede 145RSA *g_pServerKey = NULL;
c59466d2
VK
146time_t g_serverStartTime = 0;
147UINT32 g_lockTimeout = 60000; // Default timeout for acquiring mutex
148UINT32 g_agentCommandTimeout = 4000; // Default timeout for requests to agent
149UINT32 g_thresholdRepeatInterval = 0; // Disabled by default
150int g_requiredPolls = 1;
b8c1ec69 151DB_DRIVER g_dbDriver = NULL;
5d3459af 152ThreadPool *g_mainThreadPool = NULL;
9708eff4 153INT16 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
5039dede 154
f375019e
VK
155/**
156 * Static data
157 */
5039dede
AK
158static CONDITION m_condShutdown = INVALID_CONDITION_HANDLE;
159static THREAD m_thPollManager = INVALID_THREAD_HANDLE;
160static THREAD m_thHouseKeeper = INVALID_THREAD_HANDLE;
161static THREAD m_thSyncer = INVALID_THREAD_HANDLE;
162static THREAD m_thSyslogDaemon = INVALID_THREAD_HANDLE;
058bf6fc 163#if XMPP_SUPPORTED
244c65ef 164static THREAD m_thXMPPConnector = INVALID_THREAD_HANDLE;
058bf6fc 165#endif
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
AK
188{
189 if (g_hCoreDB != NULL)
190 DBDisconnect(g_hCoreDB);
b8c1ec69 191 DBUnloadDriver(g_dbDriver);
5039dede
AK
192}
193
496390c2
VK
194/**
195 * Check data directory for existence
196 */
35f836fe 197static BOOL CheckDataDir()
5039dede 198{
35f836fe 199 TCHAR szBuffer[MAX_PATH];
5039dede 200
db6a6b45 201 if (_tchdir(g_netxmsdDataDir) == -1)
5039dede 202 {
db6a6b45 203 nxlog_write(MSG_INVALID_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", g_netxmsdDataDir);
5039dede
AK
204 return FALSE;
205 }
206
207#ifdef _WIN32
35f836fe 208#define MKDIR(name) _tmkdir(name)
5039dede 209#else
35f836fe 210#define MKDIR(name) _tmkdir(name, 0700)
5039dede
AK
211#endif
212
213 // Create directory for mib files if it doesn't exist
db6a6b45 214 _tcscpy(szBuffer, g_netxmsdDataDir);
35f836fe 215 _tcscat(szBuffer, DDIR_MIBS);
5039dede
AK
216 if (MKDIR(szBuffer) == -1)
217 if (errno != EEXIST)
218 {
219 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
220 return FALSE;
221 }
222
5039dede 223 // Create directory for package files if it doesn't exist
db6a6b45 224 _tcscpy(szBuffer, g_netxmsdDataDir);
35f836fe 225 _tcscat(szBuffer, DDIR_PACKAGES);
5039dede
AK
226 if (MKDIR(szBuffer) == -1)
227 if (errno != EEXIST)
228 {
229 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
230 return FALSE;
231 }
232
4d0c32f3 233 // Create directory for map background images if it doesn't exist
db6a6b45 234 _tcscpy(szBuffer, g_netxmsdDataDir);
35f836fe 235 _tcscat(szBuffer, DDIR_BACKGROUNDS);
4d0c32f3
VK
236 if (MKDIR(szBuffer) == -1)
237 if (errno != EEXIST)
238 {
239 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
240 return FALSE;
241 }
242
e6b9439a 243 // Create directory for image library is if does't exists
db6a6b45 244 _tcscpy(szBuffer, g_netxmsdDataDir);
e6b9439a
AK
245 _tcscat(szBuffer, DDIR_IMAGES);
246 if (MKDIR(szBuffer) == -1)
247 {
248 if (errno != EEXIST)
249 {
250 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
251 return FALSE;
252 }
253 }
254
6f16f12d 255 // Create directory for shared file store if does't exists
db6a6b45 256 _tcscpy(szBuffer, g_netxmsdDataDir);
6f16f12d
VK
257 _tcscat(szBuffer, DDIR_SHARED_FILES);
258 if (MKDIR(szBuffer) == -1)
259 {
260 if (errno != EEXIST)
261 {
262 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
263 return FALSE;
264 }
265 }
266
619e5c9b 267 // Create directory for file store if does't exists
db6a6b45 268 _tcscpy(szBuffer, g_netxmsdDataDir);
619e5c9b
VK
269 _tcscat(szBuffer, DDIR_FILES);
270 if (MKDIR(szBuffer) == -1)
57fef75c
VK
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
5039dede
AK
279#undef MKDIR
280
281 return TRUE;
282}
283
496390c2
VK
284/**
285 * Load global configuration parameters
286 */
5039dede
AK
287static void LoadGlobalConfig()
288{
35f836fe
VK
289 g_dwDiscoveryPollingInterval = ConfigReadInt(_T("DiscoveryPollingInterval"), 900);
290 g_dwStatusPollingInterval = ConfigReadInt(_T("StatusPollingInterval"), 60);
291 g_dwConfigurationPollingInterval = ConfigReadInt(_T("ConfigurationPollingInterval"), 3600);
805171de 292 g_instancePollingInterval = ConfigReadInt(_T("InstancePollingInterval"), 600);
35f836fe 293 g_dwRoutingTableUpdateInterval = ConfigReadInt(_T("RoutingTableUpdateInterval"), 300);
040c45fa 294 g_dwTopologyPollingInterval = ConfigReadInt(_T("TopologyPollingInterval"), 1800);
35f836fe 295 g_dwConditionPollingInterval = ConfigReadInt(_T("ConditionPollingInterval"), 60);
c59466d2 296 g_slmPollingInterval = ConfigReadInt(_T("SlmPollingInterval"), 60);
9708eff4 297 g_defaultAgentCacheMode = (INT16)ConfigReadInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF);
e9902466
VK
298 if ((g_defaultAgentCacheMode != AGENT_CACHE_ON) && (g_defaultAgentCacheMode != AGENT_CACHE_OFF))
299 {
300 DbgPrintf(1, _T("Invalid value %d of DefaultAgentCacheMode: reset to %d (OFF)"), g_defaultAgentCacheMode, AGENT_CACHE_OFF);
301 ConfigWriteInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF, true, true, true);
302 }
35f836fe 303 if (ConfigReadInt(_T("DeleteEmptySubnets"), 1))
c8076b19 304 g_flags |= AF_DELETE_EMPTY_SUBNETS;
35f836fe 305 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
c8076b19
VK
306 g_flags |= AF_ENABLE_SNMP_TRAPD;
307 if (ConfigReadInt(_T("ProcessTrapsFromUnmanagedNodes"), 0))
308 g_flags |= AF_TRAPS_FROM_UNMANAGED_NODES;
35f836fe 309 if (ConfigReadInt(_T("EnableZoning"), 0))
c8076b19 310 g_flags |= AF_ENABLE_ZONING;
549f48b3 311 if (ConfigReadInt(_T("EnableObjectTransactions"), 0))
c8076b19 312 g_flags |= AF_ENABLE_OBJECT_TRANSACTIONS;
35f836fe 313 if (ConfigReadInt(_T("EnableMultipleDBConnections"), 1))
2a8e6a7b
VK
314 {
315 // SQLite has troubles with multiple connections to the same database
316 // from different threads, and it does not speed up database access
317 // anyway, so we will not enable multiple connections for SQLite
66c11d49 318 //if (g_dbSyntax != DB_SYNTAX_SQLITE)
2a8e6a7b 319 {
c8076b19 320 g_flags |= AF_ENABLE_MULTIPLE_DB_CONN;
2a8e6a7b 321 }
66c11d49 322 /*
2a8e6a7b
VK
323 else
324 {
325 DbgPrintf(1, _T("Configuration parameter EnableMultipleDBConnections ignored because database engine is SQLite"));
326 }
66c11d49 327 */
2a8e6a7b 328 }
35f836fe 329 if (ConfigReadInt(_T("RunNetworkDiscovery"), 0))
c8076b19 330 g_flags |= AF_ENABLE_NETWORK_DISCOVERY;
35f836fe 331 if (ConfigReadInt(_T("ActiveNetworkDiscovery"), 0))
c8076b19 332 g_flags |= AF_ACTIVE_NETWORK_DISCOVERY;
e02953a4 333 if (ConfigReadInt(_T("UseSNMPTrapsForDiscovery"), 0))
c8076b19 334 g_flags |= AF_SNMP_TRAP_DISCOVERY;
35f836fe 335 if (ConfigReadInt(_T("ResolveNodeNames"), 1))
c8076b19 336 g_flags |= AF_RESOLVE_NODE_NAMES;
35f836fe 337 if (ConfigReadInt(_T("SyncNodeNamesWithDNS"), 0))
c8076b19 338 g_flags |= AF_SYNC_NODE_NAMES_WITH_DNS;
35f836fe 339 if (ConfigReadInt(_T("CheckTrustedNodes"), 1))
c8076b19 340 g_flags |= AF_CHECK_TRUSTED_NODES;
3bbc7435 341 if (ConfigReadInt(_T("EnableNXSLContainerFunctions"), 1))
c8076b19 342 g_flags |= AF_ENABLE_NXSL_CONTAINER_FUNCS;
f31c22b3 343 if (ConfigReadInt(_T("UseFQDNForNodeNames"), 1))
c8076b19 344 g_flags |= AF_USE_FQDN_FOR_NODE_NAMES;
f31c22b3 345 if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 0))
c8076b19 346 g_flags |= AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE;
4553d424 347 if (ConfigReadInt(_T("ResolveDNSToIPOnStatusPoll"), 0))
385b1f20 348 g_flags |= AF_RESOLVE_IP_FOR_EACH_STATUS_POLL;
fc958888 349
db6a6b45 350 if (g_netxmsdDataDir[0] == 0)
f31c22b3
VK
351 {
352 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
353 if (homeDir != NULL)
354 {
355 TCHAR path[MAX_PATH];
356 _sntprintf(path, MAX_PATH, _T("%s/share/netxms"), homeDir);
db6a6b45 357 ConfigReadStr(_T("DataDirectory"), g_netxmsdDataDir, MAX_PATH, path);
f31c22b3
VK
358 }
359 else
360 {
db6a6b45 361 ConfigReadStr(_T("DataDirectory"), g_netxmsdDataDir, MAX_PATH, DEFAULT_DATA_DIR);
f31c22b3 362 }
db6a6b45 363 DbgPrintf(1, _T("Data directory set to %s from server configuration variable"), g_netxmsdDataDir);
f31c22b3
VK
364 }
365 else
366 {
db6a6b45 367 DbgPrintf(1, _T("Using data directory %s"), g_netxmsdDataDir);
f31c22b3 368 }
d96bd4c7 369
c59466d2
VK
370 g_icmpPingTimeout = ConfigReadInt(_T("IcmpPingTimeout"), 1500);
371 g_icmpPingSize = ConfigReadInt(_T("IcmpPingSize"), 46);
372 g_lockTimeout = ConfigReadInt(_T("LockTimeout"), 60000);
c59466d2
VK
373 g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000);
374 g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
375 g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
296ae03d
VK
376
377 UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 2000);
378 SnmpSetDefaultTimeout(snmpTimeout);
5039dede
AK
379}
380
fdbee7f8
VK
381/**
382 * Initialize cryptografic functions
383 */
73869331 384static BOOL InitCryptografy()
5039dede
AK
385{
386#ifdef _WITH_ENCRYPTION
35f836fe 387 TCHAR szKeyFile[MAX_PATH];
5039dede
AK
388 BOOL bResult = FALSE;
389 int fd, iPolicy;
967893bb 390 UINT32 dwLen;
5039dede
AK
391 BYTE *pBufPos, *pKeyBuffer, hash[SHA1_DIGEST_SIZE];
392
6468147c 393 if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F), DbgPrintf2))
5039dede 394 return FALSE;
ae5880f6 395 DbgPrintf(4, _T("Supported ciphers: %s"), (const TCHAR *)NXCPGetSupportedCiphersAsText());
5039dede 396
958a9397 397 SSL_library_init();
0fd5c0a1 398 SSL_load_error_strings();
958a9397 399
db6a6b45 400 _tcscpy(szKeyFile, g_netxmsdDataDir);
35f836fe
VK
401 _tcscat(szKeyFile, DFILE_KEYS);
402 fd = _topen(szKeyFile, O_RDONLY | O_BINARY);
5039dede
AK
403 g_pServerKey = LoadRSAKeys(szKeyFile);
404 if (g_pServerKey == NULL)
405 {
35f836fe 406 DbgPrintf(1, _T("Generating RSA key pair..."));
5039dede
AK
407 g_pServerKey = RSA_generate_key(NETXMS_RSA_KEYLEN, 17, NULL, 0);
408 if (g_pServerKey != NULL)
409 {
35f836fe 410 fd = _topen(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600);
5039dede
AK
411 if (fd != -1)
412 {
413 dwLen = i2d_RSAPublicKey(g_pServerKey, NULL);
414 dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
415 pKeyBuffer = (BYTE *)malloc(dwLen);
416
417 pBufPos = pKeyBuffer;
418 i2d_RSAPublicKey(g_pServerKey, &pBufPos);
419 i2d_RSAPrivateKey(g_pServerKey, &pBufPos);
967893bb 420 write(fd, &dwLen, sizeof(UINT32));
5039dede
AK
421 write(fd, pKeyBuffer, dwLen);
422
423 CalculateSHA1Hash(pKeyBuffer, dwLen, hash);
424 write(fd, hash, SHA1_DIGEST_SIZE);
425
426 close(fd);
427 free(pKeyBuffer);
428 bResult = TRUE;
429 }
c578be51
AK
430 else
431 {
432 DbgPrintf(0, _T("Failed to open %s for writing"), szKeyFile);
433 }
5039dede 434 }
c578be51
AK
435 else
436 {
437 DbgPrintf(0, _T("Failed to generate RSA key"));
438 }
5039dede
AK
439 }
440 else
441 {
442 bResult = TRUE;
443 }
444
35f836fe 445 iPolicy = ConfigReadInt(_T("DefaultEncryptionPolicy"), 1);
5039dede
AK
446 if ((iPolicy < 0) || (iPolicy > 3))
447 iPolicy = 1;
448 SetAgentDEP(iPolicy);
449
450 return bResult;
451#else
452 return TRUE;
453#endif
454}
455
496390c2
VK
456/**
457 * Check if process with given PID exists and is a NetXMS server process
458 */
967893bb 459static BOOL IsNetxmsdProcess(UINT32 dwPID)
5039dede
AK
460{
461#ifdef _WIN32
462 HANDLE hProcess;
463 TCHAR szExtModule[MAX_PATH], szIntModule[MAX_PATH];
464 BOOL bRet = FALSE;
465
466 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
467 if (hProcess != NULL)
468 {
469 if ((GetModuleBaseName(hProcess, NULL, szExtModule, MAX_PATH) > 0) &&
470 (GetModuleBaseName(GetCurrentProcess(), NULL, szIntModule, MAX_PATH) > 0))
471 {
472 bRet = !_tcsicmp(szExtModule, szIntModule);
473 }
474 else
475 {
476 // Cannot read process name, for safety assume that it's a server process
477 bRet = TRUE;
478 }
479 CloseHandle(hProcess);
480 }
481 return bRet;
482#else
483 return (kill((pid_t)dwPID, 0) != -1);
484#endif
485}
486
496390c2
VK
487/**
488 * Database event handler
489 */
35f836fe 490static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, void *userArg)
5039dede 491{
c8076b19 492 if (!(g_flags & AF_SERVER_INITIALIZED))
5039dede
AK
493 return; // Don't try to do anything if server is not ready yet
494
495 switch(dwEvent)
496 {
497 case DBEVENT_CONNECTION_LOST:
498 PostEvent(EVENT_DB_CONNECTION_LOST, g_dwMgmtNode, NULL);
c8076b19 499 g_flags |= AF_DB_CONNECTION_LOST;
5039dede
AK
500 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, FALSE);
501 break;
502 case DBEVENT_CONNECTION_RESTORED:
503 PostEvent(EVENT_DB_CONNECTION_RESTORED, g_dwMgmtNode, NULL);
c8076b19 504 g_flags &= ~AF_DB_CONNECTION_LOST;
5039dede
AK
505 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, TRUE);
506 break;
4d0c32f3 507 case DBEVENT_QUERY_FAILED:
5049e942 508 PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uu", pszArg1, pszArg2);
4d0c32f3 509 break;
5039dede
AK
510 default:
511 break;
512 }
513}
514
496390c2
VK
515/**
516 * Send console message to session with open console
517 */
f669df41
VK
518static void SendConsoleMessage(ClientSession *session, void *arg)
519{
520 if (session->isConsoleOpen())
521 {
b368969c 522 NXCPMessage msg;
f669df41 523
b368969c
VK
524 msg.setCode(CMD_ADM_MESSAGE);
525 msg.setField(VID_MESSAGE, (TCHAR *)arg);
d3a7cf4c 526 session->postMessage(&msg);
f669df41
VK
527 }
528}
529
d6217efa
VK
530/**
531 * Console writer
532 */
f669df41
VK
533static void LogConsoleWriter(const TCHAR *format, ...)
534{
535 TCHAR buffer[8192];
536 va_list args;
537
538 va_start(args, format);
539 _vsntprintf(buffer, 8192, format, args);
540 buffer[8191] = 0;
541 va_end(args);
542
543 WriteToTerminal(buffer);
544
545 EnumerateClientSessions(SendConsoleMessage, buffer);
546}
547
b6aff59d
VK
548/**
549 * Oracle session init callback
550 */
551static void OracleSessionInitCallback(DB_HANDLE hdb)
552{
553 DBQuery(hdb, _T("ALTER SESSION SET DDL_LOCK_TIMEOUT = 60"));
554}
555
fdbee7f8
VK
556/**
557 * Server initialization
558 */
bc980b27 559BOOL NXCORE_EXPORTABLE Initialize()
5039dede
AK
560{
561 int i, iDBVersion;
35f836fe 562 TCHAR szInfo[256];
5039dede 563
c59466d2
VK
564 g_serverStartTime = time(NULL);
565 srand((unsigned int)g_serverStartTime);
4f8998ca 566
db6a6b45 567 if (g_netxmsdLibDir[0] == 0)
99ba93d1 568 {
a97f02e1
VK
569 GetNetXMSDirectory(nxDirLib, g_netxmsdLibDir);
570 DbgPrintf(1, _T("Lib directory set to %s"), g_netxmsdLibDir);
99ba93d1
VK
571 }
572
c8076b19 573 if (!(g_flags & AF_USE_SYSLOG))
4f8998ca
VK
574 {
575 if (!nxlog_set_rotation_policy((int)g_dwLogRotationMode, (int)g_dwMaxLogSize, (int)g_dwLogHistorySize, g_szDailyLogFileSuffix))
c8076b19 576 if (!(g_flags & AF_DAEMON))
4f8998ca
VK
577 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
578 }
c8076b19 579 if (!nxlog_open((g_flags & AF_USE_SYSLOG) ? NETXMSD_SYSLOG_NAME : g_szLogFile,
4e0e77e6
VK
580 ((g_flags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
581 ((g_flags & AF_BACKGROUND_LOG_WRITER) ? NXLOG_BACKGROUND_WRITER : 0) |
582 ((g_flags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
9d381279 583 _T("LIBNXSRV.DLL"),
5039dede 584#ifdef _WIN32
9d381279 585 0, NULL))
5039dede 586#else
9d381279 587 g_dwNumMessages, g_szMessages))
5039dede 588#endif
9d381279
VK
589 {
590 _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
591 return FALSE;
592 }
f669df41 593 nxlog_set_console_writer(LogConsoleWriter);
5039dede
AK
594
595 // Set code page
596#ifndef _WIN32
597 if (SetDefaultCodepage(g_szCodePage))
598 {
f5797a09 599 DbgPrintf(1, _T("Code page set to %hs"), g_szCodePage);
5039dede
AK
600 }
601 else
602 {
f375019e 603 nxlog_write(MSG_CODEPAGE_ERROR, EVENTLOG_WARNING_TYPE, "m", g_szCodePage);
5039dede
AK
604 }
605#endif
606
73869331
VK
607 // Set process affinity mask
608 if (g_processAffinityMask != DEFAULT_AFFINITY_MASK)
609 {
610#ifdef _WIN32
611 if (SetProcessAffinityMask(GetCurrentProcess(), g_processAffinityMask))
612 DbgPrintf(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask);
613#else
614 nxlog_write(MSG_SET_PROCESS_AFFINITY_NOT_SUPPORTED, EVENTLOG_WARNING_TYPE, NULL);
615#endif
616 }
617
5039dede
AK
618#ifdef _WIN32
619 WSADATA wsaData;
1ddf3f0c
VK
620 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
621 if (wrc != 0)
622 {
623 nxlog_write(MSG_WSASTARTUP_FAILED, EVENTLOG_ERROR_TYPE, "e", wrc);
624 return FALSE;
625 }
5039dede
AK
626#endif
627
628 InitLocalNetInfo();
296ae03d 629 SnmpSetMessageIds(MSG_OID_PARSE_ERROR, MSG_SNMP_UNKNOWN_TYPE, MSG_SNMP_GET_ERROR);
5039dede 630
5096f5a5
VK
631 Timer::globalInit();
632
5039dede 633 // Create queue for delayed SQL queries
76fcb995
VK
634 g_dbWriterQueue = new Queue(256, 64);
635 g_dciDataWriterQueue = new Queue(1024, 1024);
636 g_dciRawDataWriterQueue = new Queue(1024, 1024);
5039dede
AK
637
638 // Initialize database driver and connect to database
9d88cdc9 639 DBSetDebugPrintCallback(DbgPrintf2);
c8076b19 640 if (!DBInit(MSG_OTHER, (g_flags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0))
b8c1ec69 641 return FALSE;
ed950274 642 g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (g_debugLevel >= 9), DBEventHandler, NULL);
b8c1ec69 643 if (g_dbDriver == NULL)
5039dede
AK
644 return FALSE;
645
646 // Connect to database
465b3f2d 647 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
5039dede
AK
648 for(i = 0; ; i++)
649 {
f3c30cf5 650 g_hCoreDB = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText);
5039dede
AK
651 if ((g_hCoreDB != NULL) || (i == 5))
652 break;
653 ThreadSleep(5);
654 }
655 if (g_hCoreDB == NULL)
656 {
465b3f2d 657 nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, "s", errorText);
5039dede
AK
658 return FALSE;
659 }
35f836fe 660 DbgPrintf(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer);
5039dede
AK
661
662 // Check database version
28f5b9a4 663 iDBVersion = DBGetSchemaVersion(g_hCoreDB);
5039dede
AK
664 if (iDBVersion != DB_FORMAT_VERSION)
665 {
666 nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", iDBVersion, DB_FORMAT_VERSION);
667 return FALSE;
668 }
669
b6aff59d
VK
670 // Read database syntax
671 g_dbSyntax = DBGetSyntax(g_hCoreDB);
672 if (g_dbSyntax == DB_SYNTAX_ORACLE)
673 {
674 DBSetSessionInitCallback(OracleSessionInitCallback);
675 }
676
35f836fe
VK
677 int baseSize = ConfigReadInt(_T("ConnectionPoolBaseSize"), 5);
678 int maxSize = ConfigReadInt(_T("ConnectionPoolMaxSize"), 20);
679 int cooldownTime = ConfigReadInt(_T("ConnectionPoolCooldownTime"), 300);
30d9c43c 680 DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, 0, g_hCoreDB);
c8076b19 681 g_flags |= AF_DB_CONNECTION_POOL_READY;
f727d089 682
58f1f627
VK
683 UINT32 lrt = ConfigReadULong(_T("LongRunningQueryThreshold"), 0);
684 if (lrt != 0)
685 DBSetLongRunningThreshold(lrt);
686
5039dede 687 // Read server ID
e9902466 688 MetaDataReadStr(_T("ServerID"), szInfo, 256, _T(""));
5039dede
AK
689 StrStrip(szInfo);
690 if (szInfo[0] != 0)
691 {
e9902466 692 g_serverId = _tcstoull(szInfo, NULL, 16);
5039dede
AK
693 }
694 else
695 {
696 // Generate new ID
e9902466
VK
697 g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF);
698 _sntprintf(szInfo, 256, UINT64X_FMT(_T("016")), g_serverId);
699 MetaDataWriteStr(_T("ServerID"), szInfo);
5039dede 700 }
e9902466 701 DbgPrintf(1, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
5039dede
AK
702
703 // Initialize locks
704retry_db_lock:
c30c0c0f
VK
705 InetAddress addr;
706 if (!InitLocks(&addr, szInfo))
5039dede 707 {
c30c0c0f 708 if (!addr.isValid()) // Some SQL problems
5039dede
AK
709 {
710 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
711 }
712 else // Database already locked by another server instance
713 {
714 // Check for lock from crashed/terminated local process
c30c0c0f 715 if (GetLocalIpAddr().equals(addr))
5039dede 716 {
967893bb 717 UINT32 dwPID;
5039dede 718
35f836fe 719 dwPID = ConfigReadULong(_T("DBLockPID"), 0);
5039dede
AK
720 if (!IsNetxmsdProcess(dwPID) || (dwPID == GetCurrentProcessId()))
721 {
722 UnlockDB();
723 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
724 goto retry_db_lock;
725 }
726 }
c30c0c0f 727 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "As", &addr, szInfo);
5039dede
AK
728 }
729 return FALSE;
730 }
c8076b19 731 g_flags |= AF_DB_LOCKED;
5039dede
AK
732
733 // Load global configuration parameters
734 LoadGlobalConfig();
958a9397 735 CASReadSettings();
35f836fe 736 DbgPrintf(1, _T("Global configuration loaded"));
5039dede
AK
737
738 // Check data directory
739 if (!CheckDataDir())
740 return FALSE;
741
742 // Initialize cryptografy
743 if (!InitCryptografy())
744 {
745 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
746 return FALSE;
747 }
748
749 // Initialize certificate store and CA
750 InitCertificates();
751
5039dede
AK
752 // Create synchronization stuff
753 m_condShutdown = ConditionCreate(TRUE);
754
5d3459af
VK
755 // Create thread pools
756 DbgPrintf(2, _T("Creating thread pools"));
757 ThreadPoolSetDebugCallback(DbgPrintf2);
758 g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN"));
759
5039dede
AK
760 // Setup unique identifiers table
761 if (!InitIdTable())
762 return FALSE;
35f836fe 763 DbgPrintf(2, _T("ID table created"));
5039dede 764
24dc5346
VK
765 // Update status for unfinished jobs in job history
766 DBQuery(g_hCoreDB, _T("UPDATE job_history SET status=4,failure_message='Aborted due to server shutdown or crash' WHERE status NOT IN (3,4,5)"));
767
5039dede
AK
768 // Load and compile scripts
769 LoadScripts();
770
f7e4c50e
VK
771 // Initialize watchdog
772 WatchdogInit();
773
53d2de79 774 // Load modules
890478d8
VK
775 if (!LoadNetXMSModules())
776 return FALSE; // Mandatory module not loaded
53d2de79 777
5039dede
AK
778 // Initialize mailer and SMS sender
779 InitMailer();
780 InitSMSSender();
781
782 // Load users from database
ab185583 783 InitUsers();
5039dede
AK
784 if (!LoadUsers())
785 {
786 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
787 return FALSE;
788 }
35f836fe 789 DbgPrintf(2, _T("User accounts loaded"));
5039dede
AK
790
791 // Initialize audit
792 InitAuditLog();
793
da84c57a
VK
794 // Initialize event handling subsystem
795 if (!InitEventSubsystem())
796 return FALSE;
797
798 // Initialize alarms
799 if (!InitAlarmManager())
800 return FALSE;
801
5039dede 802 // Initialize objects infrastructure and load objects from database
9796ce45 803 LoadNetworkDeviceDrivers();
5039dede
AK
804 ObjectsInit();
805 if (!LoadObjects())
806 return FALSE;
35f836fe 807 DbgPrintf(1, _T("Objects loaded and initialized"));
d9177dd1 808
5039dede
AK
809 // Initialize situations
810 if (!SituationsInit())
811 return FALSE;
35f836fe 812 DbgPrintf(1, _T("Situations loaded and initialized"));
5039dede
AK
813
814 // Initialize and load event actions
815 if (!InitActions())
816 {
817 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
818 return FALSE;
819 }
820
6fad8870
VK
821 // Initialize helpdesk link
822 SetHDLinkEntryPoints(ResolveAlarmByHDRef, TerminateAlarmByHDRef);
823 LoadHelpDeskLink();
824
5039dede 825 // Initialize data collection subsystem
8fd95c92 826 LoadPerfDataStorageDrivers();
5039dede
AK
827 if (!InitDataCollector())
828 return FALSE;
829
e05b1945 830 InitLogAccess();
d77baddd 831 FileUploadJob::init();
fdbee7f8 832 InitMappingTables();
e05b1945 833
5039dede
AK
834 // Check if management node object presented in database
835 CheckForMgmtNode();
836 if (g_dwMgmtNode == 0)
837 {
838 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
839 return FALSE;
840 }
841
842 // Start threads
843 ThreadCreate(WatchdogThread, 0, NULL);
844 ThreadCreate(NodePoller, 0, NULL);
3929b1ca 845 ThreadCreate(JobManagerThread, 0, NULL);
5039dede
AK
846 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
847 m_thHouseKeeper = ThreadCreateEx(HouseKeeper, 0, NULL);
848 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
849
850 // Start event processor
851 ThreadCreate(EventProcessor, 0, NULL);
852
853 // Start SNMP trapper
854 InitTraps();
35f836fe 855 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
5039dede
AK
856 ThreadCreate(SNMPTrapReceiver, 0, NULL);
857
858 // Start built-in syslog daemon
35f836fe 859 if (ConfigReadInt(_T("EnableSyslogDaemon"), 0))
5039dede
AK
860 m_thSyslogDaemon = ThreadCreateEx(SyslogDaemon, 0, NULL);
861
35f836fe 862 // Start database _T("lazy") write thread
5039dede
AK
863 StartDBWriter();
864
865 // Start local administartive interface listener if required
35f836fe 866 if (ConfigReadInt(_T("EnableAdminInterface"), 1))
5039dede
AK
867 ThreadCreate(LocalAdminListener, 0, NULL);
868
5039dede
AK
869 // Start beacon host poller
870 ThreadCreate(BeaconPoller, 0, NULL);
871
872 // Start inter-server communication listener
35f836fe 873 if (ConfigReadInt(_T("EnableISCListener"), 0))
5039dede
AK
874 ThreadCreate(ISCListener, 0, NULL);
875
d75003e1
AK
876 // Start reporting server connector
877 if (ConfigReadInt(_T("EnableReportingServer"), 0))
878 ThreadCreate(ReportingServerConnector, 0, NULL);
879
d9177dd1 880 //Start ldap synchronization
881 if (ConfigReadInt(_T("LdapSyncInterval"), 0))
882 ThreadCreate(SyncLDAPUsers, 0, NULL);
883
5039dede 884 // Allow clients to connect
36e44abe 885 InitClientListeners();
5039dede 886 ThreadCreate(ClientListener, 0, NULL);
36e44abe
VK
887#ifdef WITH_IPV6
888 ThreadCreate(ClientListenerIPv6, 0, NULL);
889#endif
5039dede 890
534e1b83
VK
891 // Allow mobile devices to connect
892 InitMobileDeviceListeners();
893 ThreadCreate(MobileDeviceListener, 0, NULL);
894#ifdef WITH_IPV6
895 ThreadCreate(MobileDeviceListenerIPv6, 0, NULL);
896#endif
897
86457857
AK
898 // Start uptime calculator for SLM
899 ThreadCreate(UptimeCalculator, 0, NULL);
900
db6a6b45 901 DbgPrintf(2, _T("LIBDIR: %s"), g_netxmsdLibDir);
712dd47d 902
1b42a673 903 // Call startup functions for the modules
a0efa7b5 904 CALL_ALL_MODULES(pfServerStarted, ());
53d2de79 905
058bf6fc 906#if XMPP_SUPPORTED
244c65ef
VK
907 if (ConfigReadInt(_T("EnableXMPPConnector"), 1))
908 {
909 m_thXMPPConnector = ThreadCreateEx(XMPPConnectionManager, 0, NULL);
910 }
058bf6fc 911#endif
244c65ef 912
c8076b19 913 g_flags |= AF_SERVER_INITIALIZED;
35f836fe 914 DbgPrintf(1, _T("Server initialization completed"));
5039dede
AK
915 return TRUE;
916}
917
371d9c60
VK
918/**
919 * Server shutdown
920 */
035a4d73 921void NXCORE_EXPORTABLE Shutdown()
5039dede 922{
5039dede
AK
923 // Notify clients
924 NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0);
925
926 nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
c8076b19 927 g_flags |= AF_SHUTDOWN; // Set shutdown flag
5039dede
AK
928 ConditionSet(m_condShutdown);
929
d140955e 930 // Stop DCI cache loading thread
19dbc8ef 931 g_dciCacheLoaderQueue.setShutdownMode();
d140955e 932
058bf6fc 933#if XMPP_SUPPORTED
244c65ef 934 StopXMPPConnector();
058bf6fc 935#endif
244c65ef 936
5039dede
AK
937#ifndef _WIN32
938 if (IsStandalone() && (m_nShutdownReason != SHUTDOWN_BY_SIGNAL))
939 {
940 pthread_kill(m_signalHandlerThread, SIGUSR1); // Terminate signal handler
941 }
942#endif
943
4f50e45c 944 // Stop event processor
19dbc8ef
VK
945 g_pEventQueue->clear();
946 g_pEventQueue->put(INVALID_POINTER_VALUE);
5039dede
AK
947
948 ShutdownMailer();
949 ShutdownSMSSender();
950
951 ThreadSleep(1); // Give other threads a chance to terminate in a safe way
35f836fe 952 DbgPrintf(2, _T("All threads was notified, continue with shutdown"));
5039dede
AK
953
954 // Wait for critical threads
955 ThreadJoin(m_thHouseKeeper);
956 ThreadJoin(m_thPollManager);
957 ThreadJoin(m_thSyncer);
958 ThreadJoin(m_thSyslogDaemon);
058bf6fc 959#if XMPP_SUPPORTED
244c65ef 960 ThreadJoin(m_thXMPPConnector);
058bf6fc 961#endif
5039dede 962
a0efa7b5
VK
963 // Call shutdown functions for the modules
964 // CALL_ALL_MODULES cannot be used here because it checks for shutdown flag
965 for(UINT32 i = 0; i < g_dwNumModules; i++)
966 {
967 if (g_pModuleList[i].pfShutdown != NULL)
968 g_pModuleList[i].pfShutdown();
969 }
970
5039dede 971 SaveObjects(g_hCoreDB);
35f836fe 972 DbgPrintf(2, _T("All objects saved to database"));
5039dede 973 SaveUsers(g_hCoreDB);
35f836fe 974 DbgPrintf(2, _T("All users saved to database"));
5039dede 975 StopDBWriter();
35f836fe 976 DbgPrintf(1, _T("Database writer stopped"));
5039dede 977
ab185583
VK
978 CleanupUsers();
979
5039dede
AK
980 // Remove database lock
981 UnlockDB();
982
7a7dfb3e
VK
983 DBConnectionPoolShutdown();
984
5039dede
AK
985 // Disconnect from database and unload driver
986 if (g_hCoreDB != NULL)
987 DBDisconnect(g_hCoreDB);
c20b2798 988
b8c1ec69 989 DBUnloadDriver(g_dbDriver);
35f836fe 990 DbgPrintf(1, _T("Database driver unloaded"));
5039dede
AK
991
992 CleanupActions();
993 ShutdownEventSubsystem();
da84c57a 994 ShutdownAlarmManager();
35f836fe 995 DbgPrintf(1, _T("Event processing stopped"));
5039dede 996
5d3459af 997 ThreadPoolDestroy(g_mainThreadPool);
d87ddcc2 998 MsgWaitQueue::shutdown();
5d3459af 999
5039dede
AK
1000 delete g_pScriptLibrary;
1001
1002 nxlog_close();
1003
1004 // Remove PID file
1005#ifndef _WIN32
dda7c270 1006 _tremove(g_szPIDFile);
5039dede
AK
1007#endif
1008
1009 // Terminate process
1010#ifdef _WIN32
c8076b19 1011 if (!(g_flags & AF_DAEMON))
5039dede
AK
1012 ExitProcess(0);
1013#else
1014 exit(0);
1015#endif
1016}
1017
371d9c60
VK
1018/**
1019 * Fast server shutdown - normally called only by Windows service on system shutdown
1020 */
f669df41 1021void NXCORE_EXPORTABLE FastShutdown()
5039dede 1022{
c8076b19 1023 g_flags |= AF_SHUTDOWN; // Set shutdown flag
5039dede
AK
1024 ConditionSet(m_condShutdown);
1025
1026 SaveObjects(g_hCoreDB);
35f836fe 1027 DbgPrintf(2, _T("All objects saved to database"));
5039dede 1028 SaveUsers(g_hCoreDB);
35f836fe 1029 DbgPrintf(2, _T("All users saved to database"));
5039dede
AK
1030
1031 // Remove database lock first, because we have a chance to loose DB connection
1032 UnlockDB();
1033
1034 // Stop database writers
1035 StopDBWriter();
35f836fe 1036 DbgPrintf(1, _T("Database writer stopped"));
5039dede
AK
1037
1038 nxlog_close();
1039}
1040
fdbee7f8
VK
1041/**
1042 * Compare given string to command template with abbreviation possibility
1043 */
ca0e18d2 1044static bool IsCommand(const TCHAR *cmdTemplate, TCHAR *pszString, int iMinChars)
5039dede
AK
1045{
1046 int i;
1047
1048 // Convert given string to uppercase
35f836fe 1049 _tcsupr(pszString);
5039dede
AK
1050
1051 for(i = 0; pszString[i] != 0; i++)
ca0e18d2 1052 if (pszString[i] != cmdTemplate[i])
fdbee7f8 1053 return false;
5039dede 1054 if (i < iMinChars)
fdbee7f8
VK
1055 return false;
1056 return true;
5039dede
AK
1057}
1058
fdbee7f8 1059/**
c75e9ee4 1060 * Dump index callback (by IP address)
fdbee7f8 1061 */
c30c0c0f 1062static void DumpIndexCallbackByInetAddr(const InetAddress& addr, NetObj *object, void *data)
5039dede 1063{
c75e9ee4 1064 TCHAR buffer[64];
c30c0c0f 1065 ConsolePrintf((CONSOLE_CTX)data, _T("%-40s %p %s [%d]\n"), addr.toString(buffer), object, object->getName(), (int)object->getId());
c75e9ee4 1066}
5039dede 1067
c75e9ee4
VK
1068/**
1069 * Dump index (by IP address)
1070 */
1071static void DumpIndex(CONSOLE_CTX pCtx, InetAddressIndex *index)
d5e19c61 1072{
c75e9ee4 1073 index->forEach(DumpIndexCallbackByInetAddr, pCtx);
d5e19c61 1074}
5039dede 1075
c75e9ee4
VK
1076/**
1077 * Dump index callback (by ID)
1078 */
1079static void DumpIndexCallbackById(NetObj *object, void *data)
1080{
1081 ConsolePrintf((CONSOLE_CTX)data, _T("%08X %p %s\n"), object->getId(), object, object->getName());
1082}
1083
1084/**
1085 * Dump index (by ID)
1086 */
1087static void DumpIndex(CONSOLE_CTX pCtx, ObjectIndex *index)
d5e19c61 1088{
c75e9ee4 1089 index->forEach(DumpIndexCallbackById, pCtx);
5039dede
AK
1090}
1091
e323047c
VK
1092/**
1093 * Process command entered from command line in standalone mode
1094 * Return TRUE if command was _T("down")
1095 */
35f836fe 1096int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
5039dede 1097{
35f836fe 1098 const TCHAR *pArg;
48c0079d 1099 TCHAR szBuffer[256], *eptr;
5039dede
AK
1100 int nExitCode = CMD_EXIT_CONTINUE;
1101
1102 // Get command
1103 pArg = ExtractWord(pszCmdLine, szBuffer);
1104
35f836fe 1105 if (IsCommand(_T("DEBUG"), szBuffer, 2))
5039dede
AK
1106 {
1107 // Get argument
1108 pArg = ExtractWord(pArg, szBuffer);
48c0079d
VK
1109 int level = (int)_tcstol(szBuffer, &eptr, 0);
1110 if ((*eptr == 0) && (level >= 0) && (level <= 9))
5039dede 1111 {
967893bb 1112 g_debugLevel = (UINT32)level;
48c0079d 1113 ConsolePrintf(pCtx, (level == 0) ? _T("Debug mode turned off\n") : _T("Debug level set to %d\n"), level);
5039dede 1114 }
35f836fe 1115 else if (IsCommand(_T("OFF"), szBuffer, 2))
5039dede 1116 {
ed950274 1117 g_debugLevel = 0;
532990d2 1118 ConsoleWrite(pCtx, _T("Debug mode turned off\n"));
5039dede
AK
1119 }
1120 else
1121 {
1122 if (szBuffer[0] == 0)
532990d2 1123 ConsoleWrite(pCtx, _T("ERROR: Missing argument\n\n"));
5039dede 1124 else
532990d2 1125 ConsoleWrite(pCtx, _T("ERROR: Invalid debug level\n\n"));
5039dede
AK
1126 }
1127 }
35f836fe 1128 else if (IsCommand(_T("DOWN"), szBuffer, 4))
5039dede 1129 {
532990d2 1130 ConsoleWrite(pCtx, _T("Proceeding with server shutdown...\n"));
5039dede
AK
1131 nExitCode = CMD_EXIT_SHUTDOWN;
1132 }
35f836fe 1133 else if (IsCommand(_T("DUMP"), szBuffer, 4))
5039dede
AK
1134 {
1135 DumpProcess(pCtx);
1136 }
206e268e
VK
1137 else if (IsCommand(_T("GET"), szBuffer, 3))
1138 {
1139 pArg = ExtractWord(pArg, szBuffer);
1140 if (szBuffer[0] != 0)
1141 {
1142 TCHAR value[256];
1143 ConfigReadStr(szBuffer, value, 256, _T(""));
1144 ConsolePrintf(pCtx, _T("%s = %s\n"), szBuffer, value);
1145 }
1146 else
1147 {
532990d2 1148 ConsoleWrite(pCtx, _T("Variable name missing\n"));
206e268e
VK
1149 }
1150 }
35f836fe 1151 else if (IsCommand(_T("RAISE"), szBuffer, 5))
5039dede
AK
1152 {
1153 // Get argument
1154 pArg = ExtractWord(pArg, szBuffer);
1155
35f836fe 1156 if (IsCommand(_T("ACCESS"), szBuffer, 6))
5039dede 1157 {
532990d2 1158 ConsoleWrite(pCtx, _T("Raising exception...\n"));
5039dede
AK
1159 char *p = NULL;
1160 *p = 0;
1161 }
35f836fe 1162 else if (IsCommand(_T("BREAKPOINT"), szBuffer, 5))
5039dede
AK
1163 {
1164#ifdef _WIN32
532990d2 1165 ConsoleWrite(pCtx, _T("Raising exception...\n"));
5039dede
AK
1166 RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
1167#else
532990d2 1168 ConsoleWrite(pCtx, _T("ERROR: Not supported on current platform\n"));
5039dede
AK
1169#endif
1170 }
1171 else
1172 {
532990d2 1173 ConsoleWrite(pCtx, _T("Invalid exception name; possible names are:\nACCESS BREAKPOINT\n"));
5039dede
AK
1174 }
1175 }
35f836fe 1176 else if (IsCommand(_T("EXIT"), szBuffer, 4))
5039dede 1177 {
f669df41 1178 if ((pCtx->hSocket != -1) || (pCtx->session != NULL))
5039dede 1179 {
532990d2 1180 ConsoleWrite(pCtx, _T("Closing session...\n"));
5039dede
AK
1181 nExitCode = CMD_EXIT_CLOSE_SESSION;
1182 }
1183 else
1184 {
532990d2 1185 ConsoleWrite(pCtx, _T("Cannot exit from local server console\n"));
5039dede
AK
1186 }
1187 }
5d9a9c84
VK
1188 else if (IsCommand(_T("KILL"), szBuffer, 4))
1189 {
1190 pArg = ExtractWord(pArg, szBuffer);
1191 if (szBuffer[0] != 0)
1192 {
1193 int id = _tcstol(szBuffer, &eptr, 10);
1194 if (*eptr == 0)
1195 {
1196 if (KillClientSession(id))
1197 {
532990d2 1198 ConsoleWrite(pCtx, _T("Session killed\n"));
5d9a9c84
VK
1199 }
1200 else
1201 {
532990d2 1202 ConsoleWrite(pCtx, _T("Invalid session ID\n"));
5d9a9c84
VK
1203 }
1204 }
1205 else
1206 {
532990d2 1207 ConsoleWrite(pCtx, _T("Invalid session ID\n"));
5d9a9c84
VK
1208 }
1209 }
1210 else
1211 {
532990d2 1212 ConsoleWrite(pCtx, _T("Session ID missing\n"));
5d9a9c84 1213 }
84d92f02
VK
1214 }
1215 else if (IsCommand(_T("PING"), szBuffer, 4))
1216 {
1217 pArg = ExtractWord(pArg, szBuffer);
1218 if (szBuffer[0] != 0)
1219 {
1220 InetAddress addr = InetAddress::parse(szBuffer);
1221 if (addr.isValid())
1222 {
1223 UINT32 rtt;
1224 UINT32 rc = IcmpPing(addr, 1, 2000, &rtt, 128);
1225 switch(rc)
1226 {
1227 case ICMP_SUCCESS:
1228 ConsolePrintf(pCtx, _T("Success, RTT = %d ms\n"), (int)rtt);
1229 break;
1230 case ICMP_UNREACHEABLE:
1231 ConsolePrintf(pCtx, _T("Destination unreachable\n"));
1232 break;
1233 case ICMP_TIMEOUT:
1234 ConsolePrintf(pCtx, _T("Request timeout\n"));
1235 break;
1236 case ICMP_RAW_SOCK_FAILED:
1237 ConsolePrintf(pCtx, _T("Cannot create raw socket\n"));
1238 break;
1239 case ICMP_API_ERROR:
1240 ConsolePrintf(pCtx, _T("API error\n"));
1241 break;
1242 default:
1243 ConsolePrintf(pCtx, _T("ERROR %d\n"), (int)rc);
1244 break;
1245 }
1246 }
1247 else
1248 {
532990d2 1249 ConsoleWrite(pCtx, _T("Invalid IP address\n"));
84d92f02
VK
1250 }
1251 }
1252 else
1253 {
532990d2 1254 ConsoleWrite(pCtx, _T("Usage: PING <address>\n"));
84d92f02 1255 }
5d9a9c84 1256 }
f34e7a6e
VK
1257 else if (IsCommand(_T("POLL"), szBuffer, 2))
1258 {
1259 pArg = ExtractWord(pArg, szBuffer);
1260 if (szBuffer[0] != 0)
1261 {
1262 int pollType;
1263 if (IsCommand(_T("CONFIGURATION"), szBuffer, 1))
1264 {
1265 pollType = 1;
1266 }
1267 else if (IsCommand(_T("STATUS"), szBuffer, 1))
1268 {
1269 pollType = 2;
1270 }
1271 else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
1272 {
1273 pollType = 3;
1274 }
1275 else
1276 {
1277 pollType = 0;
1278 }
1279
1280 if (pollType > 0)
1281 {
1282 pArg = ExtractWord(pArg, szBuffer);
1283 UINT32 id = _tcstoul(szBuffer, NULL, 0);
1284 if (id != 0)
1285 {
1286 Node *node = (Node *)FindObjectById(id, OBJECT_NODE);
1287 if (node != NULL)
1288 {
1289 switch(pollType)
1290 {
1291 case 1:
208d7427
VK
1292 node->lockForConfigurationPoll();
1293 ThreadPoolExecute(g_pollerThreadPool, node, &Node::configurationPoll, RegisterPoller(POLLER_TYPE_CONFIGURATION, node));
f34e7a6e
VK
1294 break;
1295 case 2:
208d7427
VK
1296 node->lockForStatusPoll();
1297 ThreadPoolExecute(g_pollerThreadPool, node, &Node::statusPoll, RegisterPoller(POLLER_TYPE_STATUS, node));
f34e7a6e
VK
1298 break;
1299 case 3:
208d7427
VK
1300 node->lockForTopologyPoll();
1301 ThreadPoolExecute(g_pollerThreadPool, node, &Node::topologyPoll, RegisterPoller(POLLER_TYPE_TOPOLOGY, node));
f34e7a6e
VK
1302 break;
1303 }
1304 }
1305 else
1306 {
1307 ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), id);
1308 }
1309 }
1310 else
1311 {
532990d2 1312 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
f34e7a6e
VK
1313 }
1314 }
1315 else
1316 {
532990d2 1317 ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|STATUS|TOPOLOGY] <node>\n"));
f34e7a6e
VK
1318 }
1319 }
1320 else
1321 {
532990d2 1322 ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|STATUS|TOPOLOGY] <node>\n"));
f34e7a6e
VK
1323 }
1324 }
206e268e
VK
1325 else if (IsCommand(_T("SET"), szBuffer, 3))
1326 {
1327 pArg = ExtractWord(pArg, szBuffer);
1328 if (szBuffer[0] != 0)
1329 {
1330 TCHAR value[256];
1331 pArg = ExtractWord(pArg, value);
1332 if (ConfigWriteStr(szBuffer, value, TRUE, TRUE, TRUE))
1333 {
1334 ConsolePrintf(pCtx, _T("Configuration variable %s updated\n"), szBuffer);
1335 }
1336 else
1337 {
1338 ConsolePrintf(pCtx, _T("ERROR: cannot update configuration variable %s\n"), szBuffer);
1339 }
1340 }
1341 else
1342 {
1343 ConsolePrintf(pCtx, _T("Variable name missing\n"));
1344 }
1345 }
35f836fe 1346 else if (IsCommand(_T("SHOW"), szBuffer, 2))
5039dede
AK
1347 {
1348 // Get argument
1349 pArg = ExtractWord(pArg, szBuffer);
1350
50d0de67
VK
1351 if (IsCommand(_T("COMPONENTS"), szBuffer, 1))
1352 {
1353 // Get argument
1354 pArg = ExtractWord(pArg, szBuffer);
967893bb 1355 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
50d0de67
VK
1356 if (dwNode != 0)
1357 {
1358 NetObj *pObject = FindObjectById(dwNode);
1359 if (pObject != NULL)
1360 {
c42b4551 1361 if (pObject->getObjectClass() == OBJECT_NODE)
50d0de67 1362 {
8836184f
VK
1363 ComponentTree *components = ((Node *)pObject)->getComponents();
1364 if (components != NULL)
50d0de67 1365 {
8836184f
VK
1366 components->print(pCtx);
1367 components->decRefCount();
50d0de67
VK
1368 }
1369 else
1370 {
532990d2 1371 ConsoleWrite(pCtx, _T("ERROR: Node does not have physical component information\n\n"));
50d0de67
VK
1372 }
1373 }
1374 else
1375 {
532990d2 1376 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
50d0de67
VK
1377 }
1378 }
1379 else
1380 {
1381 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1382 }
1383 }
1384 else
1385 {
532990d2 1386 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
50d0de67
VK
1387 }
1388 }
9c133761
VK
1389 else if (IsCommand(_T("DBCP"), szBuffer, 4))
1390 {
1391 ObjectArray<PoolConnectionInfo> *list = DBConnectionPoolGetConnectionList();
1392 for(int i = 0; i < list->size(); i++)
1393 {
1394 PoolConnectionInfo *c = list->get(i);
1395 TCHAR accessTime[64];
1396 struct tm *ltm = localtime(&c->lastAccessTime);
1397 _tcsftime(accessTime, 64, _T("%d.%b.%Y %H:%M:%S"), ltm);
1398 ConsolePrintf(pCtx, _T("%p %s %hs:%d\n"), c->handle, accessTime, c->srcFile, c->srcLine);
1399 }
1400 ConsolePrintf(pCtx, _T("%d database connections in use\n\n"), list->size());
1401 delete list;
1402 }
4321449e
VK
1403 else if (IsCommand(_T("FDB"), szBuffer, 3))
1404 {
1405 // Get argument
1406 pArg = ExtractWord(pArg, szBuffer);
1407 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
1408 if (dwNode != 0)
1409 {
1410 NetObj *pObject = FindObjectById(dwNode);
1411 if (pObject != NULL)
1412 {
c42b4551 1413 if (pObject->getObjectClass() == OBJECT_NODE)
4321449e
VK
1414 {
1415 ForwardingDatabase *fdb = ((Node *)pObject)->getSwitchForwardingDatabase();
1416 if (fdb != NULL)
1417 {
1418 fdb->print(pCtx, (Node *)pObject);
1419 fdb->decRefCount();
1420 }
1421 else
1422 {
532990d2 1423 ConsoleWrite(pCtx, _T("ERROR: Node does not have forwarding database information\n\n"));
4321449e
VK
1424 }
1425 }
1426 else
1427 {
532990d2 1428 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
4321449e
VK
1429 }
1430 }
1431 else
1432 {
1433 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1434 }
1435 }
1436 else
1437 {
532990d2 1438 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
4321449e
VK
1439 }
1440 }
50d0de67 1441 else if (IsCommand(_T("FLAGS"), szBuffer, 1))
5039dede 1442 {
c8076b19 1443 ConsolePrintf(pCtx, _T("Flags: 0x") UINT64X_FMT(_T("016")) _T("\n"), g_flags);
5039dede
AK
1444 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DAEMON));
1445 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSLOG));
1446 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NETWORK_DISCOVERY));
1447 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ACTIVE_NETWORK_DISCOVERY));
1448 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_SQL_ERRORS));
1449 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DELETE_EMPTY_SUBNETS));
1450 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_SNMP_TRAPD));
1451 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_ZONING));
5039dede 1452 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYNC_NODE_NAMES_WITH_DNS));
cbc777ee 1453 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CHECK_TRUSTED_NODES));
549f48b3
VK
1454 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NXSL_CONTAINER_FUNCS));
1455 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_FQDN_FOR_NODE_NAMES));
1456 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE));
1457 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DEBUG_CONSOLE_DISABLED));
1458 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_OBJECT_TRANSACTIONS));
cbc777ee
VK
1459 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_WRITE_FULL_DUMP));
1460 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_NODE_NAMES));
5039dede 1461 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CATCH_EXCEPTIONS));
d41268ba 1462 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_HELPDESK_LINK_ACTIVE));
5039dede 1463 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_LOCKED));
cbc777ee 1464 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_MULTIPLE_DB_CONN));
5039dede 1465 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_CONNECTION_LOST));
cbc777ee 1466 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_NO_NETWORK_CONNECTIVITY));
5039dede 1467 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_EVENT_STORM_DETECTED));
e02953a4 1468 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SNMP_TRAP_DISCOVERY));
c8076b19 1469 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAPS_FROM_UNMANAGED_NODES));
ea50bc33
VK
1470 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_IP_FOR_EACH_STATUS_POLL));
1471 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_PERFDATA_STORAGE_DRIVER_LOADED));
4e0e77e6 1472 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_BACKGROUND_LOG_WRITER));
5039dede
AK
1473 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SERVER_INITIALIZED));
1474 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SHUTDOWN));
35f836fe 1475 ConsolePrintf(pCtx, _T("\n"));
5039dede 1476 }
5962498b
VK
1477 else if (IsCommand(_T("HEAP"), szBuffer, 1))
1478 {
1479 TCHAR *text = GetHeapInfo();
1480 if (text != NULL)
1481 {
532990d2
VK
1482 ConsoleWrite(pCtx, text);
1483 ConsoleWrite(pCtx, _T("\n"));
5962498b
VK
1484 free(text);
1485 }
1486 else
1487 {
532990d2 1488 ConsoleWrite(pCtx, _T("Error reading heap information\n"));
5962498b
VK
1489 }
1490 }
35f836fe 1491 else if (IsCommand(_T("INDEX"), szBuffer, 1))
5039dede
AK
1492 {
1493 // Get argument
1494 pArg = ExtractWord(pArg, szBuffer);
1495
35f836fe 1496 if (IsCommand(_T("CONDITION"), szBuffer, 1))
5039dede 1497 {
c75e9ee4 1498 DumpIndex(pCtx, &g_idxConditionById);
5039dede 1499 }
35f836fe 1500 else if (IsCommand(_T("ID"), szBuffer, 2))
5039dede 1501 {
c75e9ee4 1502 DumpIndex(pCtx, &g_idxObjectById);
5039dede 1503 }
35f836fe 1504 else if (IsCommand(_T("INTERFACE"), szBuffer, 2))
5039dede 1505 {
c75e9ee4 1506 DumpIndex(pCtx, &g_idxInterfaceByAddr);
6aba3998 1507 }
16d6f798
VK
1508 else if (IsCommand(_T("NODEADDR"), szBuffer, 5))
1509 {
c75e9ee4 1510 DumpIndex(pCtx, &g_idxNodeByAddr);
16d6f798
VK
1511 }
1512 else if (IsCommand(_T("NODEID"), szBuffer, 5))
6aba3998 1513 {
c75e9ee4 1514 DumpIndex(pCtx, &g_idxNodeById);
5039dede 1515 }
35f836fe 1516 else if (IsCommand(_T("SUBNET"), szBuffer, 1))
5039dede 1517 {
c75e9ee4 1518 DumpIndex(pCtx, &g_idxSubnetByAddr);
5039dede 1519 }
16d6f798
VK
1520 else if (IsCommand(_T("ZONE"), szBuffer, 1))
1521 {
c75e9ee4 1522 DumpIndex(pCtx, &g_idxZoneByGUID);
16d6f798 1523 }
5039dede
AK
1524 else
1525 {
1526 if (szBuffer[0] == 0)
532990d2
VK
1527 ConsoleWrite(pCtx, _T("ERROR: Missing index name\n")
1528 _T("Valid names are: CONDITION, ID, INTERFACE, NODEADDR, NODEID, SUBNET, ZONE\n\n"));
5039dede 1529 else
532990d2 1530 ConsoleWrite(pCtx, _T("ERROR: Invalid index name\n\n"));
5039dede
AK
1531 }
1532 }
fee245d1
VK
1533 else if (IsCommand(_T("MODULES"), szBuffer, 3))
1534 {
532990d2 1535 ConsoleWrite(pCtx, _T("Loaded server modules:\n"));
fee245d1
VK
1536 for(UINT32 i = 0; i < g_dwNumModules; i++)
1537 {
1538 ConsolePrintf(pCtx, _T(" %s\n"), g_pModuleList[i].szName);
1539 }
1540 ConsolePrintf(pCtx, _T("%d modules loaded\n"), g_dwNumModules);
5039dede 1541 }
d87ddcc2
VK
1542 else if (IsCommand(_T("MSGWQ"), szBuffer, 2))
1543 {
1544 String text = MsgWaitQueue::getDiagInfo();
1545 ConsoleWrite(pCtx, text);
1546 ConsoleWrite(pCtx, _T("\n"));
1547 }
35f836fe 1548 else if (IsCommand(_T("OBJECTS"), szBuffer, 1))
5039dede 1549 {
01ca557f
VK
1550 // Get filter
1551 pArg = ExtractWord(pArg, szBuffer);
1552 StrStrip(szBuffer);
1553 DumpObjects(pCtx, (szBuffer[0] != 0) ? szBuffer : NULL);
5039dede 1554 }
35f836fe 1555 else if (IsCommand(_T("POLLERS"), szBuffer, 1))
5039dede 1556 {
208d7427 1557 ShowPollers(pCtx);
5039dede 1558 }
35f836fe 1559 else if (IsCommand(_T("QUEUES"), szBuffer, 1))
5039dede 1560 {
d140955e
VK
1561 ShowQueueStats(pCtx, &g_dataCollectionQueue, _T("Data collector"));
1562 ShowQueueStats(pCtx, &g_dciCacheLoaderQueue, _T("DCI cache loader"));
76fcb995
VK
1563 ShowQueueStats(pCtx, g_dbWriterQueue, _T("Database writer"));
1564 ShowQueueStats(pCtx, g_dciDataWriterQueue, _T("Database writer (IData)"));
1565 ShowQueueStats(pCtx, g_dciRawDataWriterQueue, _T("Database writer (raw DCI values)"));
35f836fe 1566 ShowQueueStats(pCtx, g_pEventQueue, _T("Event processor"));
35f836fe 1567 ShowQueueStats(pCtx, &g_nodePollerQueue, _T("Node poller"));
f1784ab6
VK
1568 ShowQueueStats(pCtx, &g_syslogProcessingQueue, _T("Syslog processing"));
1569 ShowQueueStats(pCtx, &g_syslogWriteQueue, _T("Syslog writer"));
35f836fe 1570 ConsolePrintf(pCtx, _T("\n"));
5039dede 1571 }
35f836fe 1572 else if (IsCommand(_T("ROUTING-TABLE"), szBuffer, 1))
5039dede 1573 {
967893bb 1574 UINT32 dwNode;
5039dede
AK
1575 NetObj *pObject;
1576
1577 pArg = ExtractWord(pArg, szBuffer);
35f836fe 1578 dwNode = _tcstoul(szBuffer, NULL, 0);
5039dede
AK
1579 if (dwNode != 0)
1580 {
1581 pObject = FindObjectById(dwNode);
1582 if (pObject != NULL)
1583 {
c42b4551 1584 if (pObject->getObjectClass() == OBJECT_NODE)
5039dede
AK
1585 {
1586 ROUTING_TABLE *pRT;
35f836fe 1587 TCHAR szIpAddr[16];
5039dede
AK
1588 int i;
1589
c42b4551 1590 ConsolePrintf(pCtx, _T("Routing table for node %s:\n\n"), pObject->getName());
58b3e451 1591 pRT = ((Node *)pObject)->getCachedRoutingTable();
5039dede
AK
1592 if (pRT != NULL)
1593 {
1594 for(i = 0; i < pRT->iNumEntries; i++)
1595 {
35f836fe
VK
1596 _sntprintf(szBuffer, 256, _T("%s/%d"), IpToStr(pRT->pRoutes[i].dwDestAddr, szIpAddr),
1597 BitsInMask(pRT->pRoutes[i].dwDestMask));
1598 ConsolePrintf(pCtx, _T("%-18s %-15s %-6d %d\n"), szBuffer,
1599 IpToStr(pRT->pRoutes[i].dwNextHop, szIpAddr),
1600 pRT->pRoutes[i].dwIfIndex, pRT->pRoutes[i].dwRouteType);
5039dede 1601 }
532990d2 1602 ConsoleWrite(pCtx, _T("\n"));
5039dede
AK
1603 }
1604 else
1605 {
532990d2 1606 ConsoleWrite(pCtx, _T("Node doesn't have cached routing table\n\n"));
5039dede
AK
1607 }
1608 }
1609 else
1610 {
532990d2 1611 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
5039dede
AK
1612 }
1613 }
1614 else
1615 {
35f836fe 1616 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
5039dede
AK
1617 }
1618 }
1619 else
1620 {
532990d2 1621 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
5039dede
AK
1622 }
1623 }
35f836fe 1624 else if (IsCommand(_T("SESSIONS"), szBuffer, 2))
5039dede 1625 {
532990d2 1626 ConsoleWrite(pCtx, _T("\x1b[1mCLIENT SESSIONS\x1b[0m\n============================================================\n"));
534e1b83 1627 DumpClientSessions(pCtx);
532990d2 1628 ConsoleWrite(pCtx, _T("\n\x1b[1mMOBILE DEVICE SESSIONS\x1b[0m\n============================================================\n"));
534e1b83 1629 DumpMobileDeviceSessions(pCtx);
5039dede 1630 }
35f836fe 1631 else if (IsCommand(_T("STATS"), szBuffer, 2))
5039dede
AK
1632 {
1633 ShowServerStats(pCtx);
1634 }
5d3459af
VK
1635 else if (IsCommand(_T("THREADS"), szBuffer, 2))
1636 {
1637 ShowThreadPool(pCtx, g_mainThreadPool);
1638 }
b833cbf5
VK
1639 else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
1640 {
1641 pArg = ExtractWord(pArg, szBuffer);
1642 UINT32 nodeId = _tcstoul(szBuffer, NULL, 0);
1643 if (nodeId != 0)
1644 {
1645 Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
1646 if (node != NULL)
1647 {
1648 LinkLayerNeighbors *nbs = BuildLinkLayerNeighborList(node);
1649 if (nbs != NULL)
1650 {
1651 ConsolePrintf(pCtx, _T("Proto | PtP | ifLocal | ifRemote | Peer\n")
1652 _T("--------+-----+---------+----------+------------------------------------\n"));
1653 for(int i = 0; i < nbs->size(); i++)
1654 {
1655 LL_NEIGHBOR_INFO *ni = nbs->getConnection(i);
1656 TCHAR peer[256];
1657 if (ni->objectId != 0)
1658 {
1659 NetObj *object = FindObjectById(ni->objectId);
1660 if (object != NULL)
c42b4551 1661 _sntprintf(peer, 256, _T("%s [%d]"), object->getName(), ni->objectId);
b833cbf5
VK
1662 else
1663 _sntprintf(peer, 256, _T("[%d]"), ni->objectId);
1664 }
1665 else
1666 {
1667 peer[0] = 0;
1668 }
1669 ConsolePrintf(pCtx, _T("%-7s | %c | %7d | %7d | %s\n"),
1670 GetLinkLayerProtocolName(ni->protocol), ni->isPtToPt ? _T('Y') : _T('N'), ni->ifLocal, ni->ifRemote, peer);
1671 }
1672 nbs->decRefCount();
1673 }
1674 else
1675 {
532990d2 1676 ConsoleWrite(pCtx, _T("ERROR: call to BuildLinkLayerNeighborList failed\n\n"));
b833cbf5
VK
1677 }
1678 }
1679 else
1680 {
1681 ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), nodeId);
1682 }
1683 }
1684 else
1685 {
532990d2 1686 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
b833cbf5
VK
1687 }
1688 }
35f836fe 1689 else if (IsCommand(_T("USERS"), szBuffer, 1))
5039dede
AK
1690 {
1691 DumpUsers(pCtx);
1692 }
b0ff1179
VK
1693 else if (IsCommand(_T("VLANS"), szBuffer, 1))
1694 {
967893bb 1695 UINT32 dwNode;
b0ff1179
VK
1696 NetObj *pObject;
1697
1698 pArg = ExtractWord(pArg, szBuffer);
1699 dwNode = _tcstoul(szBuffer, NULL, 0);
1700 if (dwNode != 0)
1701 {
1702 pObject = FindObjectById(dwNode);
1703 if (pObject != NULL)
1704 {
c42b4551 1705 if (pObject->getObjectClass() == OBJECT_NODE)
b0ff1179
VK
1706 {
1707 VlanList *vlans = ((Node *)pObject)->getVlans();
1708 if (vlans != NULL)
1709 {
532990d2
VK
1710 ConsoleWrite(pCtx, _T("\x1b[1mVLAN\x1b[0m | \x1b[1mName\x1b[0m | \x1b[1mPorts\x1b[0m\n")
1711 _T("-----+------------------+-----------------------------------------------------------------\n"));
a6312bd6 1712 for(int i = 0; i < vlans->size(); i++)
b0ff1179
VK
1713 {
1714 VlanInfo *vlan = vlans->get(i);
1715 ConsolePrintf(pCtx, _T("%4d | %-16s |"), vlan->getVlanId(), vlan->getName());
1716 for(int j = 0; j < vlan->getNumPorts(); j++)
1717 ConsolePrintf(pCtx, _T(" %d.%d"), (int)(vlan->getPorts()[j] >> 16), (int)(vlan->getPorts()[j] & 0xFFFF));
1718 ConsolePrintf(pCtx, _T("\n"));
1719 }
1720 ConsolePrintf(pCtx, _T("\n"));
1721 vlans->decRefCount();
1722 }
1723 else
1724 {
532990d2 1725 ConsoleWrite(pCtx, _T("\x1b[31mNode doesn't have VLAN information\x1b[0m\n\n"));
b0ff1179
VK
1726 }
1727 }
1728 else
1729 {
532990d2 1730 ConsoleWrite(pCtx, _T("\x1b[31mERROR: Object is not a node\x1b[0m\n\n"));
b0ff1179
VK
1731 }
1732 }
1733 else
1734 {
1735 ConsolePrintf(pCtx, _T("\x1b[31mERROR: Object with ID %d does not exist\x1b[0m\n\n"), dwNode);
1736 }
1737 }
1738 else
1739 {
532990d2 1740 ConsoleWrite(pCtx, _T("\x1b[31mERROR: Invalid or missing node ID\x1b[0m\n\n"));
b0ff1179
VK
1741 }
1742 }
35f836fe 1743 else if (IsCommand(_T("WATCHDOG"), szBuffer, 1))
5039dede
AK
1744 {
1745 WatchdogPrintStatus(pCtx);
532990d2 1746 ConsoleWrite(pCtx, _T("\n"));
5039dede
AK
1747 }
1748 else
1749 {
1750 if (szBuffer[0] == 0)
532990d2 1751 ConsoleWrite(pCtx, _T("ERROR: Missing subcommand\n\n"));
5039dede 1752 else
532990d2 1753 ConsoleWrite(pCtx, _T("ERROR: Invalid SHOW subcommand\n\n"));
5039dede
AK
1754 }
1755 }
06a8857b
AK
1756 else if (IsCommand(_T("EXEC"), szBuffer, 3))
1757 {
1758 pArg = ExtractWord(pArg, szBuffer);
35104062 1759
e323047c 1760 bool libraryLocked = true;
6b29839d 1761 bool destroyCompiledScript = false;
e323047c
VK
1762 g_pScriptLibrary->lock();
1763
35104062
VK
1764 NXSL_Program *compiledScript = g_pScriptLibrary->findScript(szBuffer);
1765 if (compiledScript == NULL)
06a8857b 1766 {
e323047c
VK
1767 g_pScriptLibrary->unlock();
1768 libraryLocked = false;
6b29839d 1769 destroyCompiledScript = true;
35104062 1770 char *script;
967893bb 1771 UINT32 fileSize;
35104062 1772 if ((script = (char *)LoadFile(szBuffer, &fileSize)) != NULL)
06a8857b 1773 {
35104062
VK
1774 const int errorMsgLen = 512;
1775 TCHAR errorMsg[errorMsgLen];
1776#ifdef UNICODE
1777 WCHAR *wscript = WideStringFromMBString(script);
1778 compiledScript = NXSLCompile(wscript, errorMsg, errorMsgLen);
1779 free(wscript);
1780#else
1781 compiledScript = NXSLCompile(script, errorMsg, errorMsgLen);
1782#endif
1783 free(script);
1784 if (compiledScript == NULL)
06a8857b 1785 {
35104062 1786 ConsolePrintf(pCtx, _T("ERROR: Script compilation error: %s\n\n"), errorMsg);
06a8857b
AK
1787 }
1788 }
1789 else
1790 {
35104062 1791 ConsolePrintf(pCtx, _T("ERROR: Script \"%s\" not found\n\n"), szBuffer);
06a8857b
AK
1792 }
1793 }
35104062
VK
1794
1795 if (compiledScript != NULL)
06a8857b 1796 {
35104062 1797 NXSL_ServerEnv *pEnv = new NXSL_ServerEnv;
2773ef30 1798 pEnv->setConsole(pCtx);
35104062 1799
6b29839d
VK
1800 NXSL_VM *vm = new NXSL_VM(pEnv);
1801 if (vm->load(compiledScript))
d9177dd1 1802 {
6b29839d
VK
1803 if (libraryLocked)
1804 {
1805 g_pScriptLibrary->unlock();
1806 libraryLocked = false;
1807 }
1808
1809 NXSL_Value *argv[32];
1810 int argc = 0;
1811 while(argc < 32)
1812 {
1813 pArg = ExtractWord(pArg, szBuffer);
1814 if (szBuffer[0] == 0)
1815 break;
1816 argv[argc++] = new NXSL_Value(szBuffer);
1817 }
1818
1819 if (vm->run(argc, argv))
1820 {
1821 NXSL_Value *pValue = vm->getResult();
1822 int retCode = pValue->getValueAsInt32();
1823 ConsolePrintf(pCtx, _T("INFO: Script finished with rc=%d\n\n"), retCode);
1824 }
1825 else
1826 {
1827 ConsolePrintf(pCtx, _T("ERROR: Script finished with error: %s\n\n"), vm->getErrorText());
1828 }
1829 }
1830 else
1831 {
1832 ConsolePrintf(pCtx, _T("ERROR: VM creation failed: %s\n\n"), vm->getErrorText());
1833 }
1834 delete vm;
1835 if (destroyCompiledScript)
1836 delete compiledScript;
06a8857b 1837 }
e323047c
VK
1838 if (libraryLocked)
1839 g_pScriptLibrary->unlock();
06a8857b 1840 }
35f836fe 1841 else if (IsCommand(_T("TRACE"), szBuffer, 1))
5039dede 1842 {
967893bb 1843 UINT32 dwNode1, dwNode2;
5039dede 1844 NetObj *pObject1, *pObject2;
6d069676 1845 NetworkPath *pTrace;
35f836fe 1846 TCHAR szNextHop[16];
5039dede
AK
1847 int i;
1848
1849 // Get arguments
1850 pArg = ExtractWord(pArg, szBuffer);
35f836fe 1851 dwNode1 = _tcstoul(szBuffer, NULL, 0);
5039dede
AK
1852
1853 pArg = ExtractWord(pArg, szBuffer);
35f836fe 1854 dwNode2 = _tcstoul(szBuffer, NULL, 0);
5039dede
AK
1855
1856 if ((dwNode1 != 0) && (dwNode2 != 0))
1857 {
1858 pObject1 = FindObjectById(dwNode1);
1859 if (pObject1 == NULL)
1860 {
35f836fe 1861 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode1);
5039dede
AK
1862 }
1863 else
1864 {
1865 pObject2 = FindObjectById(dwNode2);
1866 if (pObject2 == NULL)
1867 {
35f836fe 1868 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode2);
5039dede
AK
1869 }
1870 else
1871 {
c42b4551 1872 if ((pObject1->getObjectClass() == OBJECT_NODE) && (pObject2->getObjectClass() == OBJECT_NODE))
5039dede
AK
1873 {
1874 pTrace = TraceRoute((Node *)pObject1, (Node *)pObject2);
1875 if (pTrace != NULL)
1876 {
99c11466
VK
1877 TCHAR sourceIp[32];
1878 ConsolePrintf(pCtx, _T("Trace from %s to %s (%d hops, %s, source IP %s):\n"),
c42b4551 1879 pObject1->getName(), pObject2->getName(), pTrace->getHopCount(),
99c11466 1880 pTrace->isComplete() ? _T("complete") : _T("incomplete"),
c75e9ee4 1881 pTrace->getSourceAddress().toString(sourceIp));
99c11466 1882 for(i = 0; i < pTrace->getHopCount(); i++)
6d069676
VK
1883 {
1884 HOP_INFO *hop = pTrace->getHopInfo(i);
35f836fe 1885 ConsolePrintf(pCtx, _T("[%d] %s %s %s %d\n"),
c42b4551
VK
1886 hop->object->getId(),
1887 hop->object->getName(),
c75e9ee4 1888 hop->nextHop.toString(szNextHop),
6d069676
VK
1889 hop->isVpn ? _T("VPN Connector ID:") : _T("Interface Index: "),
1890 hop->ifIndex);
1891 }
1892 delete pTrace;
35f836fe 1893 ConsolePrintf(pCtx, _T("\n"));
5039dede
AK
1894 }
1895 else
1896 {
532990d2 1897 ConsoleWrite(pCtx, _T("ERROR: Call to TraceRoute() failed\n\n"));
5039dede
AK
1898 }
1899 }
1900 else
1901 {
532990d2 1902 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
5039dede
AK
1903 }
1904 }
1905 }
1906 }
1907 else
1908 {
532990d2 1909 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node id(s)\n\n"));
5039dede
AK
1910 }
1911 }
d9177dd1 1912 else if (IsCommand(_T("LDAPSYNC"), szBuffer, 4))
1913 {
1914 LDAPConnection conn;
1915 conn.syncUsers();
1916 }
35f836fe 1917 else if (IsCommand(_T("HELP"), szBuffer, 2) || IsCommand(_T("?"), szBuffer, 1))
5039dede 1918 {
532990d2
VK
1919 ConsoleWrite(pCtx,
1920 _T("Valid commands are:\n")
48c0079d 1921 _T(" debug [<level>|off] - Set debug level (valid range is 0..9)\n")
48a3497b
VK
1922 _T(" down - Shutdown NetXMS server\n")
1923 _T(" exec <script> [<params>] - Executes NXSL script from script library\n")
35f836fe 1924 _T(" exit - Exit from remote session\n")
5d9a9c84 1925 _T(" kill <session> - Kill client session\n")
206e268e 1926 _T(" get <variable> - Get value of server configuration variable\n")
35f836fe 1927 _T(" help - Display this help\n")
d9177dd1 1928 _T(" ldapsync - Synchronize ldap users with local user database\n")
06b83321 1929 _T(" ping <address> - Send ICMP echo request to given IP address\n")
f34e7a6e 1930 _T(" poll <type> <node> - Initiate node poll\n")
35f836fe 1931 _T(" raise <exception> - Raise exception\n")
206e268e 1932 _T(" set <variable> <value> - Set value of server configuration variable\n")
50d0de67 1933 _T(" show components <node> - Show physical components of given node\n")
9c133761 1934 _T(" show dbcp - Show active sessions in database connection pool\n")
48a3497b 1935 _T(" show fdb <node> - Show forwarding database for node\n")
35f836fe 1936 _T(" show flags - Show internal server flags\n")
5962498b 1937 _T(" show heap - Show heap information\n")
35f836fe 1938 _T(" show index <index> - Show internal index\n")
713825d1 1939 _T(" show modules - Show loaded server modules\n")
d87ddcc2 1940 _T(" show msgwq - Show message wait queues information\n")
01ca557f 1941 _T(" show objects [<filter>] - Dump network objects to screen\n")
35f836fe
VK
1942 _T(" show pollers - Show poller threads state information\n")
1943 _T(" show queues - Show internal queues statistics\n")
1944 _T(" show routing-table <node> - Show cached routing table for node\n")
1945 _T(" show sessions - Show active client sessions\n")
1946 _T(" show stats - Show server statistics\n")
b833cbf5 1947 _T(" show topology <node> - Collect and show link layer topology for node\n")
35f836fe 1948 _T(" show users - Show users\n")
b0ff1179 1949 _T(" show vlans <node> - Show cached VLAN information for node\n")
35f836fe
VK
1950 _T(" show watchdog - Display watchdog information\n")
1951 _T(" trace <node1> <node2> - Show network path trace between two nodes\n")
1952 _T("\nAlmost all commands can be abbreviated to 2 or 3 characters\n")
1953 _T("\n"));
5039dede 1954 }
d9177dd1 1955 else
5039dede 1956 {
532990d2 1957 ConsoleWrite(pCtx, _T("UNKNOWN COMMAND\n\n"));
5039dede
AK
1958 }
1959
1960 return nExitCode;
1961}
1962
fdbee7f8
VK
1963/**
1964 * Signal handler for UNIX platforms
1965 */
5039dede
AK
1966#ifndef _WIN32
1967
1968void SignalHandlerStub(int nSignal)
1969{
1970 // should be unused, but JIC...
1971 if (nSignal == SIGCHLD)
1972 {
1973 while (waitpid(-1, NULL, WNOHANG) > 0)
1974 ;
1975 }
1976}
1977
1978THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
1979{
1980 sigset_t signals;
1981 int nSignal;
1982 BOOL bCallShutdown = FALSE;
1983
1984 m_signalHandlerThread = pthread_self();
1985
1986 // default for SIGCHLD: ignore
1987 signal(SIGCHLD, &SignalHandlerStub);
1988
1989 sigemptyset(&signals);
1990 sigaddset(&signals, SIGTERM);
1991 sigaddset(&signals, SIGINT);
5039dede
AK
1992 sigaddset(&signals, SIGSEGV);
1993 sigaddset(&signals, SIGCHLD);
1994 sigaddset(&signals, SIGHUP);
1995 sigaddset(&signals, SIGUSR1);
1996 sigaddset(&signals, SIGUSR2);
95e2329a
VK
1997#if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
1998 sigaddset(&signals, SIGPIPE);
1999#endif
5039dede
AK
2000
2001 sigprocmask(SIG_BLOCK, &signals, NULL);
2002
2003 while(1)
2004 {
2005 if (sigwait(&signals, &nSignal) == 0)
2006 {
2007 switch(nSignal)
2008 {
2009 case SIGTERM:
2010 case SIGINT:
2011 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
2012 if (IsStandalone())
2013 bCallShutdown = TRUE;
2014 ConditionSet(m_condShutdown);
2015 goto stop_handler;
2016 case SIGSEGV:
2017 abort();
2018 break;
2019 case SIGCHLD:
2020 while (waitpid(-1, NULL, WNOHANG) > 0)
2021 ;
2022 break;
2023 case SIGUSR1:
c8076b19 2024 if (g_flags & AF_SHUTDOWN)
5039dede
AK
2025 goto stop_handler;
2026 break;
2027 default:
2028 break;
2029 }
2030 }
2031 else
2032 {
2033 ThreadSleepMs(100);
2034 }
2035 }
2036
2037stop_handler:
2038 sigprocmask(SIG_UNBLOCK, &signals, NULL);
2039 if (bCallShutdown)
2040 Shutdown();
2041 return THREAD_OK;
2042}
2043
2044#endif
2045
fdbee7f8
VK
2046/**
2047 * Common main()
2048 */
5039dede
AK
2049THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
2050{
2051 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
2052
7bdb43c3
VK
2053 if (IsStandalone())
2054 {
c8076b19 2055 if (!(g_flags & AF_DEBUG_CONSOLE_DISABLED))
7bdb43c3
VK
2056 {
2057 char *ptr, szCommand[256];
2058 struct __console_ctx ctx;
35f836fe 2059#ifdef UNICODE
7bdb43c3 2060 WCHAR wcCommand[256];
35f836fe 2061#endif
5039dede 2062
7bdb43c3
VK
2063 ctx.hSocket = -1;
2064 ctx.socketMutex = INVALID_MUTEX_HANDLE;
2065 ctx.pMsg = NULL;
2066 ctx.session = NULL;
2067 ctx.output = NULL;
8e17001f 2068 WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T(" Ready\n")
7bdb43c3
VK
2069 _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n")
2070 _T("System Console\n\n"));
5039dede
AK
2071
2072#if USE_READLINE
7bdb43c3
VK
2073 // Initialize readline library if we use it
2074 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
5039dede
AK
2075#endif
2076
7bdb43c3
VK
2077 while(1)
2078 {
5039dede 2079#if USE_READLINE
7bdb43c3 2080 ptr = readline("\x1b[33mnetxmsd:\x1b[0m ");
5039dede 2081#else
7bdb43c3
VK
2082 WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m "));
2083 fflush(stdout);
2084 if (fgets(szCommand, 255, stdin) == NULL)
2085 break; // Error reading stdin
2086 ptr = strchr(szCommand, '\n');
2087 if (ptr != NULL)
2088 *ptr = 0;
2089 ptr = szCommand;
5039dede
AK
2090#endif
2091
7bdb43c3
VK
2092 if (ptr != NULL)
2093 {
35f836fe 2094#ifdef UNICODE
7bdb43c3
VK
2095 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
2096 wcCommand[255] = 0;
2097 StrStrip(wcCommand);
2098 if (wcCommand[0] != 0)
2099 {
2100 if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN)
35f836fe 2101#else
7bdb43c3
VK
2102 StrStrip(ptr);
2103 if (*ptr != 0)
2104 {
2105 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
35f836fe 2106#endif
7bdb43c3 2107 break;
5039dede 2108#if USE_READLINE
7bdb43c3 2109 add_history(ptr);
5039dede 2110#endif
7bdb43c3 2111 }
5039dede 2112#if USE_READLINE
7bdb43c3 2113 free(ptr);
5039dede 2114#endif
7bdb43c3
VK
2115 }
2116 else
2117 {
2118 _tprintf(_T("\n"));
2119 }
2120 }
5039dede
AK
2121
2122#if USE_READLINE
7bdb43c3 2123 free(ptr);
5039dede 2124#endif
7bdb43c3
VK
2125 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
2126 Shutdown();
2127 }
2128 else
2129 {
2130 // standalone with debug console disabled
2131#ifdef _WIN32
2132 _tprintf(_T("Server running. Press ESC to shutdown.\n"));
2133 while(1)
2134 {
2135 if (_getch() == 27)
2136 break;
2137 }
2138 _tprintf(_T("Server shutting down...\n"));
2139 Shutdown();
2140#else
2141 _tprintf(_T("Server running. Press Ctrl+C to shutdown.\n"));
2142 // Shutdown will be called from signal handler
2143 ConditionWait(m_condShutdown, INFINITE);
2144#endif
2145 }
5039dede
AK
2146 }
2147 else
2148 {
2149 ConditionWait(m_condShutdown, INFINITE);
2150 // On Win32, Shutdown() will be called by service control handler
2151#ifndef _WIN32
2152 Shutdown();
2153#endif
2154 }
2155 return THREAD_OK;
2156}
2157
fdbee7f8
VK
2158/**
2159 * Initiate server shutdown
2160 */
035a4d73 2161void InitiateShutdown()
5039dede
AK
2162{
2163#ifdef _WIN32
2164 Shutdown();
2165#else
2166 if (IsStandalone())
2167 {
2168 Shutdown();
2169 }
2170 else
2171 {
2172 pthread_kill(m_signalHandlerThread, SIGTERM);
2173 }
2174#endif
2175}
2176
fdbee7f8
VK
2177/**
2178 *DLL Entry point
2179 */
5039dede
AK
2180#ifdef _WIN32
2181
2182BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
2183{
2184 if (dwReason == DLL_PROCESS_ATTACH)
2185 DisableThreadLibraryCalls(hInstance);
2186 return TRUE;
2187}
2188
2189#endif