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