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