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