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