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