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