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