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