fixed event storm on object delete; changed behaviour of SYS_SUBNET_ADDED
[public/netxms.git] / src / server / core / main.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
fdbee7f8 3** Copyright (C) 2003-2013 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>
5039dede 26
b847803c 27#if !defined(_WIN32) && HAVE_READLINE_READLINE_H && HAVE_READLINE && !defined(UNICODE)
0322eed7
VK
28#include <readline/readline.h>
29#include <readline/history.h>
30#define USE_READLINE 1
5039dede
AK
31#endif
32
33#ifdef _WIN32
a23d8e0d
VK
34#include <errno.h>
35#include <psapi.h>
d717b69c
VK
36#define open _open
37#define write _write
38#define close _close
5039dede 39#else
a23d8e0d
VK
40#include <signal.h>
41#include <sys/wait.h>
5039dede
AK
42#endif
43
3a82d5ae
VK
44/**
45 * Messages generated by mc.pl (for UNIX version only)
46 */
5039dede
AK
47#ifndef _WIN32
48extern unsigned int g_dwNumMessages;
49extern const TCHAR *g_szMessages[];
50#endif
51
8f99849c
VK
52/**
53 * Shutdown reasons
54 */
030a0779
VK
55#define SHUTDOWN_DEFAULT 0
56#define SHUTDOWN_FROM_CONSOLE 1
57#define SHUTDOWN_BY_SIGNAL 2
5039dede 58
8f99849c
VK
59/**
60 * Externals
61 */
5039dede
AK
62extern Queue g_statusPollQueue;
63extern Queue g_configPollQueue;
040c45fa 64extern Queue g_topologyPollQueue;
5039dede
AK
65extern Queue g_routePollQueue;
66extern Queue g_discoveryPollQueue;
67extern Queue g_nodePollerQueue;
68extern Queue g_conditionPollerQueue;
69extern Queue *g_pItemQueue;
70
36e44abe 71void InitClientListeners();
534e1b83 72void InitMobileDeviceListeners();
36e44abe 73void InitCertificates();
ab185583
VK
74void InitUsers();
75void CleanupUsers();
5039dede 76
534e1b83
VK
77/**
78 * Thread functions
79 */
80THREAD_RESULT THREAD_CALL HouseKeeper(void *);
81THREAD_RESULT THREAD_CALL Syncer(void *);
82THREAD_RESULT THREAD_CALL NodePoller(void *);
83THREAD_RESULT THREAD_CALL PollManager(void *);
84THREAD_RESULT THREAD_CALL EventProcessor(void *);
85THREAD_RESULT THREAD_CALL WatchdogThread(void *);
86THREAD_RESULT THREAD_CALL ClientListener(void *);
87THREAD_RESULT THREAD_CALL ClientListenerIPv6(void *);
88THREAD_RESULT THREAD_CALL MobileDeviceListener(void *);
89THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *);
90THREAD_RESULT THREAD_CALL ISCListener(void *);
91THREAD_RESULT THREAD_CALL LocalAdminListener(void *);
92THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *);
93THREAD_RESULT THREAD_CALL SyslogDaemon(void *);
94THREAD_RESULT THREAD_CALL BeaconPoller(void *);
95THREAD_RESULT THREAD_CALL JobManagerThread(void *);
96THREAD_RESULT THREAD_CALL UptimeCalculator(void *);
d75003e1 97THREAD_RESULT THREAD_CALL ReportingServerConnector(void *);
5039dede 98
534e1b83
VK
99/**
100 * Global variables
101 */
5039dede
AK
102TCHAR NXCORE_EXPORTABLE g_szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE;
103TCHAR NXCORE_EXPORTABLE g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
967893bb
VK
104UINT32 g_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
105UINT32 g_dwMaxLogSize = 16384 * 1024;
106UINT32 g_dwLogHistorySize = 4;
4f8998ca 107TCHAR g_szDailyLogFileSuffix[64] = _T("");
5039dede 108TCHAR NXCORE_EXPORTABLE g_szDumpDir[MAX_PATH] = DEFAULT_DUMP_DIR;
29dc8792 109char g_szCodePage[256] = ICONV_DEFAULT_CODEPAGE;
5039dede
AK
110TCHAR NXCORE_EXPORTABLE g_szListenAddress[MAX_PATH] = _T("0.0.0.0");
111#ifndef _WIN32
b07c50cc 112TCHAR NXCORE_EXPORTABLE g_szPIDFile[MAX_PATH] = _T("/var/run/netxmsd.pid");
5039dede
AK
113#endif
114DB_HANDLE g_hCoreDB = 0;
967893bb
VK
115UINT32 g_dwDiscoveryPollingInterval;
116UINT32 g_dwStatusPollingInterval;
117UINT32 g_dwConfigurationPollingInterval;
118UINT32 g_dwRoutingTableUpdateInterval;
119UINT32 g_dwTopologyPollingInterval;
120UINT32 g_dwConditionPollingInterval;
c59466d2
VK
121UINT32 g_icmpPingSize;
122UINT32 g_icmpPingTimeout = 1500; // ICMP ping timeout (milliseconds)
123UINT32 g_auditFlags;
124UINT32 g_slmPollingInterval;
d96bd4c7 125TCHAR g_szDataDir[MAX_PATH] = _T("");
9796ce45 126TCHAR g_szLibDir[MAX_PATH] = DEFAULT_LIBDIR;
712dd47d
VK
127TCHAR g_szJavaLibDir[MAX_PATH] = DEFAULT_JAVA_LIBDIR;
128TCHAR NXCORE_EXPORTABLE g_szJavaPath[MAX_DB_NAME] = _T("java");
28f5b9a4 129int g_nDBSyntax = DB_SYNTAX_UNKNOWN;
967893bb 130UINT32 NXCORE_EXPORTABLE g_processAffinityMask = DEFAULT_AFFINITY_MASK;
5039dede
AK
131QWORD g_qwServerId;
132RSA *g_pServerKey = NULL;
c59466d2
VK
133time_t g_serverStartTime = 0;
134UINT32 g_lockTimeout = 60000; // Default timeout for acquiring mutex
135UINT32 g_agentCommandTimeout = 4000; // Default timeout for requests to agent
136UINT32 g_thresholdRepeatInterval = 0; // Disabled by default
137int g_requiredPolls = 1;
b8c1ec69 138DB_DRIVER g_dbDriver = NULL;
5039dede 139
f375019e
VK
140/**
141 * Static data
142 */
5039dede
AK
143static CONDITION m_condShutdown = INVALID_CONDITION_HANDLE;
144static THREAD m_thPollManager = INVALID_THREAD_HANDLE;
145static THREAD m_thHouseKeeper = INVALID_THREAD_HANDLE;
146static THREAD m_thSyncer = INVALID_THREAD_HANDLE;
147static THREAD m_thSyslogDaemon = INVALID_THREAD_HANDLE;
148static int m_nShutdownReason = SHUTDOWN_DEFAULT;
149
150#ifndef _WIN32
151static pthread_t m_signalHandlerThread;
152#endif
153
496390c2
VK
154/**
155 * Sleep for specified number of seconds or until system shutdown arrives
156 * Function will return TRUE if shutdown event occurs
157 *
158 * @param seconds seconds to sleep
159 * @return true if server is shutting down
160 */
161BOOL NXCORE_EXPORTABLE SleepAndCheckForShutdown(int seconds)
5039dede 162{
496390c2 163 return ConditionWait(m_condShutdown, seconds * 1000);
5039dede
AK
164}
165
496390c2
VK
166/**
167 * Disconnect from database (exportable function for startup module)
168 */
73869331 169void NXCORE_EXPORTABLE ShutdownDB()
5039dede
AK
170{
171 if (g_hCoreDB != NULL)
172 DBDisconnect(g_hCoreDB);
b8c1ec69 173 DBUnloadDriver(g_dbDriver);
5039dede
AK
174}
175
496390c2
VK
176/**
177 * Check data directory for existence
178 */
35f836fe 179static BOOL CheckDataDir()
5039dede 180{
35f836fe 181 TCHAR szBuffer[MAX_PATH];
5039dede 182
35f836fe 183 if (_tchdir(g_szDataDir) == -1)
5039dede
AK
184 {
185 nxlog_write(MSG_INVALID_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", g_szDataDir);
186 return FALSE;
187 }
188
189#ifdef _WIN32
35f836fe 190#define MKDIR(name) _tmkdir(name)
5039dede 191#else
35f836fe 192#define MKDIR(name) _tmkdir(name, 0700)
5039dede
AK
193#endif
194
195 // Create directory for mib files if it doesn't exist
35f836fe
VK
196 _tcscpy(szBuffer, g_szDataDir);
197 _tcscat(szBuffer, DDIR_MIBS);
5039dede
AK
198 if (MKDIR(szBuffer) == -1)
199 if (errno != EEXIST)
200 {
201 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
202 return FALSE;
203 }
204
5039dede 205 // Create directory for package files if it doesn't exist
35f836fe
VK
206 _tcscpy(szBuffer, g_szDataDir);
207 _tcscat(szBuffer, DDIR_PACKAGES);
5039dede
AK
208 if (MKDIR(szBuffer) == -1)
209 if (errno != EEXIST)
210 {
211 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
212 return FALSE;
213 }
214
4d0c32f3 215 // Create directory for map background images if it doesn't exist
35f836fe
VK
216 _tcscpy(szBuffer, g_szDataDir);
217 _tcscat(szBuffer, DDIR_BACKGROUNDS);
4d0c32f3
VK
218 if (MKDIR(szBuffer) == -1)
219 if (errno != EEXIST)
220 {
221 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
222 return FALSE;
223 }
224
e6b9439a
AK
225 // Create directory for image library is if does't exists
226 _tcscpy(szBuffer, g_szDataDir);
227 _tcscat(szBuffer, DDIR_IMAGES);
228 if (MKDIR(szBuffer) == -1)
229 {
230 if (errno != EEXIST)
231 {
232 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
233 return FALSE;
234 }
235 }
236
6f16f12d
VK
237 // Create directory for shared file store if does't exists
238 _tcscpy(szBuffer, g_szDataDir);
239 _tcscat(szBuffer, DDIR_SHARED_FILES);
240 if (MKDIR(szBuffer) == -1)
241 {
242 if (errno != EEXIST)
243 {
244 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
245 return FALSE;
246 }
247 }
248
619e5c9b
VK
249 // Create directory for file store if does't exists
250 _tcscpy(szBuffer, g_szDataDir);
251 _tcscat(szBuffer, DDIR_FILES);
252 if (MKDIR(szBuffer) == -1)
253 {
254 if (errno != EEXIST)
255 {
256 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
57fef75c
VK
257 return FALSE;
258 }
259 }
260
261 // Create directory for reports if does't exists
262 _tcscpy(szBuffer, g_szDataDir);
263 _tcscat(szBuffer, DDIR_REPORTS);
264 if (MKDIR(szBuffer) == -1)
265 {
266 if (errno != EEXIST)
267 {
268 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
619e5c9b
VK
269 return FALSE;
270 }
271 }
272
5039dede
AK
273#undef MKDIR
274
275 return TRUE;
276}
277
496390c2
VK
278/**
279 * Load global configuration parameters
280 */
5039dede
AK
281static void LoadGlobalConfig()
282{
35f836fe
VK
283 g_dwDiscoveryPollingInterval = ConfigReadInt(_T("DiscoveryPollingInterval"), 900);
284 g_dwStatusPollingInterval = ConfigReadInt(_T("StatusPollingInterval"), 60);
285 g_dwConfigurationPollingInterval = ConfigReadInt(_T("ConfigurationPollingInterval"), 3600);
286 g_dwRoutingTableUpdateInterval = ConfigReadInt(_T("RoutingTableUpdateInterval"), 300);
040c45fa 287 g_dwTopologyPollingInterval = ConfigReadInt(_T("TopologyPollingInterval"), 1800);
35f836fe 288 g_dwConditionPollingInterval = ConfigReadInt(_T("ConditionPollingInterval"), 60);
c59466d2 289 g_slmPollingInterval = ConfigReadInt(_T("SlmPollingInterval"), 60);
35f836fe 290 if (ConfigReadInt(_T("DeleteEmptySubnets"), 1))
5039dede 291 g_dwFlags |= AF_DELETE_EMPTY_SUBNETS;
35f836fe 292 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
5039dede 293 g_dwFlags |= AF_ENABLE_SNMP_TRAPD;
35f836fe 294 if (ConfigReadInt(_T("EnableZoning"), 0))
5039dede 295 g_dwFlags |= AF_ENABLE_ZONING;
549f48b3
VK
296 if (ConfigReadInt(_T("EnableObjectTransactions"), 0))
297 g_dwFlags |= AF_ENABLE_OBJECT_TRANSACTIONS;
35f836fe 298 if (ConfigReadInt(_T("EnableMultipleDBConnections"), 1))
2a8e6a7b
VK
299 {
300 // SQLite has troubles with multiple connections to the same database
301 // from different threads, and it does not speed up database access
302 // anyway, so we will not enable multiple connections for SQLite
303 if (g_nDBSyntax != DB_SYNTAX_SQLITE)
304 {
305 g_dwFlags |= AF_ENABLE_MULTIPLE_DB_CONN;
306 }
307 else
308 {
309 DbgPrintf(1, _T("Configuration parameter EnableMultipleDBConnections ignored because database engine is SQLite"));
310 }
311 }
35f836fe 312 if (ConfigReadInt(_T("RunNetworkDiscovery"), 0))
5039dede 313 g_dwFlags |= AF_ENABLE_NETWORK_DISCOVERY;
35f836fe 314 if (ConfigReadInt(_T("ActiveNetworkDiscovery"), 0))
5039dede 315 g_dwFlags |= AF_ACTIVE_NETWORK_DISCOVERY;
e02953a4
VK
316 if (ConfigReadInt(_T("UseSNMPTrapsForDiscovery"), 0))
317 g_dwFlags |= AF_SNMP_TRAP_DISCOVERY;
35f836fe 318 if (ConfigReadInt(_T("ResolveNodeNames"), 1))
5039dede 319 g_dwFlags |= AF_RESOLVE_NODE_NAMES;
35f836fe 320 if (ConfigReadInt(_T("SyncNodeNamesWithDNS"), 0))
5039dede 321 g_dwFlags |= AF_SYNC_NODE_NAMES_WITH_DNS;
35f836fe 322 if (ConfigReadInt(_T("InternalCA"), 0))
5039dede 323 g_dwFlags |= AF_INTERNAL_CA;
35f836fe 324 if (ConfigReadInt(_T("CheckTrustedNodes"), 1))
5039dede 325 g_dwFlags |= AF_CHECK_TRUSTED_NODES;
3bbc7435
AK
326 if (ConfigReadInt(_T("EnableNXSLContainerFunctions"), 1))
327 g_dwFlags |= AF_ENABLE_NXSL_CONTAINER_FUNCS;
a203ea53
AK
328 if (ConfigReadInt(_T("UseFQDNForNodeNames"), 1))
329 g_dwFlags |= AF_USE_FQDN_FOR_NODE_NAMES;
dc4a1aec
AK
330 if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 0))
331 g_dwFlags |= AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE;
fc958888 332
d96bd4c7
VK
333 if (g_szDataDir[0] == 0)
334 {
35f836fe 335 ConfigReadStr(_T("DataDirectory"), g_szDataDir, MAX_PATH, DEFAULT_DATA_DIR);
d96bd4c7
VK
336 DbgPrintf(1, _T("Data directory set to %s from server configuration variable"), g_szDataDir);
337 }
338 else
339 {
340 DbgPrintf(1, _T("Using data directory %s"), g_szDataDir);
341 }
342
c59466d2
VK
343 g_icmpPingTimeout = ConfigReadInt(_T("IcmpPingTimeout"), 1500);
344 g_icmpPingSize = ConfigReadInt(_T("IcmpPingSize"), 46);
345 g_lockTimeout = ConfigReadInt(_T("LockTimeout"), 60000);
35f836fe 346 g_dwSNMPTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 2000);
c59466d2
VK
347 g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000);
348 g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
349 g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
5039dede
AK
350}
351
fdbee7f8
VK
352/**
353 * Initialize cryptografic functions
354 */
73869331 355static BOOL InitCryptografy()
5039dede
AK
356{
357#ifdef _WITH_ENCRYPTION
35f836fe 358 TCHAR szKeyFile[MAX_PATH];
5039dede
AK
359 BOOL bResult = FALSE;
360 int fd, iPolicy;
967893bb 361 UINT32 dwLen;
5039dede
AK
362 BYTE *pBufPos, *pKeyBuffer, hash[SHA1_DIGEST_SIZE];
363
9e9d631e 364 if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x1F)))
5039dede
AK
365 return FALSE;
366
958a9397 367 SSL_library_init();
0fd5c0a1 368 SSL_load_error_strings();
958a9397 369
35f836fe
VK
370 _tcscpy(szKeyFile, g_szDataDir);
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 */
35f836fe 460static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, void *userArg)
5039dede
AK
461{
462 if (!(g_dwFlags & AF_SERVER_INITIALIZED))
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);
469 g_dwFlags |= AF_DB_CONNECTION_LOST;
470 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, FALSE);
471 break;
472 case DBEVENT_CONNECTION_RESTORED:
473 PostEvent(EVENT_DB_CONNECTION_RESTORED, g_dwMgmtNode, NULL);
474 g_dwFlags &= ~AF_DB_CONNECTION_LOST;
475 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, TRUE);
476 break;
4d0c32f3 477 case DBEVENT_QUERY_FAILED:
5049e942 478 PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uu", pszArg1, pszArg2);
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 {
492 CSCPMessage msg;
493
494 msg.SetCode(CMD_ADM_MESSAGE);
495 msg.SetVariable(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
fdbee7f8
VK
518/**
519 * Server initialization
520 */
bc980b27 521BOOL NXCORE_EXPORTABLE Initialize()
5039dede
AK
522{
523 int i, iDBVersion;
967893bb 524 UINT32 dwAddr;
35f836fe 525 TCHAR szInfo[256];
5039dede 526
c59466d2
VK
527 g_serverStartTime = time(NULL);
528 srand((unsigned int)g_serverStartTime);
4f8998ca
VK
529
530 if (!(g_dwFlags & AF_USE_SYSLOG))
531 {
532 if (!nxlog_set_rotation_policy((int)g_dwLogRotationMode, (int)g_dwMaxLogSize, (int)g_dwLogHistorySize, g_szDailyLogFileSuffix))
533 if (!(g_dwFlags & AF_DAEMON))
534 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
535 }
9d381279
VK
536 if (!nxlog_open((g_dwFlags & AF_USE_SYSLOG) ? NETXMSD_SYSLOG_NAME : g_szLogFile,
537 ((g_dwFlags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) | ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
538 _T("LIBNXSRV.DLL"),
5039dede 539#ifdef _WIN32
9d381279 540 0, NULL))
5039dede 541#else
9d381279 542 g_dwNumMessages, g_szMessages))
5039dede 543#endif
9d381279
VK
544 {
545 _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
546 return FALSE;
547 }
f669df41 548 nxlog_set_console_writer(LogConsoleWriter);
5039dede
AK
549
550 // Set code page
551#ifndef _WIN32
552 if (SetDefaultCodepage(g_szCodePage))
553 {
f5797a09 554 DbgPrintf(1, _T("Code page set to %hs"), g_szCodePage);
5039dede
AK
555 }
556 else
557 {
f375019e 558 nxlog_write(MSG_CODEPAGE_ERROR, EVENTLOG_WARNING_TYPE, "m", g_szCodePage);
5039dede
AK
559 }
560#endif
561
73869331
VK
562 // Set process affinity mask
563 if (g_processAffinityMask != DEFAULT_AFFINITY_MASK)
564 {
565#ifdef _WIN32
566 if (SetProcessAffinityMask(GetCurrentProcess(), g_processAffinityMask))
567 DbgPrintf(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask);
568#else
569 nxlog_write(MSG_SET_PROCESS_AFFINITY_NOT_SUPPORTED, EVENTLOG_WARNING_TYPE, NULL);
570#endif
571 }
572
5039dede
AK
573#ifdef _WIN32
574 WSADATA wsaData;
1ddf3f0c
VK
575 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
576 if (wrc != 0)
577 {
578 nxlog_write(MSG_WSASTARTUP_FAILED, EVENTLOG_ERROR_TYPE, "e", wrc);
579 return FALSE;
580 }
5039dede
AK
581#endif
582
583 InitLocalNetInfo();
584
585 // Create queue for delayed SQL queries
73869331 586 g_pLazyRequestQueue = new Queue(256, 64);
c9a9601c 587 g_pIDataInsertQueue = new Queue(1024, 1024);
5039dede
AK
588
589 // Initialize database driver and connect to database
9d88cdc9 590 DBSetDebugPrintCallback(DbgPrintf2);
b8c1ec69
VK
591 if (!DBInit(MSG_OTHER, (g_dwFlags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0))
592 return FALSE;
ed950274 593 g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (g_debugLevel >= 9), DBEventHandler, NULL);
b8c1ec69 594 if (g_dbDriver == NULL)
5039dede
AK
595 return FALSE;
596
597 // Connect to database
465b3f2d 598 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
5039dede
AK
599 for(i = 0; ; i++)
600 {
f3c30cf5 601 g_hCoreDB = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText);
5039dede
AK
602 if ((g_hCoreDB != NULL) || (i == 5))
603 break;
604 ThreadSleep(5);
605 }
606 if (g_hCoreDB == NULL)
607 {
465b3f2d 608 nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, "s", errorText);
5039dede
AK
609 return FALSE;
610 }
35f836fe 611 DbgPrintf(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer);
5039dede
AK
612
613 // Check database version
28f5b9a4 614 iDBVersion = DBGetSchemaVersion(g_hCoreDB);
5039dede
AK
615 if (iDBVersion != DB_FORMAT_VERSION)
616 {
617 nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", iDBVersion, DB_FORMAT_VERSION);
618 return FALSE;
619 }
620
35f836fe
VK
621 int baseSize = ConfigReadInt(_T("ConnectionPoolBaseSize"), 5);
622 int maxSize = ConfigReadInt(_T("ConnectionPoolMaxSize"), 20);
623 int cooldownTime = ConfigReadInt(_T("ConnectionPoolCooldownTime"), 300);
30d9c43c 624 DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, 0, g_hCoreDB);
e94b29f6 625 g_dwFlags |= AF_DB_CONNECTION_POOL_READY;
f727d089 626
5039dede 627 // Read database syntax
28f5b9a4 628 g_nDBSyntax = DBGetSyntax(g_hCoreDB);
5039dede
AK
629
630 // Read server ID
35f836fe 631 ConfigReadStr(_T("ServerID"), szInfo, 256, _T(""));
5039dede
AK
632 StrStrip(szInfo);
633 if (szInfo[0] != 0)
634 {
635 StrToBin(szInfo, (BYTE *)&g_qwServerId, sizeof(QWORD));
636 }
637 else
638 {
639 // Generate new ID
640 g_qwServerId = (((QWORD)time(NULL)) << 32) | rand();
641 BinToStr((BYTE *)&g_qwServerId, sizeof(QWORD), szInfo);
35f836fe 642 ConfigWriteStr(_T("ServerID"), szInfo, TRUE);
5039dede
AK
643 }
644
645 // Initialize locks
646retry_db_lock:
647 if (!InitLocks(&dwAddr, szInfo))
648 {
649 if (dwAddr == UNLOCKED) // Some SQL problems
650 {
651 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
652 }
653 else // Database already locked by another server instance
654 {
655 // Check for lock from crashed/terminated local process
656 if (dwAddr == GetLocalIpAddr())
657 {
967893bb 658 UINT32 dwPID;
5039dede 659
35f836fe 660 dwPID = ConfigReadULong(_T("DBLockPID"), 0);
5039dede
AK
661 if (!IsNetxmsdProcess(dwPID) || (dwPID == GetCurrentProcessId()))
662 {
663 UnlockDB();
664 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
665 goto retry_db_lock;
666 }
667 }
668 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "as", dwAddr, szInfo);
669 }
670 return FALSE;
671 }
672 g_dwFlags |= AF_DB_LOCKED;
673
674 // Load global configuration parameters
675 LoadGlobalConfig();
958a9397 676 CASReadSettings();
35f836fe 677 DbgPrintf(1, _T("Global configuration loaded"));
5039dede
AK
678
679 // Check data directory
680 if (!CheckDataDir())
681 return FALSE;
682
683 // Initialize cryptografy
684 if (!InitCryptografy())
685 {
686 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
687 return FALSE;
688 }
689
690 // Initialize certificate store and CA
691 InitCertificates();
692
5039dede
AK
693 // Create synchronization stuff
694 m_condShutdown = ConditionCreate(TRUE);
695
696 // Setup unique identifiers table
697 if (!InitIdTable())
698 return FALSE;
35f836fe 699 DbgPrintf(2, _T("ID table created"));
5039dede 700
24dc5346
VK
701 // Update status for unfinished jobs in job history
702 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)"));
703
5039dede
AK
704 // Load and compile scripts
705 LoadScripts();
706
f7e4c50e
VK
707 // Initialize watchdog
708 WatchdogInit();
709
53d2de79 710 // Load modules
890478d8
VK
711 if (!LoadNetXMSModules())
712 return FALSE; // Mandatory module not loaded
53d2de79 713
5039dede
AK
714 // Initialize mailer and SMS sender
715 InitMailer();
716 InitSMSSender();
717
718 // Load users from database
ab185583 719 InitUsers();
5039dede
AK
720 if (!LoadUsers())
721 {
722 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
723 return FALSE;
724 }
35f836fe 725 DbgPrintf(2, _T("User accounts loaded"));
5039dede
AK
726
727 // Initialize audit
728 InitAuditLog();
729
730 // Initialize objects infrastructure and load objects from database
9796ce45 731 LoadNetworkDeviceDrivers();
5039dede
AK
732 ObjectsInit();
733 if (!LoadObjects())
734 return FALSE;
35f836fe 735 DbgPrintf(1, _T("Objects loaded and initialized"));
5039dede
AK
736
737 // Initialize situations
738 if (!SituationsInit())
739 return FALSE;
35f836fe 740 DbgPrintf(1, _T("Situations loaded and initialized"));
5039dede
AK
741
742 // Initialize and load event actions
743 if (!InitActions())
744 {
745 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
746 return FALSE;
747 }
748
749 // Initialize event handling subsystem
750 if (!InitEventSubsystem())
751 return FALSE;
752
753 // Initialize alarms
1b94acbf 754 if (!g_alarmMgr.init())
5039dede
AK
755 return FALSE;
756
757 // Initialize data collection subsystem
758 if (!InitDataCollector())
759 return FALSE;
760
e05b1945 761 InitLogAccess();
d77baddd 762 FileUploadJob::init();
fdbee7f8 763 InitMappingTables();
e05b1945 764
5039dede
AK
765 // Check if management node object presented in database
766 CheckForMgmtNode();
767 if (g_dwMgmtNode == 0)
768 {
769 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
770 return FALSE;
771 }
772
773 // Start threads
774 ThreadCreate(WatchdogThread, 0, NULL);
775 ThreadCreate(NodePoller, 0, NULL);
3929b1ca 776 ThreadCreate(JobManagerThread, 0, NULL);
5039dede
AK
777 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
778 m_thHouseKeeper = ThreadCreateEx(HouseKeeper, 0, NULL);
779 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
780
781 // Start event processor
782 ThreadCreate(EventProcessor, 0, NULL);
783
784 // Start SNMP trapper
785 InitTraps();
35f836fe 786 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
5039dede
AK
787 ThreadCreate(SNMPTrapReceiver, 0, NULL);
788
789 // Start built-in syslog daemon
35f836fe 790 if (ConfigReadInt(_T("EnableSyslogDaemon"), 0))
5039dede
AK
791 m_thSyslogDaemon = ThreadCreateEx(SyslogDaemon, 0, NULL);
792
35f836fe 793 // Start database _T("lazy") write thread
5039dede
AK
794 StartDBWriter();
795
796 // Start local administartive interface listener if required
35f836fe 797 if (ConfigReadInt(_T("EnableAdminInterface"), 1))
5039dede
AK
798 ThreadCreate(LocalAdminListener, 0, NULL);
799
5039dede
AK
800 // Start beacon host poller
801 ThreadCreate(BeaconPoller, 0, NULL);
802
803 // Start inter-server communication listener
35f836fe 804 if (ConfigReadInt(_T("EnableISCListener"), 0))
5039dede
AK
805 ThreadCreate(ISCListener, 0, NULL);
806
d75003e1
AK
807 // Start reporting server connector
808 if (ConfigReadInt(_T("EnableReportingServer"), 0))
809 ThreadCreate(ReportingServerConnector, 0, NULL);
810
5039dede 811 // Allow clients to connect
36e44abe 812 InitClientListeners();
5039dede 813 ThreadCreate(ClientListener, 0, NULL);
36e44abe
VK
814#ifdef WITH_IPV6
815 ThreadCreate(ClientListenerIPv6, 0, NULL);
816#endif
5039dede 817
534e1b83
VK
818 // Allow mobile devices to connect
819 InitMobileDeviceListeners();
820 ThreadCreate(MobileDeviceListener, 0, NULL);
821#ifdef WITH_IPV6
822 ThreadCreate(MobileDeviceListenerIPv6, 0, NULL);
823#endif
824
86457857
AK
825 // Start uptime calculator for SLM
826 ThreadCreate(UptimeCalculator, 0, NULL);
827
712dd47d
VK
828 DbgPrintf(2, _T("Java VM: %s"), g_szJavaPath);
829 DbgPrintf(2, _T("Java LIBDIR: %s"), g_szJavaLibDir);
830 DbgPrintf(2, _T("LIBDIR: %s"), g_szLibDir);
831
1b42a673 832 // Call startup functions for the modules
967893bb 833 for(UINT32 i = 0; i < g_dwNumModules; i++)
53d2de79
VK
834 {
835 if (g_pModuleList[i].pfServerStarted != NULL)
836 g_pModuleList[i].pfServerStarted();
837 }
838
5039dede 839 g_dwFlags |= AF_SERVER_INITIALIZED;
35f836fe 840 DbgPrintf(1, _T("Server initialization completed"));
5039dede
AK
841 return TRUE;
842}
843
371d9c60
VK
844/**
845 * Server shutdown
846 */
035a4d73 847void NXCORE_EXPORTABLE Shutdown()
5039dede 848{
5039dede
AK
849 // Notify clients
850 NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0);
851
852 nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
853 g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag
854 ConditionSet(m_condShutdown);
855
856#ifndef _WIN32
857 if (IsStandalone() && (m_nShutdownReason != SHUTDOWN_BY_SIGNAL))
858 {
859 pthread_kill(m_signalHandlerThread, SIGUSR1); // Terminate signal handler
860 }
861#endif
862
496390c2 863 // Call shutdown functions for the modules
967893bb 864 for(UINT32 i = 0; i < g_dwNumModules; i++)
496390c2
VK
865 {
866 if (g_pModuleList[i].pfShutdown != NULL)
867 g_pModuleList[i].pfShutdown();
868 }
869
4f50e45c 870 // Stop event processor
5039dede 871 g_pEventQueue->Clear();
4f50e45c 872 g_pEventQueue->Put(INVALID_POINTER_VALUE);
5039dede
AK
873
874 ShutdownMailer();
875 ShutdownSMSSender();
876
877 ThreadSleep(1); // Give other threads a chance to terminate in a safe way
35f836fe 878 DbgPrintf(2, _T("All threads was notified, continue with shutdown"));
5039dede
AK
879
880 // Wait for critical threads
881 ThreadJoin(m_thHouseKeeper);
882 ThreadJoin(m_thPollManager);
883 ThreadJoin(m_thSyncer);
884 ThreadJoin(m_thSyslogDaemon);
885
886 SaveObjects(g_hCoreDB);
35f836fe 887 DbgPrintf(2, _T("All objects saved to database"));
5039dede 888 SaveUsers(g_hCoreDB);
35f836fe 889 DbgPrintf(2, _T("All users saved to database"));
5039dede 890 StopDBWriter();
35f836fe 891 DbgPrintf(1, _T("Database writer stopped"));
5039dede 892
ab185583
VK
893 CleanupUsers();
894
5039dede
AK
895 // Remove database lock
896 UnlockDB();
897
898 // Disconnect from database and unload driver
899 if (g_hCoreDB != NULL)
900 DBDisconnect(g_hCoreDB);
c20b2798
AK
901
902 DBConnectionPoolShutdown();
903
b8c1ec69 904 DBUnloadDriver(g_dbDriver);
35f836fe 905 DbgPrintf(1, _T("Database driver unloaded"));
5039dede
AK
906
907 CleanupActions();
908 ShutdownEventSubsystem();
35f836fe 909 DbgPrintf(1, _T("Event processing stopped"));
5039dede
AK
910
911 // Delete all objects
912 //for(i = 0; i < g_dwIdIndexSize; i++)
913 // delete g_pIndexById[i].pObject;
914
915 delete g_pScriptLibrary;
916
917 nxlog_close();
918
919 // Remove PID file
920#ifndef _WIN32
dda7c270 921 _tremove(g_szPIDFile);
5039dede
AK
922#endif
923
924 // Terminate process
925#ifdef _WIN32
926 if (!(g_dwFlags & AF_DAEMON))
927 ExitProcess(0);
928#else
929 exit(0);
930#endif
931}
932
371d9c60
VK
933/**
934 * Fast server shutdown - normally called only by Windows service on system shutdown
935 */
f669df41 936void NXCORE_EXPORTABLE FastShutdown()
5039dede
AK
937{
938 g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag
939 ConditionSet(m_condShutdown);
940
941 SaveObjects(g_hCoreDB);
35f836fe 942 DbgPrintf(2, _T("All objects saved to database"));
5039dede 943 SaveUsers(g_hCoreDB);
35f836fe 944 DbgPrintf(2, _T("All users saved to database"));
5039dede
AK
945
946 // Remove database lock first, because we have a chance to loose DB connection
947 UnlockDB();
948
949 // Stop database writers
950 StopDBWriter();
35f836fe 951 DbgPrintf(1, _T("Database writer stopped"));
5039dede
AK
952
953 nxlog_close();
954}
955
fdbee7f8
VK
956/**
957 * Compare given string to command template with abbreviation possibility
958 */
959static bool IsCommand(const TCHAR *pszTemplate, TCHAR *pszString, int iMinChars)
5039dede
AK
960{
961 int i;
962
963 // Convert given string to uppercase
35f836fe 964 _tcsupr(pszString);
5039dede
AK
965
966 for(i = 0; pszString[i] != 0; i++)
967 if (pszString[i] != pszTemplate[i])
fdbee7f8 968 return false;
5039dede 969 if (i < iMinChars)
fdbee7f8
VK
970 return false;
971 return true;
5039dede
AK
972}
973
fdbee7f8
VK
974/**
975 * Dump index
976 */
d5e19c61 977struct __dump_index_data
5039dede 978{
d5e19c61
VK
979 CONSOLE_CTX console;
980 bool indexByIP;
981};
5039dede 982
d5e19c61
VK
983static void DumpIndexCallback(NetObj *object, void *data)
984{
985 struct __dump_index_data *d = (struct __dump_index_data *)data;
986 if (d->indexByIP)
5039dede 987 {
d5e19c61
VK
988 TCHAR buffer[16];
989 ConsolePrintf(d->console, _T("%08X [%-15s] %p %s\n"), object->IpAddr(),
990 IpToStr(object->IpAddr(), buffer),
991 object, object->Name());
5039dede 992 }
d5e19c61
VK
993 else
994 {
995 ConsolePrintf(d->console, _T("%08X %p %s\n"), object->Id(), object, object->Name());
996 }
997}
5039dede 998
d5e19c61
VK
999static void DumpIndex(CONSOLE_CTX pCtx, ObjectIndex *index, bool indexByIp)
1000{
1001 struct __dump_index_data data;
1002 data.console = pCtx;
1003 data.indexByIP = indexByIp;
1004 index->forEach(DumpIndexCallback, &data);
5039dede
AK
1005}
1006
e323047c
VK
1007/**
1008 * Process command entered from command line in standalone mode
1009 * Return TRUE if command was _T("down")
1010 */
35f836fe 1011int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
5039dede 1012{
35f836fe 1013 const TCHAR *pArg;
48c0079d 1014 TCHAR szBuffer[256], *eptr;
5039dede
AK
1015 int nExitCode = CMD_EXIT_CONTINUE;
1016
1017 // Get command
1018 pArg = ExtractWord(pszCmdLine, szBuffer);
1019
35f836fe 1020 if (IsCommand(_T("DEBUG"), szBuffer, 2))
5039dede
AK
1021 {
1022 // Get argument
1023 pArg = ExtractWord(pArg, szBuffer);
48c0079d
VK
1024 int level = (int)_tcstol(szBuffer, &eptr, 0);
1025 if ((*eptr == 0) && (level >= 0) && (level <= 9))
5039dede 1026 {
967893bb 1027 g_debugLevel = (UINT32)level;
48c0079d 1028 ConsolePrintf(pCtx, (level == 0) ? _T("Debug mode turned off\n") : _T("Debug level set to %d\n"), level);
5039dede 1029 }
35f836fe 1030 else if (IsCommand(_T("OFF"), szBuffer, 2))
5039dede 1031 {
ed950274 1032 g_debugLevel = 0;
35f836fe 1033 ConsolePrintf(pCtx, _T("Debug mode turned off\n"));
5039dede
AK
1034 }
1035 else
1036 {
1037 if (szBuffer[0] == 0)
35f836fe 1038 ConsolePrintf(pCtx, _T("ERROR: Missing argument\n\n"));
5039dede 1039 else
48c0079d 1040 ConsolePrintf(pCtx, _T("ERROR: Invalid debug level\n\n"));
5039dede
AK
1041 }
1042 }
35f836fe 1043 else if (IsCommand(_T("DOWN"), szBuffer, 4))
5039dede 1044 {
35f836fe 1045 ConsolePrintf(pCtx, _T("Proceeding with server shutdown...\n"));
5039dede
AK
1046 nExitCode = CMD_EXIT_SHUTDOWN;
1047 }
35f836fe 1048 else if (IsCommand(_T("DUMP"), szBuffer, 4))
5039dede
AK
1049 {
1050 DumpProcess(pCtx);
1051 }
206e268e
VK
1052 else if (IsCommand(_T("GET"), szBuffer, 3))
1053 {
1054 pArg = ExtractWord(pArg, szBuffer);
1055 if (szBuffer[0] != 0)
1056 {
1057 TCHAR value[256];
1058 ConfigReadStr(szBuffer, value, 256, _T(""));
1059 ConsolePrintf(pCtx, _T("%s = %s\n"), szBuffer, value);
1060 }
1061 else
1062 {
1063 ConsolePrintf(pCtx, _T("Variable name missing\n"));
1064 }
1065 }
35f836fe 1066 else if (IsCommand(_T("RAISE"), szBuffer, 5))
5039dede
AK
1067 {
1068 // Get argument
1069 pArg = ExtractWord(pArg, szBuffer);
1070
35f836fe 1071 if (IsCommand(_T("ACCESS"), szBuffer, 6))
5039dede 1072 {
35f836fe 1073 ConsolePrintf(pCtx, _T("Raising exception...\n"));
5039dede
AK
1074 char *p = NULL;
1075 *p = 0;
1076 }
35f836fe 1077 else if (IsCommand(_T("BREAKPOINT"), szBuffer, 5))
5039dede
AK
1078 {
1079#ifdef _WIN32
35f836fe 1080 ConsolePrintf(pCtx, _T("Raising exception...\n"));
5039dede
AK
1081 RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
1082#else
35f836fe 1083 ConsolePrintf(pCtx, _T("ERROR: Not supported on current platform\n"));
5039dede
AK
1084#endif
1085 }
1086 else
1087 {
35f836fe 1088 ConsolePrintf(pCtx, _T("Invalid exception name; possible names are:\nACCESS BREAKPOINT\n"));
5039dede
AK
1089 }
1090 }
35f836fe 1091 else if (IsCommand(_T("EXIT"), szBuffer, 4))
5039dede 1092 {
f669df41 1093 if ((pCtx->hSocket != -1) || (pCtx->session != NULL))
5039dede 1094 {
35f836fe 1095 ConsolePrintf(pCtx, _T("Closing session...\n"));
5039dede
AK
1096 nExitCode = CMD_EXIT_CLOSE_SESSION;
1097 }
1098 else
1099 {
35f836fe 1100 ConsolePrintf(pCtx, _T("Cannot exit from local server console\n"));
5039dede
AK
1101 }
1102 }
206e268e
VK
1103 else if (IsCommand(_T("SET"), szBuffer, 3))
1104 {
1105 pArg = ExtractWord(pArg, szBuffer);
1106 if (szBuffer[0] != 0)
1107 {
1108 TCHAR value[256];
1109 pArg = ExtractWord(pArg, value);
1110 if (ConfigWriteStr(szBuffer, value, TRUE, TRUE, TRUE))
1111 {
1112 ConsolePrintf(pCtx, _T("Configuration variable %s updated\n"), szBuffer);
1113 }
1114 else
1115 {
1116 ConsolePrintf(pCtx, _T("ERROR: cannot update configuration variable %s\n"), szBuffer);
1117 }
1118 }
1119 else
1120 {
1121 ConsolePrintf(pCtx, _T("Variable name missing\n"));
1122 }
1123 }
35f836fe 1124 else if (IsCommand(_T("SHOW"), szBuffer, 2))
5039dede
AK
1125 {
1126 // Get argument
1127 pArg = ExtractWord(pArg, szBuffer);
1128
50d0de67
VK
1129 if (IsCommand(_T("COMPONENTS"), szBuffer, 1))
1130 {
1131 // Get argument
1132 pArg = ExtractWord(pArg, szBuffer);
967893bb 1133 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
50d0de67
VK
1134 if (dwNode != 0)
1135 {
1136 NetObj *pObject = FindObjectById(dwNode);
1137 if (pObject != NULL)
1138 {
1139 if (pObject->Type() == OBJECT_NODE)
1140 {
8836184f
VK
1141 ComponentTree *components = ((Node *)pObject)->getComponents();
1142 if (components != NULL)
50d0de67 1143 {
8836184f
VK
1144 components->print(pCtx);
1145 components->decRefCount();
50d0de67
VK
1146 }
1147 else
1148 {
1149 ConsolePrintf(pCtx, _T("ERROR: Node does not have physical component information\n\n"));
1150 }
1151 }
1152 else
1153 {
1154 ConsolePrintf(pCtx, _T("ERROR: Object is not a node\n\n"));
1155 }
1156 }
1157 else
1158 {
1159 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1160 }
1161 }
1162 else
1163 {
1164 ConsolePrintf(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1165 }
1166 }
4321449e
VK
1167 else if (IsCommand(_T("FDB"), szBuffer, 3))
1168 {
1169 // Get argument
1170 pArg = ExtractWord(pArg, szBuffer);
1171 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
1172 if (dwNode != 0)
1173 {
1174 NetObj *pObject = FindObjectById(dwNode);
1175 if (pObject != NULL)
1176 {
1177 if (pObject->Type() == OBJECT_NODE)
1178 {
1179 ForwardingDatabase *fdb = ((Node *)pObject)->getSwitchForwardingDatabase();
1180 if (fdb != NULL)
1181 {
1182 fdb->print(pCtx, (Node *)pObject);
1183 fdb->decRefCount();
1184 }
1185 else
1186 {
1187 ConsolePrintf(pCtx, _T("ERROR: Node does not have forwarding database information\n\n"));
1188 }
1189 }
1190 else
1191 {
1192 ConsolePrintf(pCtx, _T("ERROR: Object is not a node\n\n"));
1193 }
1194 }
1195 else
1196 {
1197 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1198 }
1199 }
1200 else
1201 {
1202 ConsolePrintf(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1203 }
1204 }
50d0de67 1205 else if (IsCommand(_T("FLAGS"), szBuffer, 1))
5039dede 1206 {
35f836fe 1207 ConsolePrintf(pCtx, _T("Flags: 0x%08X\n"), g_dwFlags);
5039dede
AK
1208 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DAEMON));
1209 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSLOG));
1210 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NETWORK_DISCOVERY));
1211 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ACTIVE_NETWORK_DISCOVERY));
1212 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_SQL_ERRORS));
1213 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DELETE_EMPTY_SUBNETS));
1214 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_SNMP_TRAPD));
1215 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_ZONING));
5039dede 1216 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYNC_NODE_NAMES_WITH_DNS));
cbc777ee 1217 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CHECK_TRUSTED_NODES));
549f48b3
VK
1218 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NXSL_CONTAINER_FUNCS));
1219 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_FQDN_FOR_NODE_NAMES));
1220 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE));
1221 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DEBUG_CONSOLE_DISABLED));
1222 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_OBJECT_TRANSACTIONS));
cbc777ee
VK
1223 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_WRITE_FULL_DUMP));
1224 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_NODE_NAMES));
5039dede 1225 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CATCH_EXCEPTIONS));
5039dede
AK
1226 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_INTERNAL_CA));
1227 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_LOCKED));
cbc777ee 1228 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_MULTIPLE_DB_CONN));
5039dede 1229 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_CONNECTION_LOST));
cbc777ee 1230 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_NO_NETWORK_CONNECTIVITY));
5039dede 1231 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_EVENT_STORM_DETECTED));
e02953a4 1232 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SNMP_TRAP_DISCOVERY));
5039dede
AK
1233 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SERVER_INITIALIZED));
1234 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SHUTDOWN));
35f836fe 1235 ConsolePrintf(pCtx, _T("\n"));
5039dede 1236 }
35f836fe 1237 else if (IsCommand(_T("INDEX"), szBuffer, 1))
5039dede
AK
1238 {
1239 // Get argument
1240 pArg = ExtractWord(pArg, szBuffer);
1241
35f836fe 1242 if (IsCommand(_T("CONDITION"), szBuffer, 1))
5039dede 1243 {
d5e19c61 1244 DumpIndex(pCtx, &g_idxConditionById, false);
5039dede 1245 }
35f836fe 1246 else if (IsCommand(_T("ID"), szBuffer, 2))
5039dede 1247 {
d5e19c61 1248 DumpIndex(pCtx, &g_idxObjectById, false);
5039dede 1249 }
35f836fe 1250 else if (IsCommand(_T("INTERFACE"), szBuffer, 2))
5039dede 1251 {
d5e19c61 1252 DumpIndex(pCtx, &g_idxInterfaceByAddr, true);
6aba3998 1253 }
16d6f798
VK
1254 else if (IsCommand(_T("NODEADDR"), szBuffer, 5))
1255 {
1256 DumpIndex(pCtx, &g_idxNodeByAddr, true);
1257 }
1258 else if (IsCommand(_T("NODEID"), szBuffer, 5))
6aba3998 1259 {
d5e19c61 1260 DumpIndex(pCtx, &g_idxNodeById, false);
5039dede 1261 }
35f836fe 1262 else if (IsCommand(_T("SUBNET"), szBuffer, 1))
5039dede 1263 {
d5e19c61 1264 DumpIndex(pCtx, &g_idxSubnetByAddr, true);
5039dede 1265 }
16d6f798
VK
1266 else if (IsCommand(_T("ZONE"), szBuffer, 1))
1267 {
1268 DumpIndex(pCtx, &g_idxZoneByGUID, true);
1269 }
5039dede
AK
1270 else
1271 {
1272 if (szBuffer[0] == 0)
35f836fe 1273 ConsolePrintf(pCtx, _T("ERROR: Missing index name\n")
16d6f798 1274 _T("Valid names are: CONDITION, ID, INTERFACE, NODEADDR, NODEID, SUBNET, ZONE\n\n"));
5039dede 1275 else
35f836fe 1276 ConsolePrintf(pCtx, _T("ERROR: Invalid index name\n\n"));
5039dede
AK
1277 }
1278 }
35f836fe 1279 else if (IsCommand(_T("MEMORY"), szBuffer, 2))
5039dede
AK
1280 {
1281#ifdef NETXMS_MEMORY_DEBUG
1282 PrintMemoryBlocks();
1283#else
35f836fe 1284 ConsolePrintf(pCtx, _T("ERROR: Server was compiled without memory debugger\n\n"));
5039dede
AK
1285#endif
1286 }
35f836fe 1287 else if (IsCommand(_T("OBJECTS"), szBuffer, 1))
5039dede
AK
1288 {
1289 DumpObjects(pCtx);
1290 }
35f836fe 1291 else if (IsCommand(_T("POLLERS"), szBuffer, 1))
5039dede
AK
1292 {
1293 ShowPollerState(pCtx);
1294 }
35f836fe 1295 else if (IsCommand(_T("QUEUES"), szBuffer, 1))
5039dede 1296 {
35f836fe
VK
1297 ShowQueueStats(pCtx, &g_conditionPollerQueue, _T("Condition poller"));
1298 ShowQueueStats(pCtx, &g_configPollQueue, _T("Configuration poller"));
040c45fa 1299 ShowQueueStats(pCtx, &g_topologyPollQueue, _T("Topology poller"));
35f836fe
VK
1300 ShowQueueStats(pCtx, g_pItemQueue, _T("Data collector"));
1301 ShowQueueStats(pCtx, g_pLazyRequestQueue, _T("Database writer"));
c9a9601c 1302 ShowQueueStats(pCtx, g_pIDataInsertQueue, _T("Database writer (IData)"));
35f836fe
VK
1303 ShowQueueStats(pCtx, g_pEventQueue, _T("Event processor"));
1304 ShowQueueStats(pCtx, &g_discoveryPollQueue, _T("Network discovery poller"));
1305 ShowQueueStats(pCtx, &g_nodePollerQueue, _T("Node poller"));
1306 ShowQueueStats(pCtx, &g_routePollQueue, _T("Routing table poller"));
1307 ShowQueueStats(pCtx, &g_statusPollQueue, _T("Status poller"));
1308 ConsolePrintf(pCtx, _T("\n"));
5039dede 1309 }
35f836fe 1310 else if (IsCommand(_T("ROUTING-TABLE"), szBuffer, 1))
5039dede 1311 {
967893bb 1312 UINT32 dwNode;
5039dede
AK
1313 NetObj *pObject;
1314
1315 pArg = ExtractWord(pArg, szBuffer);
35f836fe 1316 dwNode = _tcstoul(szBuffer, NULL, 0);
5039dede
AK
1317 if (dwNode != 0)
1318 {
1319 pObject = FindObjectById(dwNode);
1320 if (pObject != NULL)
1321 {
1322 if (pObject->Type() == OBJECT_NODE)
1323 {
1324 ROUTING_TABLE *pRT;
35f836fe 1325 TCHAR szIpAddr[16];
5039dede
AK
1326 int i;
1327
35f836fe 1328 ConsolePrintf(pCtx, _T("Routing table for node %s:\n\n"), pObject->Name());
58b3e451 1329 pRT = ((Node *)pObject)->getCachedRoutingTable();
5039dede
AK
1330 if (pRT != NULL)
1331 {
1332 for(i = 0; i < pRT->iNumEntries; i++)
1333 {
35f836fe
VK
1334 _sntprintf(szBuffer, 256, _T("%s/%d"), IpToStr(pRT->pRoutes[i].dwDestAddr, szIpAddr),
1335 BitsInMask(pRT->pRoutes[i].dwDestMask));
1336 ConsolePrintf(pCtx, _T("%-18s %-15s %-6d %d\n"), szBuffer,
1337 IpToStr(pRT->pRoutes[i].dwNextHop, szIpAddr),
1338 pRT->pRoutes[i].dwIfIndex, pRT->pRoutes[i].dwRouteType);
5039dede 1339 }
35f836fe 1340 ConsolePrintf(pCtx, _T("\n"));
5039dede
AK
1341 }
1342 else
1343 {
35f836fe 1344 ConsolePrintf(pCtx, _T("Node doesn't have cached routing table\n\n"));
5039dede
AK
1345 }
1346 }
1347 else
1348 {
35f836fe 1349 ConsolePrintf(pCtx, _T("ERROR: Object is not a node\n\n"));
5039dede
AK
1350 }
1351 }
1352 else
1353 {
35f836fe 1354 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
5039dede
AK
1355 }
1356 }
1357 else
1358 {
35f836fe 1359 ConsolePrintf(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
5039dede
AK
1360 }
1361 }
35f836fe 1362 else if (IsCommand(_T("SESSIONS"), szBuffer, 2))
5039dede 1363 {
534e1b83
VK
1364 ConsolePrintf(pCtx, _T("\x1b[1mCLIENT SESSIONS\x1b[0m\n============================================================\n"));
1365 DumpClientSessions(pCtx);
1366 ConsolePrintf(pCtx, _T("\n\x1b[1mMOBILE DEVICE SESSIONS\x1b[0m\n============================================================\n"));
1367 DumpMobileDeviceSessions(pCtx);
5039dede 1368 }
35f836fe 1369 else if (IsCommand(_T("STATS"), szBuffer, 2))
5039dede
AK
1370 {
1371 ShowServerStats(pCtx);
1372 }
35f836fe 1373 else if (IsCommand(_T("USERS"), szBuffer, 1))
5039dede
AK
1374 {
1375 DumpUsers(pCtx);
1376 }
b0ff1179
VK
1377 else if (IsCommand(_T("VLANS"), szBuffer, 1))
1378 {
967893bb 1379 UINT32 dwNode;
b0ff1179
VK
1380 NetObj *pObject;
1381
1382 pArg = ExtractWord(pArg, szBuffer);
1383 dwNode = _tcstoul(szBuffer, NULL, 0);
1384 if (dwNode != 0)
1385 {
1386 pObject = FindObjectById(dwNode);
1387 if (pObject != NULL)
1388 {
1389 if (pObject->Type() == OBJECT_NODE)
1390 {
1391 VlanList *vlans = ((Node *)pObject)->getVlans();
1392 if (vlans != NULL)
1393 {
1394 ConsolePrintf(pCtx, _T("\x1b[1mVLAN\x1b[0m | \x1b[1mName\x1b[0m | \x1b[1mPorts\x1b[0m\n")
1395 _T("-----+------------------+-----------------------------------------------------------------\n"));
1396 for(int i = 0; i < vlans->getSize(); i++)
1397 {
1398 VlanInfo *vlan = vlans->get(i);
1399 ConsolePrintf(pCtx, _T("%4d | %-16s |"), vlan->getVlanId(), vlan->getName());
1400 for(int j = 0; j < vlan->getNumPorts(); j++)
1401 ConsolePrintf(pCtx, _T(" %d.%d"), (int)(vlan->getPorts()[j] >> 16), (int)(vlan->getPorts()[j] & 0xFFFF));
1402 ConsolePrintf(pCtx, _T("\n"));
1403 }
1404 ConsolePrintf(pCtx, _T("\n"));
1405 vlans->decRefCount();
1406 }
1407 else
1408 {
1409 ConsolePrintf(pCtx, _T("\x1b[31mNode doesn't have VLAN information\x1b[0m\n\n"));
1410 }
1411 }
1412 else
1413 {
1414 ConsolePrintf(pCtx, _T("\x1b[31mERROR: Object is not a node\x1b[0m\n\n"));
1415 }
1416 }
1417 else
1418 {
1419 ConsolePrintf(pCtx, _T("\x1b[31mERROR: Object with ID %d does not exist\x1b[0m\n\n"), dwNode);
1420 }
1421 }
1422 else
1423 {
1424 ConsolePrintf(pCtx, _T("\x1b[31mERROR: Invalid or missing node ID\x1b[0m\n\n"));
1425 }
1426 }
35f836fe 1427 else if (IsCommand(_T("WATCHDOG"), szBuffer, 1))
5039dede
AK
1428 {
1429 WatchdogPrintStatus(pCtx);
35f836fe 1430 ConsolePrintf(pCtx, _T("\n"));
5039dede
AK
1431 }
1432 else
1433 {
1434 if (szBuffer[0] == 0)
35f836fe 1435 ConsolePrintf(pCtx, _T("ERROR: Missing subcommand\n\n"));
5039dede 1436 else
35f836fe 1437 ConsolePrintf(pCtx, _T("ERROR: Invalid SHOW subcommand\n\n"));
5039dede
AK
1438 }
1439 }
06a8857b
AK
1440 else if (IsCommand(_T("EXEC"), szBuffer, 3))
1441 {
1442 pArg = ExtractWord(pArg, szBuffer);
35104062 1443
e323047c
VK
1444 bool libraryLocked = true;
1445 g_pScriptLibrary->lock();
1446
35104062
VK
1447 NXSL_Program *compiledScript = g_pScriptLibrary->findScript(szBuffer);
1448 if (compiledScript == NULL)
06a8857b 1449 {
e323047c
VK
1450 g_pScriptLibrary->unlock();
1451 libraryLocked = false;
35104062 1452 char *script;
967893bb 1453 UINT32 fileSize;
35104062 1454 if ((script = (char *)LoadFile(szBuffer, &fileSize)) != NULL)
06a8857b 1455 {
35104062
VK
1456 const int errorMsgLen = 512;
1457 TCHAR errorMsg[errorMsgLen];
1458#ifdef UNICODE
1459 WCHAR *wscript = WideStringFromMBString(script);
1460 compiledScript = NXSLCompile(wscript, errorMsg, errorMsgLen);
1461 free(wscript);
1462#else
1463 compiledScript = NXSLCompile(script, errorMsg, errorMsgLen);
1464#endif
1465 free(script);
1466 if (compiledScript == NULL)
06a8857b 1467 {
35104062 1468 ConsolePrintf(pCtx, _T("ERROR: Script compilation error: %s\n\n"), errorMsg);
06a8857b
AK
1469 }
1470 }
1471 else
1472 {
35104062 1473 ConsolePrintf(pCtx, _T("ERROR: Script \"%s\" not found\n\n"), szBuffer);
06a8857b
AK
1474 }
1475 }
35104062
VK
1476
1477 if (compiledScript != NULL)
06a8857b 1478 {
35104062 1479 NXSL_ServerEnv *pEnv = new NXSL_ServerEnv;
2773ef30 1480 pEnv->setConsole(pCtx);
35104062
VK
1481
1482 NXSL_Value *argv[32];
1483 int argc = 0;
1484 while(argc < 32)
1485 {
1486 pArg = ExtractWord(pArg, szBuffer);
1487 if (szBuffer[0] == 0)
1488 break;
1489 argv[argc++] = new NXSL_Value(szBuffer);
1490 }
1491
1492 if (compiledScript->run(pEnv, argc, argv) == 0)
1493 {
1494 NXSL_Value *pValue = compiledScript->getResult();
1495 int retCode = pValue->getValueAsInt32();
1496 ConsolePrintf(pCtx, _T("INFO: Script finished with rc=%d\n\n"), retCode);
1497 }
1498 else
1499 {
1500 ConsolePrintf(pCtx, _T("ERROR: Script finished with error: %s\n\n"), compiledScript->getErrorText());
1501 }
06a8857b 1502 }
e323047c
VK
1503 if (libraryLocked)
1504 g_pScriptLibrary->unlock();
06a8857b 1505 }
35f836fe 1506 else if (IsCommand(_T("TRACE"), szBuffer, 1))
5039dede 1507 {
967893bb 1508 UINT32 dwNode1, dwNode2;
5039dede 1509 NetObj *pObject1, *pObject2;
6d069676 1510 NetworkPath *pTrace;
35f836fe 1511 TCHAR szNextHop[16];
5039dede
AK
1512 int i;
1513
1514 // Get arguments
1515 pArg = ExtractWord(pArg, szBuffer);
35f836fe 1516 dwNode1 = _tcstoul(szBuffer, NULL, 0);
5039dede
AK
1517
1518 pArg = ExtractWord(pArg, szBuffer);
35f836fe 1519 dwNode2 = _tcstoul(szBuffer, NULL, 0);
5039dede
AK
1520
1521 if ((dwNode1 != 0) && (dwNode2 != 0))
1522 {
1523 pObject1 = FindObjectById(dwNode1);
1524 if (pObject1 == NULL)
1525 {
35f836fe 1526 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode1);
5039dede
AK
1527 }
1528 else
1529 {
1530 pObject2 = FindObjectById(dwNode2);
1531 if (pObject2 == NULL)
1532 {
35f836fe 1533 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode2);
5039dede
AK
1534 }
1535 else
1536 {
6d069676 1537 if ((pObject1->Type() == OBJECT_NODE) && (pObject2->Type() == OBJECT_NODE))
5039dede
AK
1538 {
1539 pTrace = TraceRoute((Node *)pObject1, (Node *)pObject2);
1540 if (pTrace != NULL)
1541 {
6d069676
VK
1542 ConsolePrintf(pCtx, _T("Trace from %s to %s (%d hops, %s):\n"),
1543 pObject1->Name(), pObject2->Name(), pTrace->getHopCount(),
1544 pTrace->isComplete() ? _T("complete") : _T("incomplete"));
1545 for(i = 0; i < pTrace->getHopCount(); i++)
1546 {
1547 HOP_INFO *hop = pTrace->getHopInfo(i);
35f836fe 1548 ConsolePrintf(pCtx, _T("[%d] %s %s %s %d\n"),
6d069676
VK
1549 hop->object->Id(),
1550 hop->object->Name(),
1551 IpToStr(hop->nextHop, szNextHop),
1552 hop->isVpn ? _T("VPN Connector ID:") : _T("Interface Index: "),
1553 hop->ifIndex);
1554 }
1555 delete pTrace;
35f836fe 1556 ConsolePrintf(pCtx, _T("\n"));
5039dede
AK
1557 }
1558 else
1559 {
35f836fe 1560 ConsolePrintf(pCtx, _T("ERROR: Call to TraceRoute() failed\n\n"));
5039dede
AK
1561 }
1562 }
1563 else
1564 {
35f836fe 1565 ConsolePrintf(pCtx, _T("ERROR: Object is not a node\n\n"));
5039dede
AK
1566 }
1567 }
1568 }
1569 }
1570 else
1571 {
35f836fe 1572 ConsolePrintf(pCtx, _T("ERROR: Invalid or missing node id(s)\n\n"));
5039dede
AK
1573 }
1574 }
35f836fe 1575 else if (IsCommand(_T("HELP"), szBuffer, 2) || IsCommand(_T("?"), szBuffer, 1))
5039dede 1576 {
35f836fe 1577 ConsolePrintf(pCtx, _T("Valid commands are:\n")
48c0079d 1578 _T(" debug [<level>|off] - Set debug level (valid range is 0..9)\n")
48a3497b
VK
1579 _T(" down - Shutdown NetXMS server\n")
1580 _T(" exec <script> [<params>] - Executes NXSL script from script library\n")
35f836fe 1581 _T(" exit - Exit from remote session\n")
206e268e 1582 _T(" get <variable> - Get value of server configuration variable\n")
35f836fe
VK
1583 _T(" help - Display this help\n")
1584 _T(" raise <exception> - Raise exception\n")
206e268e 1585 _T(" set <variable> <value> - Set value of server configuration variable\n")
50d0de67 1586 _T(" show components <node> - Show physical components of given node\n")
48a3497b 1587 _T(" show fdb <node> - Show forwarding database for node\n")
35f836fe
VK
1588 _T(" show flags - Show internal server flags\n")
1589 _T(" show index <index> - Show internal index\n")
35f836fe
VK
1590 _T(" show objects - Dump network objects to screen\n")
1591 _T(" show pollers - Show poller threads state information\n")
1592 _T(" show queues - Show internal queues statistics\n")
1593 _T(" show routing-table <node> - Show cached routing table for node\n")
1594 _T(" show sessions - Show active client sessions\n")
1595 _T(" show stats - Show server statistics\n")
1596 _T(" show users - Show users\n")
b0ff1179 1597 _T(" show vlans <node> - Show cached VLAN information for node\n")
35f836fe
VK
1598 _T(" show watchdog - Display watchdog information\n")
1599 _T(" trace <node1> <node2> - Show network path trace between two nodes\n")
1600 _T("\nAlmost all commands can be abbreviated to 2 or 3 characters\n")
1601 _T("\n"));
5039dede
AK
1602 }
1603 else
1604 {
35f836fe 1605 ConsolePrintf(pCtx, _T("UNKNOWN COMMAND\n\n"));
5039dede
AK
1606 }
1607
1608 return nExitCode;
1609}
1610
fdbee7f8
VK
1611/**
1612 * Signal handler for UNIX platforms
1613 */
5039dede
AK
1614#ifndef _WIN32
1615
1616void SignalHandlerStub(int nSignal)
1617{
1618 // should be unused, but JIC...
1619 if (nSignal == SIGCHLD)
1620 {
1621 while (waitpid(-1, NULL, WNOHANG) > 0)
1622 ;
1623 }
1624}
1625
1626THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
1627{
1628 sigset_t signals;
1629 int nSignal;
1630 BOOL bCallShutdown = FALSE;
1631
1632 m_signalHandlerThread = pthread_self();
1633
1634 // default for SIGCHLD: ignore
1635 signal(SIGCHLD, &SignalHandlerStub);
1636
1637 sigemptyset(&signals);
1638 sigaddset(&signals, SIGTERM);
1639 sigaddset(&signals, SIGINT);
1640 sigaddset(&signals, SIGPIPE);
1641 sigaddset(&signals, SIGSEGV);
1642 sigaddset(&signals, SIGCHLD);
1643 sigaddset(&signals, SIGHUP);
1644 sigaddset(&signals, SIGUSR1);
1645 sigaddset(&signals, SIGUSR2);
1646
1647 sigprocmask(SIG_BLOCK, &signals, NULL);
1648
1649 while(1)
1650 {
1651 if (sigwait(&signals, &nSignal) == 0)
1652 {
1653 switch(nSignal)
1654 {
1655 case SIGTERM:
1656 case SIGINT:
1657 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
1658 if (IsStandalone())
1659 bCallShutdown = TRUE;
1660 ConditionSet(m_condShutdown);
1661 goto stop_handler;
1662 case SIGSEGV:
1663 abort();
1664 break;
1665 case SIGCHLD:
1666 while (waitpid(-1, NULL, WNOHANG) > 0)
1667 ;
1668 break;
1669 case SIGUSR1:
1670 if (g_dwFlags & AF_SHUTDOWN)
1671 goto stop_handler;
1672 break;
1673 default:
1674 break;
1675 }
1676 }
1677 else
1678 {
1679 ThreadSleepMs(100);
1680 }
1681 }
1682
1683stop_handler:
1684 sigprocmask(SIG_UNBLOCK, &signals, NULL);
1685 if (bCallShutdown)
1686 Shutdown();
1687 return THREAD_OK;
1688}
1689
1690#endif
1691
fdbee7f8
VK
1692/**
1693 * Common main()
1694 */
5039dede
AK
1695THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
1696{
1697 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
1698
3a82d5ae 1699 if (IsStandalone() && ((g_dwFlags & AF_DEBUG_CONSOLE_DISABLED) == 0))
5039dede
AK
1700 {
1701 char *ptr, szCommand[256];
1702 struct __console_ctx ctx;
35f836fe
VK
1703#ifdef UNICODE
1704 WCHAR wcCommand[256];
1705#endif
5039dede
AK
1706
1707 ctx.hSocket = -1;
d3a7cf4c 1708 ctx.socketMutex = INVALID_MUTEX_HANDLE;
5039dede 1709 ctx.pMsg = NULL;
200d662d 1710 ctx.session = NULL;
bfdba2df 1711 WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING _T(" Ready\n")
f669df41
VK
1712 _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n")
1713 _T("System Console\n\n"));
5039dede
AK
1714
1715#if USE_READLINE
1716 // Initialize readline library if we use it
0322eed7 1717 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
5039dede
AK
1718#endif
1719
1720 while(1)
1721 {
1722#if USE_READLINE
f669df41 1723 ptr = readline("\x1b[33mnetxmsd:\x1b[0m ");
5039dede 1724#else
f669df41 1725 WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m "));
5039dede
AK
1726 fflush(stdout);
1727 if (fgets(szCommand, 255, stdin) == NULL)
1728 break; // Error reading stdin
1729 ptr = strchr(szCommand, '\n');
1730 if (ptr != NULL)
1731 *ptr = 0;
1732 ptr = szCommand;
1733#endif
1734
1735 if (ptr != NULL)
1736 {
35f836fe
VK
1737#ifdef UNICODE
1738 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
1739 wcCommand[255] = 0;
1740 StrStrip(wcCommand);
1741 if (wcCommand[0] != 0)
1742 {
1743 if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN)
1744#else
5039dede
AK
1745 StrStrip(ptr);
1746 if (*ptr != 0)
1747 {
1748 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
35f836fe 1749#endif
5039dede
AK
1750 break;
1751#if USE_READLINE
1752 add_history(ptr);
1753#endif
1754 }
1755#if USE_READLINE
1756 free(ptr);
1757#endif
1758 }
1759 else
1760 {
f375019e 1761 _tprintf(_T("\n"));
5039dede
AK
1762 }
1763 }
1764
1765#if USE_READLINE
1766 free(ptr);
1767#endif
1768 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
1769 Shutdown();
1770 }
1771 else
1772 {
1773 ConditionWait(m_condShutdown, INFINITE);
1774 // On Win32, Shutdown() will be called by service control handler
1775#ifndef _WIN32
1776 Shutdown();
1777#endif
1778 }
1779 return THREAD_OK;
1780}
1781
fdbee7f8
VK
1782/**
1783 * Initiate server shutdown
1784 */
035a4d73 1785void InitiateShutdown()
5039dede
AK
1786{
1787#ifdef _WIN32
1788 Shutdown();
1789#else
1790 if (IsStandalone())
1791 {
1792 Shutdown();
1793 }
1794 else
1795 {
1796 pthread_kill(m_signalHandlerThread, SIGTERM);
1797 }
1798#endif
1799}
1800
fdbee7f8
VK
1801/**
1802 *DLL Entry point
1803 */
5039dede
AK
1804#ifdef _WIN32
1805
1806BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
1807{
1808 if (dwReason == DLL_PROCESS_ATTACH)
1809 DisableThreadLibraryCalls(hInstance);
1810 return TRUE;
1811}
1812
1813#endif