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