LogParser crash fixed when no event tag in rule configuration
[public/netxms.git] / src / server / core / main.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Copyright (C) 2003, 2004, 2005, 2006, 2007 NetXMS Team
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;
466 WSAStartup(0x0002, &wsaData);
467#endif
468
469 InitLocalNetInfo();
470
471 // Create queue for delayed SQL queries
73869331 472 g_pLazyRequestQueue = new Queue(256, 64);
5039dede
AK
473
474 // Initialize database driver and connect to database
9d88cdc9 475 DBSetDebugPrintCallback(DbgPrintf2);
b8c1ec69
VK
476 if (!DBInit(MSG_OTHER, (g_dwFlags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0))
477 return FALSE;
478 g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (g_nDebugLevel >= 9), DBEventHandler, NULL);
479 if (g_dbDriver == NULL)
5039dede
AK
480 return FALSE;
481
482 // Connect to database
483 for(i = 0; ; i++)
484 {
b8c1ec69 485 g_hCoreDB = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword);
5039dede
AK
486 if ((g_hCoreDB != NULL) || (i == 5))
487 break;
488 ThreadSleep(5);
489 }
490 if (g_hCoreDB == NULL)
491 {
492 nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, NULL);
493 return FALSE;
494 }
495 DbgPrintf(1, "Successfully connected to database %s@%s", g_szDbName, g_szDbServer);
496
497 // Check database version
28f5b9a4 498 iDBVersion = DBGetSchemaVersion(g_hCoreDB);
5039dede
AK
499 if (iDBVersion != DB_FORMAT_VERSION)
500 {
501 nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", iDBVersion, DB_FORMAT_VERSION);
502 return FALSE;
503 }
504
f727d089
VK
505 int baseSize = ConfigReadInt("ConnectionPoolBaseSize", 5);
506 int maxSize = ConfigReadInt("ConnectionPoolMaxSize", 20);
507 int cooldownTime = ConfigReadInt("ConnectionPoolCooldownTime", 300);
b8c1ec69 508 DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, baseSize, maxSize, cooldownTime);
f727d089 509
5039dede 510 // Read database syntax
28f5b9a4 511 g_nDBSyntax = DBGetSyntax(g_hCoreDB);
5039dede
AK
512
513 // Read server ID
514 ConfigReadStr("ServerID", szInfo, 256, "");
515 StrStrip(szInfo);
516 if (szInfo[0] != 0)
517 {
518 StrToBin(szInfo, (BYTE *)&g_qwServerId, sizeof(QWORD));
519 }
520 else
521 {
522 // Generate new ID
523 g_qwServerId = (((QWORD)time(NULL)) << 32) | rand();
524 BinToStr((BYTE *)&g_qwServerId, sizeof(QWORD), szInfo);
525 ConfigWriteStr("ServerID", szInfo, TRUE);
526 }
527
528 // Initialize locks
529retry_db_lock:
530 if (!InitLocks(&dwAddr, szInfo))
531 {
532 if (dwAddr == UNLOCKED) // Some SQL problems
533 {
534 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
535 }
536 else // Database already locked by another server instance
537 {
538 // Check for lock from crashed/terminated local process
539 if (dwAddr == GetLocalIpAddr())
540 {
541 DWORD dwPID;
542
543 dwPID = ConfigReadULong("DBLockPID", 0);
544 if (!IsNetxmsdProcess(dwPID) || (dwPID == GetCurrentProcessId()))
545 {
546 UnlockDB();
547 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
548 goto retry_db_lock;
549 }
550 }
551 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "as", dwAddr, szInfo);
552 }
553 return FALSE;
554 }
555 g_dwFlags |= AF_DB_LOCKED;
556
557 // Load global configuration parameters
558 LoadGlobalConfig();
559 DbgPrintf(1, "Global configuration loaded");
560
561 // Check data directory
562 if (!CheckDataDir())
563 return FALSE;
564
565 // Initialize cryptografy
566 if (!InitCryptografy())
567 {
568 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
569 return FALSE;
570 }
571
572 // Initialize certificate store and CA
573 InitCertificates();
574
575 // Initialize SNMP stuff
576 SnmpInit();
577
5039dede
AK
578 // Create synchronization stuff
579 m_condShutdown = ConditionCreate(TRUE);
580
581 // Setup unique identifiers table
582 if (!InitIdTable())
583 return FALSE;
584 DbgPrintf(2, "ID table created");
585
586 // Load and compile scripts
587 LoadScripts();
588
589 // Initialize mailer and SMS sender
590 InitMailer();
591 InitSMSSender();
592
593 // Load users from database
ab185583 594 InitUsers();
5039dede
AK
595 if (!LoadUsers())
596 {
597 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
598 return FALSE;
599 }
600 DbgPrintf(2, "User accounts loaded");
601
602 // Initialize audit
603 InitAuditLog();
604
605 // Initialize objects infrastructure and load objects from database
606 ObjectsInit();
607 if (!LoadObjects())
608 return FALSE;
609 LoadMaps();
610 DbgPrintf(1, "Objects loaded and initialized");
611
612 // Initialize situations
613 if (!SituationsInit())
614 return FALSE;
615 DbgPrintf(1, "Situations loaded and initialized");
616
617 // Initialize and load event actions
618 if (!InitActions())
619 {
620 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
621 return FALSE;
622 }
623
624 // Initialize event handling subsystem
625 if (!InitEventSubsystem())
626 return FALSE;
627
628 // Initialize alarms
629 if (!g_alarmMgr.Init())
630 return FALSE;
631
632 // Initialize data collection subsystem
633 if (!InitDataCollector())
634 return FALSE;
635
e05b1945
VK
636 InitLogAccess();
637
5039dede
AK
638 // Initialize watchdog
639 WatchdogInit();
640
641 // Check if management node object presented in database
642 CheckForMgmtNode();
643 if (g_dwMgmtNode == 0)
644 {
645 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
646 return FALSE;
647 }
648
649 // Start threads
650 ThreadCreate(WatchdogThread, 0, NULL);
651 ThreadCreate(NodePoller, 0, NULL);
3929b1ca 652 ThreadCreate(JobManagerThread, 0, NULL);
5039dede
AK
653 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
654 m_thHouseKeeper = ThreadCreateEx(HouseKeeper, 0, NULL);
655 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
656
657 // Start event processor
658 ThreadCreate(EventProcessor, 0, NULL);
659
660 // Start SNMP trapper
661 InitTraps();
662 if (ConfigReadInt("EnableSNMPTraps", 1))
663 ThreadCreate(SNMPTrapReceiver, 0, NULL);
664
665 // Start built-in syslog daemon
666 if (ConfigReadInt("EnableSyslogDaemon", 0))
667 m_thSyslogDaemon = ThreadCreateEx(SyslogDaemon, 0, NULL);
668
669 // Start database "lazy" write thread
670 StartDBWriter();
671
672 // Start local administartive interface listener if required
673 if (ConfigReadInt("EnableAdminInterface", 1))
674 ThreadCreate(LocalAdminListener, 0, NULL);
675
676 // Load modules
677 LoadNetXMSModules();
678
679 // Start beacon host poller
680 ThreadCreate(BeaconPoller, 0, NULL);
681
682 // Start inter-server communication listener
683 if (ConfigReadInt("EnableISCListener", 0))
684 ThreadCreate(ISCListener, 0, NULL);
685
686 // Allow clients to connect
687 ThreadCreate(ClientListener, 0, NULL);
688
689 g_dwFlags |= AF_SERVER_INITIALIZED;
690 DbgPrintf(1, "Server initialization completed");
691 return TRUE;
692}
693
694
695//
696// Server shutdown
697//
698
035a4d73 699void NXCORE_EXPORTABLE Shutdown()
5039dede
AK
700{
701 DWORD i, dwNumThreads;
702
703 // Notify clients
704 NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0);
705
706 nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
707 g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag
708 ConditionSet(m_condShutdown);
709
710#ifndef _WIN32
711 if (IsStandalone() && (m_nShutdownReason != SHUTDOWN_BY_SIGNAL))
712 {
713 pthread_kill(m_signalHandlerThread, SIGUSR1); // Terminate signal handler
714 }
715#endif
716
717 // Stop event processor(s)
718 g_pEventQueue->Clear();
719 dwNumThreads = ConfigReadInt("NumberOfEventProcessors", 1);
720 for(i = 0; i < dwNumThreads; i++)
721 g_pEventQueue->Put(INVALID_POINTER_VALUE);
722
723 ShutdownMailer();
724 ShutdownSMSSender();
725
726 ThreadSleep(1); // Give other threads a chance to terminate in a safe way
727 DbgPrintf(2, "All threads was notified, continue with shutdown");
728
729 // Wait for critical threads
730 ThreadJoin(m_thHouseKeeper);
731 ThreadJoin(m_thPollManager);
732 ThreadJoin(m_thSyncer);
733 ThreadJoin(m_thSyslogDaemon);
734
735 SaveObjects(g_hCoreDB);
736 DbgPrintf(2, "All objects saved to database");
737 SaveUsers(g_hCoreDB);
738 DbgPrintf(2, "All users saved to database");
739 StopDBWriter();
740 DbgPrintf(1, "Database writer stopped");
741
ab185583
VK
742 CleanupUsers();
743
5039dede
AK
744 // Remove database lock
745 UnlockDB();
746
747 // Disconnect from database and unload driver
748 if (g_hCoreDB != NULL)
749 DBDisconnect(g_hCoreDB);
c20b2798
AK
750
751 DBConnectionPoolShutdown();
752
b8c1ec69 753 DBUnloadDriver(g_dbDriver);
5039dede
AK
754 DbgPrintf(1, "Database driver unloaded");
755
756 CleanupActions();
757 ShutdownEventSubsystem();
758 DbgPrintf(1, "Event processing stopped");
759
760 // Delete all objects
761 //for(i = 0; i < g_dwIdIndexSize; i++)
762 // delete g_pIndexById[i].pObject;
763
764 delete g_pScriptLibrary;
765
766 nxlog_close();
767
768 // Remove PID file
769#ifndef _WIN32
770 remove(g_szPIDFile);
771#endif
772
773 // Terminate process
774#ifdef _WIN32
775 if (!(g_dwFlags & AF_DAEMON))
776 ExitProcess(0);
777#else
778 exit(0);
779#endif
780}
781
782
783//
784// Fast server shutdown - normally called only by Windows service on system shutdown
785//
786
787void NXCORE_EXPORTABLE FastShutdown(void)
788{
789 g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag
790 ConditionSet(m_condShutdown);
791
792 SaveObjects(g_hCoreDB);
793 DbgPrintf(2, "All objects saved to database");
794 SaveUsers(g_hCoreDB);
795 DbgPrintf(2, "All users saved to database");
796
797 // Remove database lock first, because we have a chance to loose DB connection
798 UnlockDB();
799
800 // Stop database writers
801 StopDBWriter();
802 DbgPrintf(1, "Database writer stopped");
803
804 nxlog_close();
805}
806
807
808//
809// Compare given string to command template with abbreviation possibility
810//
811
812static BOOL IsCommand(const char *pszTemplate, char *pszString, int iMinChars)
813{
814 int i;
815
816 // Convert given string to uppercase
817 strupr(pszString);
818
819 for(i = 0; pszString[i] != 0; i++)
820 if (pszString[i] != pszTemplate[i])
821 return FALSE;
822 if (i < iMinChars)
823 return FALSE;
824 return TRUE;
825}
826
827
828//
829// Dump index
830//
831
832static void DumpIndex(CONSOLE_CTX pCtx, RWLOCK hLock, INDEX *pIndex, DWORD dwSize,
833 BOOL bIndexByIp)
834{
835 DWORD i;
836 char szIpAddr[16];
837
838 if (!RWLockReadLock(hLock, 5000))
839 {
840 ConsolePrintf(pCtx, "ERROR: unable to obtain index lock in 5 seconds\n");
841 return;
842 }
843
844 for(i = 0; i < dwSize; i++)
845 {
846 if (bIndexByIp)
847 {
848 ConsolePrintf(pCtx, "%08X [%-15s] %p %s\n", pIndex[i].dwKey,
849 IpToStr(pIndex[i].dwKey, szIpAddr),
850 pIndex[i].pObject, ((NetObj *)pIndex[i].pObject)->Name());
851 }
852 else
853 {
854 ConsolePrintf(pCtx, "%08X %p %s\n", pIndex[i].dwKey, pIndex[i].pObject,
855 ((NetObj *)pIndex[i].pObject)->Name());
856 }
857 }
858
859 RWLockUnlock(hLock);
860}
861
862
863//
864// Process command entered from command line in standalone mode
865// Return TRUE if command was "down"
866//
867
868int ProcessConsoleCommand(char *pszCmdLine, CONSOLE_CTX pCtx)
869{
870 char *pArg;
871 char szBuffer[256];
872 int nExitCode = CMD_EXIT_CONTINUE;
873
874 // Get command
875 pArg = ExtractWord(pszCmdLine, szBuffer);
876
877 if (IsCommand("DEBUG", szBuffer, 2))
878 {
879 // Get argument
880 pArg = ExtractWord(pArg, szBuffer);
881
882 if (IsCommand("ON", szBuffer, 2))
883 {
884 g_nDebugLevel = 8;
885 ConsolePrintf(pCtx, "Debug mode turned on\n");
886 }
887 else if (IsCommand("OFF", szBuffer, 2))
888 {
889 g_nDebugLevel = 0;
890 ConsolePrintf(pCtx, "Debug mode turned off\n");
891 }
892 else
893 {
894 if (szBuffer[0] == 0)
895 ConsolePrintf(pCtx, "ERROR: Missing argument\n\n");
896 else
897 ConsolePrintf(pCtx, "ERROR: Invalid DEBUG argument\n\n");
898 }
899 }
900 else if (IsCommand("DOWN", szBuffer, 4))
901 {
902 ConsolePrintf(pCtx, "Proceeding with server shutdown...\n");
903 nExitCode = CMD_EXIT_SHUTDOWN;
904 }
905 else if (IsCommand("DUMP", szBuffer, 4))
906 {
907 DumpProcess(pCtx);
908 }
909 else if (IsCommand("RAISE", szBuffer, 5))
910 {
911 // Get argument
912 pArg = ExtractWord(pArg, szBuffer);
913
914 if (IsCommand("ACCESS", szBuffer, 6))
915 {
916 ConsolePrintf(pCtx, "Raising exception...\n");
917 char *p = NULL;
918 *p = 0;
919 }
920 else if (IsCommand("BREAKPOINT", szBuffer, 5))
921 {
922#ifdef _WIN32
923 ConsolePrintf(pCtx, "Raising exception...\n");
924 RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
925#else
926 ConsolePrintf(pCtx, "ERROR: Not supported on current platform\n");
927#endif
928 }
929 else
930 {
931 ConsolePrintf(pCtx, "Invalid exception name; possible names are:\nACCESS BREAKPOINT\n");
932 }
933 }
934 else if (IsCommand("EXIT", szBuffer, 4))
935 {
936 if (pCtx->hSocket != -1)
937 {
938 ConsolePrintf(pCtx, "Closing session...\n");
939 nExitCode = CMD_EXIT_CLOSE_SESSION;
940 }
941 else
942 {
943 ConsolePrintf(pCtx, "Cannot exit from local server console\n");
944 }
945 }
946 else if (IsCommand("SHOW", szBuffer, 2))
947 {
948 // Get argument
949 pArg = ExtractWord(pArg, szBuffer);
950
951 if (IsCommand("FLAGS", szBuffer, 1))
952 {
953 ConsolePrintf(pCtx, "Flags: 0x%08X\n", g_dwFlags);
954 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DAEMON));
955 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSLOG));
956 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NETWORK_DISCOVERY));
957 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ACTIVE_NETWORK_DISCOVERY));
958 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_SQL_ERRORS));
959 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DELETE_EMPTY_SUBNETS));
960 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_SNMP_TRAPD));
961 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_ZONING));
5039dede 962 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYNC_NODE_NAMES_WITH_DNS));
cbc777ee
VK
963 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CHECK_TRUSTED_NODES));
964 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_WRITE_FULL_DUMP));
965 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_NODE_NAMES));
5039dede 966 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CATCH_EXCEPTIONS));
5039dede
AK
967 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_INTERNAL_CA));
968 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_LOCKED));
cbc777ee 969 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_MULTIPLE_DB_CONN));
5039dede 970 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_CONNECTION_LOST));
cbc777ee 971 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_NO_NETWORK_CONNECTIVITY));
5039dede
AK
972 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_EVENT_STORM_DETECTED));
973 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SERVER_INITIALIZED));
974 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SHUTDOWN));
975 ConsolePrintf(pCtx, "\n");
976 }
977 else if (IsCommand("INDEX", szBuffer, 1))
978 {
979 // Get argument
980 pArg = ExtractWord(pArg, szBuffer);
981
982 if (IsCommand("CONDITION", szBuffer, 1))
983 {
984 DumpIndex(pCtx, g_rwlockConditionIndex, g_pConditionIndex, g_dwConditionIndexSize, FALSE);
985 }
986 else if (IsCommand("ID", szBuffer, 2))
987 {
988 DumpIndex(pCtx, g_rwlockIdIndex, g_pIndexById, g_dwIdIndexSize, FALSE);
989 }
990 else if (IsCommand("INTERFACE", szBuffer, 2))
991 {
992 DumpIndex(pCtx, g_rwlockInterfaceIndex, g_pInterfaceIndexByAddr,
993 g_dwInterfaceAddrIndexSize, TRUE);
994 }
995 else if (IsCommand("NODE", szBuffer, 1))
996 {
997 DumpIndex(pCtx, g_rwlockNodeIndex, g_pNodeIndexByAddr,
998 g_dwNodeAddrIndexSize, TRUE);
999 }
1000 else if (IsCommand("SUBNET", szBuffer, 1))
1001 {
1002 DumpIndex(pCtx, g_rwlockSubnetIndex, g_pSubnetIndexByAddr,
1003 g_dwSubnetAddrIndexSize, TRUE);
1004 }
1005 else
1006 {
1007 if (szBuffer[0] == 0)
1008 ConsolePrintf(pCtx, "ERROR: Missing index name\n"
1009 "Valid names are: CONDITION, ID, INTERFACE, NODE, SUBNET\n\n");
1010 else
1011 ConsolePrintf(pCtx, "ERROR: Invalid index name\n\n");
1012 }
1013 }
1014 else if (IsCommand("MEMORY", szBuffer, 2))
1015 {
1016#ifdef NETXMS_MEMORY_DEBUG
1017 PrintMemoryBlocks();
1018#else
1019 ConsolePrintf(pCtx, "ERROR: Server was compiled without memory debugger\n\n");
1020#endif
1021 }
1022 else if (IsCommand("MUTEX", szBuffer, 2))
1023 {
1024 ConsolePrintf(pCtx, "Mutex status:\n");
1025 DbgTestRWLock(g_rwlockIdIndex, "g_hMutexIdIndex", pCtx);
1026 DbgTestRWLock(g_rwlockNodeIndex, "g_hMutexNodeIndex", pCtx);
1027 DbgTestRWLock(g_rwlockSubnetIndex, "g_hMutexSubnetIndex", pCtx);
1028 DbgTestRWLock(g_rwlockInterfaceIndex, "g_hMutexInterfaceIndex", pCtx);
1029 ConsolePrintf(pCtx, "\n");
1030 }
1031 else if (IsCommand("OBJECTS", szBuffer, 1))
1032 {
1033 DumpObjects(pCtx);
1034 }
1035 else if (IsCommand("POLLERS", szBuffer, 1))
1036 {
1037 ShowPollerState(pCtx);
1038 }
1039 else if (IsCommand("QUEUES", szBuffer, 1))
1040 {
1041 ShowQueueStats(pCtx, &g_conditionPollerQueue, "Condition poller");
1042 ShowQueueStats(pCtx, &g_configPollQueue, "Configuration poller");
1043 ShowQueueStats(pCtx, g_pItemQueue, "Data collector");
1044 ShowQueueStats(pCtx, g_pLazyRequestQueue, "Database writer");
1045 ShowQueueStats(pCtx, g_pEventQueue, "Event processor");
1046 ShowQueueStats(pCtx, &g_discoveryPollQueue, "Network discovery poller");
1047 ShowQueueStats(pCtx, &g_nodePollerQueue, "Node poller");
1048 ShowQueueStats(pCtx, &g_routePollQueue, "Routing table poller");
1049 ShowQueueStats(pCtx, &g_statusPollQueue, "Status poller");
1050 ConsolePrintf(pCtx, "\n");
1051 }
1052 else if (IsCommand("ROUTING-TABLE", szBuffer, 1))
1053 {
1054 DWORD dwNode;
1055 NetObj *pObject;
1056
1057 pArg = ExtractWord(pArg, szBuffer);
1058 dwNode = strtoul(szBuffer, NULL, 0);
1059 if (dwNode != 0)
1060 {
1061 pObject = FindObjectById(dwNode);
1062 if (pObject != NULL)
1063 {
1064 if (pObject->Type() == OBJECT_NODE)
1065 {
1066 ROUTING_TABLE *pRT;
1067 char szIpAddr[16];
1068 int i;
1069
1070 ConsolePrintf(pCtx, "Routing table for node %s:\n\n", pObject->Name());
58b3e451 1071 pRT = ((Node *)pObject)->getCachedRoutingTable();
5039dede
AK
1072 if (pRT != NULL)
1073 {
1074 for(i = 0; i < pRT->iNumEntries; i++)
1075 {
1076 sprintf(szBuffer, "%s/%d", IpToStr(pRT->pRoutes[i].dwDestAddr, szIpAddr),
1077 BitsInMask(pRT->pRoutes[i].dwDestMask));
1078 ConsolePrintf(pCtx, "%-18s %-15s %-6d %d\n", szBuffer,
1079 IpToStr(pRT->pRoutes[i].dwNextHop, szIpAddr),
1080 pRT->pRoutes[i].dwIfIndex, pRT->pRoutes[i].dwRouteType);
1081 }
1082 ConsolePrintf(pCtx, "\n");
1083 }
1084 else
1085 {
1086 ConsolePrintf(pCtx, "Node doesn't have cached routing table\n\n");
1087 }
1088 }
1089 else
1090 {
1091 ConsolePrintf(pCtx, "ERROR: Object is not a node\n\n");
1092 }
1093 }
1094 else
1095 {
1096 ConsolePrintf(pCtx, "ERROR: Object with ID %d does not exist\n\n", dwNode);
1097 }
1098 }
1099 else
1100 {
1101 ConsolePrintf(pCtx, "ERROR: Invalid or missing node ID\n\n");
1102 }
1103 }
1104 else if (IsCommand("SESSIONS", szBuffer, 2))
1105 {
1106 DumpSessions(pCtx);
1107 }
1108 else if (IsCommand("STATS", szBuffer, 2))
1109 {
1110 ShowServerStats(pCtx);
1111 }
1112 else if (IsCommand("USERS", szBuffer, 1))
1113 {
1114 DumpUsers(pCtx);
1115 }
1116 else if (IsCommand("WATCHDOG", szBuffer, 1))
1117 {
1118 WatchdogPrintStatus(pCtx);
1119 ConsolePrintf(pCtx, "\n");
1120 }
1121 else
1122 {
1123 if (szBuffer[0] == 0)
1124 ConsolePrintf(pCtx, "ERROR: Missing subcommand\n\n");
1125 else
1126 ConsolePrintf(pCtx, "ERROR: Invalid SHOW subcommand\n\n");
1127 }
1128 }
1129 else if (IsCommand("TRACE", szBuffer, 1))
1130 {
1131 DWORD dwNode1, dwNode2;
1132 NetObj *pObject1, *pObject2;
1133 NETWORK_PATH_TRACE *pTrace;
1134 char szNextHop[16];
1135 int i;
1136
1137 // Get arguments
1138 pArg = ExtractWord(pArg, szBuffer);
1139 dwNode1 = strtoul(szBuffer, NULL, 0);
1140
1141 pArg = ExtractWord(pArg, szBuffer);
1142 dwNode2 = strtoul(szBuffer, NULL, 0);
1143
1144 if ((dwNode1 != 0) && (dwNode2 != 0))
1145 {
1146 pObject1 = FindObjectById(dwNode1);
1147 if (pObject1 == NULL)
1148 {
1149 ConsolePrintf(pCtx, "ERROR: Object with ID %d does not exist\n\n", dwNode1);
1150 }
1151 else
1152 {
1153 pObject2 = FindObjectById(dwNode2);
1154 if (pObject2 == NULL)
1155 {
1156 ConsolePrintf(pCtx, "ERROR: Object with ID %d does not exist\n\n", dwNode2);
1157 }
1158 else
1159 {
1160 if ((pObject1->Type() == OBJECT_NODE) &&
1161 (pObject2->Type() == OBJECT_NODE))
1162 {
1163 pTrace = TraceRoute((Node *)pObject1, (Node *)pObject2);
1164 if (pTrace != NULL)
1165 {
1166 ConsolePrintf(pCtx, "Trace from %s to %s (%d hops):\n",
1167 pObject1->Name(), pObject2->Name(), pTrace->iNumHops);
1168 for(i = 0; i < pTrace->iNumHops; i++)
1169 ConsolePrintf(pCtx, "[%d] %s %s %s %d\n",
1170 pTrace->pHopList[i].pObject->Id(),
1171 pTrace->pHopList[i].pObject->Name(),
1172 IpToStr(pTrace->pHopList[i].dwNextHop, szNextHop),
1173 pTrace->pHopList[i].bIsVPN ? "VPN Connector ID:" : "Interface Index: ",
1174 pTrace->pHopList[i].dwIfIndex);
1175 DestroyTraceData(pTrace);
1176 ConsolePrintf(pCtx, "\n");
1177 }
1178 else
1179 {
1180 ConsolePrintf(pCtx, "ERROR: Call to TraceRoute() failed\n\n");
1181 }
1182 }
1183 else
1184 {
1185 ConsolePrintf(pCtx, "ERROR: Object is not a node\n\n");
1186 }
1187 }
1188 }
1189 }
1190 else
1191 {
1192 ConsolePrintf(pCtx, "ERROR: Invalid or missing node id(s)\n\n");
1193 }
1194 }
1195 else if (IsCommand("HELP", szBuffer, 2) || IsCommand("?", szBuffer, 1))
1196 {
1197 ConsolePrintf(pCtx, "Valid commands are:\n"
1198 " debug [on|off] - Turn debug mode on or off\n"
1199 " down - Down NetXMS server\n"
1200 " exit - Exit from remote session\n"
1201 " help - Display this help\n"
1202 " raise <exception> - Raise exception\n"
1203 " show flags - Show internal server flags\n"
1204 " show index <index> - Show internal index\n"
1205 " show mutex - Display mutex status\n"
1206 " show objects - Dump network objects to screen\n"
1207 " show pollers - Show poller threads state information\n"
1208 " show queues - Show internal queues statistics\n"
1209 " show routing-table <node> - Show cached routing table for node\n"
1210 " show sessions - Show active client sessions\n"
1211 " show stats - Show server statistics\n"
1212 " show users - Show users\n"
1213 " show watchdog - Display watchdog information\n"
1214 " trace <node1> <node2> - Show network path trace between two nodes\n"
1215 "\nAlmost all commands can be abbreviated to 2 or 3 characters\n"
1216 "\n");
1217 }
1218 else
1219 {
1220 ConsolePrintf(pCtx, "UNKNOWN COMMAND\n\n");
1221 }
1222
1223 return nExitCode;
1224}
1225
1226
1227//
1228// Signal handler for UNIX platforms
1229//
1230
1231#ifndef _WIN32
1232
1233void SignalHandlerStub(int nSignal)
1234{
1235 // should be unused, but JIC...
1236 if (nSignal == SIGCHLD)
1237 {
1238 while (waitpid(-1, NULL, WNOHANG) > 0)
1239 ;
1240 }
1241}
1242
1243THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
1244{
1245 sigset_t signals;
1246 int nSignal;
1247 BOOL bCallShutdown = FALSE;
1248
1249 m_signalHandlerThread = pthread_self();
1250
1251 // default for SIGCHLD: ignore
1252 signal(SIGCHLD, &SignalHandlerStub);
1253
1254 sigemptyset(&signals);
1255 sigaddset(&signals, SIGTERM);
1256 sigaddset(&signals, SIGINT);
1257 sigaddset(&signals, SIGPIPE);
1258 sigaddset(&signals, SIGSEGV);
1259 sigaddset(&signals, SIGCHLD);
1260 sigaddset(&signals, SIGHUP);
1261 sigaddset(&signals, SIGUSR1);
1262 sigaddset(&signals, SIGUSR2);
1263
1264 sigprocmask(SIG_BLOCK, &signals, NULL);
1265
1266 while(1)
1267 {
1268 if (sigwait(&signals, &nSignal) == 0)
1269 {
1270 switch(nSignal)
1271 {
1272 case SIGTERM:
1273 case SIGINT:
1274 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
1275 if (IsStandalone())
1276 bCallShutdown = TRUE;
1277 ConditionSet(m_condShutdown);
1278 goto stop_handler;
1279 case SIGSEGV:
1280 abort();
1281 break;
1282 case SIGCHLD:
1283 while (waitpid(-1, NULL, WNOHANG) > 0)
1284 ;
1285 break;
1286 case SIGUSR1:
1287 if (g_dwFlags & AF_SHUTDOWN)
1288 goto stop_handler;
1289 break;
1290 default:
1291 break;
1292 }
1293 }
1294 else
1295 {
1296 ThreadSleepMs(100);
1297 }
1298 }
1299
1300stop_handler:
1301 sigprocmask(SIG_UNBLOCK, &signals, NULL);
1302 if (bCallShutdown)
1303 Shutdown();
1304 return THREAD_OK;
1305}
1306
1307#endif
1308
1309
1310//
1311// Common main()
1312//
1313
1314THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
1315{
1316 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
1317
1318 if (IsStandalone())
1319 {
1320 char *ptr, szCommand[256];
1321 struct __console_ctx ctx;
1322
1323 ctx.hSocket = -1;
1324 ctx.pMsg = NULL;
1325 printf("\nNetXMS Server V" NETXMS_VERSION_STRING " Ready\n"
1326 "Enter \"help\" for command list or \"down\" for server shutdown\n"
1327 "System Console\n\n");
1328
1329#if USE_READLINE
1330 // Initialize readline library if we use it
0322eed7 1331 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
5039dede
AK
1332#endif
1333
1334 while(1)
1335 {
1336#if USE_READLINE
1337 ptr = readline("netxmsd: ");
1338#else
1339 printf("netxmsd: ");
1340 fflush(stdout);
1341 if (fgets(szCommand, 255, stdin) == NULL)
1342 break; // Error reading stdin
1343 ptr = strchr(szCommand, '\n');
1344 if (ptr != NULL)
1345 *ptr = 0;
1346 ptr = szCommand;
1347#endif
1348
1349 if (ptr != NULL)
1350 {
1351 StrStrip(ptr);
1352 if (*ptr != 0)
1353 {
1354 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
1355 break;
1356#if USE_READLINE
1357 add_history(ptr);
1358#endif
1359 }
1360#if USE_READLINE
1361 free(ptr);
1362#endif
1363 }
1364 else
1365 {
1366 printf("\n");
1367 }
1368 }
1369
1370#if USE_READLINE
1371 free(ptr);
1372#endif
1373 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
1374 Shutdown();
1375 }
1376 else
1377 {
1378 ConditionWait(m_condShutdown, INFINITE);
1379 // On Win32, Shutdown() will be called by service control handler
1380#ifndef _WIN32
1381 Shutdown();
1382#endif
1383 }
1384 return THREAD_OK;
1385}
1386
1387
1388//
1389// Initiate server shutdown
1390//
1391
035a4d73 1392void InitiateShutdown()
5039dede
AK
1393{
1394#ifdef _WIN32
1395 Shutdown();
1396#else
1397 if (IsStandalone())
1398 {
1399 Shutdown();
1400 }
1401 else
1402 {
1403 pthread_kill(m_signalHandlerThread, SIGTERM);
1404 }
1405#endif
1406}
1407
1408
1409//
1410// DLL Entry point
1411//
1412
1413#ifdef _WIN32
1414
1415BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
1416{
1417 if (dwReason == DLL_PROCESS_ATTACH)
1418 DisableThreadLibraryCalls(hInstance);
1419 return TRUE;
1420}
1421
1422#endif