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