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