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