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