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