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