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