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