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