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