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