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