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