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