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