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