fixed LLDP based topology discovery issues on some devices (mostly D-Link)
[public/netxms.git] / src / server / core / main.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Raden Solutions
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 #include <netxms_mt.h>
26 #include <hdlink.h>
27
28 #if !defined(_WIN32) && HAVE_READLINE_READLINE_H && HAVE_READLINE && !defined(UNICODE)
29 #include <readline/readline.h>
30 #include <readline/history.h>
31 #define USE_READLINE 1
32 #endif
33
34 #ifdef _WIN32
35 #include <errno.h>
36 #include <psapi.h>
37 #include <conio.h>
38 #define open _open
39 #define write _write
40 #define close _close
41 #else
42 #include <signal.h>
43 #include <sys/wait.h>
44 #endif
45
46 #ifdef WITH_ZMQ
47 #include "zeromq.h"
48 #endif
49
50 /**
51 * Format string to show value of global flag
52 */
53 #define SHOW_FLAG_VALUE(x) _T(" %-38s = %d\n"), _T(#x), (g_flags & x) ? 1 : 0
54
55 /**
56 * Messages generated by mc.pl (for UNIX version only)
57 */
58 #ifndef _WIN32
59 extern unsigned int g_dwNumMessages;
60 extern const TCHAR *g_szMessages[];
61 #endif
62
63 /**
64 * Shutdown reasons
65 */
66 #define SHUTDOWN_DEFAULT 0
67 #define SHUTDOWN_FROM_CONSOLE 1
68 #define SHUTDOWN_BY_SIGNAL 2
69
70 /**
71 * Externals
72 */
73 extern Queue g_nodePollerQueue;
74 extern Queue g_dataCollectionQueue;
75 extern Queue g_dciCacheLoaderQueue;
76 extern Queue g_syslogProcessingQueue;
77 extern Queue g_syslogWriteQueue;
78 extern ThreadPool *g_pollerThreadPool;
79 extern ThreadPool *g_schedulerThreadPool;
80
81 void InitClientListeners();
82 void InitMobileDeviceListeners();
83 void InitCertificates();
84 void InitUsers();
85 void CleanupUsers();
86 void LoadPerfDataStorageDrivers();
87 void ImportLocalConfiguration();
88
89 void ExecuteScheduledScript(const ScheduledTaskParameters *param);
90 void MaintenanceModeEnter(const ScheduledTaskParameters *params);
91 void MaintenanceModeLeave(const ScheduledTaskParameters *params);
92
93 #if XMPP_SUPPORTED
94 void StartXMPPConnector();
95 void StopXMPPConnector();
96 #endif
97
98 /**
99 * Syslog server control
100 */
101 void StartSyslogServer();
102 void StopSyslogServer();
103
104 /**
105 * Housekeeper control
106 */
107 void StartHouseKeeper();
108 void StopHouseKeeper();
109 void RunHouseKeeper();
110
111 /**
112 * Thread functions
113 */
114 THREAD_RESULT THREAD_CALL Syncer(void *);
115 THREAD_RESULT THREAD_CALL NodePoller(void *);
116 THREAD_RESULT THREAD_CALL PollManager(void *);
117 THREAD_RESULT THREAD_CALL EventProcessor(void *);
118 THREAD_RESULT THREAD_CALL WatchdogThread(void *);
119 THREAD_RESULT THREAD_CALL ClientListener(void *);
120 THREAD_RESULT THREAD_CALL ClientListenerIPv6(void *);
121 THREAD_RESULT THREAD_CALL MobileDeviceListener(void *);
122 THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *);
123 THREAD_RESULT THREAD_CALL ISCListener(void *);
124 THREAD_RESULT THREAD_CALL LocalAdminListener(void *);
125 THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *);
126 THREAD_RESULT THREAD_CALL BeaconPoller(void *);
127 THREAD_RESULT THREAD_CALL JobManagerThread(void *);
128 THREAD_RESULT THREAD_CALL UptimeCalculator(void *);
129 THREAD_RESULT THREAD_CALL ReportingServerConnector(void *);
130
131 /**
132 * Global variables
133 */
134 TCHAR NXCORE_EXPORTABLE g_szConfigFile[MAX_PATH] = _T("{search}");
135 TCHAR NXCORE_EXPORTABLE g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
136 UINT32 g_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
137 UINT32 g_dwMaxLogSize = 16384 * 1024;
138 UINT32 g_dwLogHistorySize = 4;
139 TCHAR g_szDailyLogFileSuffix[64] = _T("");
140 TCHAR NXCORE_EXPORTABLE g_szDumpDir[MAX_PATH] = DEFAULT_DUMP_DIR;
141 char g_szCodePage[256] = ICONV_DEFAULT_CODEPAGE;
142 TCHAR NXCORE_EXPORTABLE g_szListenAddress[MAX_PATH] = _T("*");
143 #ifndef _WIN32
144 TCHAR NXCORE_EXPORTABLE g_szPIDFile[MAX_PATH] = _T("/var/run/netxmsd.pid");
145 #endif
146 UINT32 g_dwDiscoveryPollingInterval;
147 UINT32 g_dwStatusPollingInterval;
148 UINT32 g_dwConfigurationPollingInterval;
149 UINT32 g_dwRoutingTableUpdateInterval;
150 UINT32 g_dwTopologyPollingInterval;
151 UINT32 g_dwConditionPollingInterval;
152 UINT32 g_instancePollingInterval;
153 UINT32 g_icmpPingSize;
154 UINT32 g_icmpPingTimeout = 1500; // ICMP ping timeout (milliseconds)
155 UINT32 g_auditFlags;
156 UINT32 g_slmPollingInterval;
157 UINT32 g_offlineDataRelevanceTime = 86400;
158 TCHAR NXCORE_EXPORTABLE g_netxmsdDataDir[MAX_PATH] = _T("");
159 TCHAR NXCORE_EXPORTABLE g_netxmsdLibDir[MAX_PATH] = _T("");
160 int g_dbSyntax = DB_SYNTAX_UNKNOWN;
161 UINT32 NXCORE_EXPORTABLE g_processAffinityMask = DEFAULT_AFFINITY_MASK;
162 UINT64 g_serverId = 0;
163 RSA *g_pServerKey = NULL;
164 time_t g_serverStartTime = 0;
165 UINT32 g_lockTimeout = 60000; // Default timeout for acquiring mutex
166 UINT32 g_agentCommandTimeout = 4000; // Default timeout for requests to agent
167 UINT32 g_thresholdRepeatInterval = 0; // Disabled by default
168 int g_requiredPolls = 1;
169 DB_DRIVER g_dbDriver = NULL;
170 ThreadPool *g_mainThreadPool = NULL;
171 INT16 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
172
173 /**
174 * Static data
175 */
176 static CONDITION m_condShutdown = INVALID_CONDITION_HANDLE;
177 static THREAD m_thPollManager = INVALID_THREAD_HANDLE;
178 static THREAD m_thSyncer = INVALID_THREAD_HANDLE;
179 static int m_nShutdownReason = SHUTDOWN_DEFAULT;
180
181 #ifndef _WIN32
182 static pthread_t m_signalHandlerThread;
183 #endif
184
185 /**
186 * Sleep for specified number of seconds or until system shutdown arrives
187 * Function will return TRUE if shutdown event occurs
188 *
189 * @param seconds seconds to sleep
190 * @return true if server is shutting down
191 */
192 bool NXCORE_EXPORTABLE SleepAndCheckForShutdown(int seconds)
193 {
194 return ConditionWait(m_condShutdown, seconds * 1000);
195 }
196
197 /**
198 * Disconnect from database (exportable function for startup module)
199 */
200 void NXCORE_EXPORTABLE ShutdownDB()
201 {
202 DBConnectionPoolShutdown();
203 DBUnloadDriver(g_dbDriver);
204 }
205
206 /**
207 * Check data directory for existence
208 */
209 static BOOL CheckDataDir()
210 {
211 TCHAR szBuffer[MAX_PATH];
212
213 if (_tchdir(g_netxmsdDataDir) == -1)
214 {
215 nxlog_write(MSG_INVALID_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", g_netxmsdDataDir);
216 return FALSE;
217 }
218
219 #ifdef _WIN32
220 #define MKDIR(name) _tmkdir(name)
221 #else
222 #define MKDIR(name) _tmkdir(name, 0700)
223 #endif
224
225 // Create directory for package files if it doesn't exist
226 _tcscpy(szBuffer, g_netxmsdDataDir);
227 _tcscat(szBuffer, DDIR_PACKAGES);
228 if (MKDIR(szBuffer) == -1)
229 if (errno != EEXIST)
230 {
231 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
232 return FALSE;
233 }
234
235 // Create directory for map background images if it doesn't exist
236 _tcscpy(szBuffer, g_netxmsdDataDir);
237 _tcscat(szBuffer, DDIR_BACKGROUNDS);
238 if (MKDIR(szBuffer) == -1)
239 if (errno != EEXIST)
240 {
241 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
242 return FALSE;
243 }
244
245 // Create directory for image library is if does't exists
246 _tcscpy(szBuffer, g_netxmsdDataDir);
247 _tcscat(szBuffer, DDIR_IMAGES);
248 if (MKDIR(szBuffer) == -1)
249 {
250 if (errno != EEXIST)
251 {
252 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
253 return FALSE;
254 }
255 }
256
257 // Create directory for file store if does't exists
258 _tcscpy(szBuffer, g_netxmsdDataDir);
259 _tcscat(szBuffer, DDIR_FILES);
260 if (MKDIR(szBuffer) == -1)
261 {
262 if (errno != EEXIST)
263 {
264 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
265 return FALSE;
266 }
267 }
268
269 #undef MKDIR
270
271 return TRUE;
272 }
273
274 /**
275 * Load global configuration parameters
276 */
277 static void LoadGlobalConfig()
278 {
279 g_dwDiscoveryPollingInterval = ConfigReadInt(_T("DiscoveryPollingInterval"), 900);
280 g_dwStatusPollingInterval = ConfigReadInt(_T("StatusPollingInterval"), 60);
281 g_dwConfigurationPollingInterval = ConfigReadInt(_T("ConfigurationPollingInterval"), 3600);
282 g_instancePollingInterval = ConfigReadInt(_T("InstancePollingInterval"), 600);
283 g_dwRoutingTableUpdateInterval = ConfigReadInt(_T("RoutingTableUpdateInterval"), 300);
284 g_dwTopologyPollingInterval = ConfigReadInt(_T("TopologyPollingInterval"), 1800);
285 g_dwConditionPollingInterval = ConfigReadInt(_T("ConditionPollingInterval"), 60);
286 g_slmPollingInterval = ConfigReadInt(_T("SlmPollingInterval"), 60);
287 DCObject::m_defaultPollingInterval = ConfigReadInt(_T("DefaultDCIPollingInterval"), 60);
288 DCObject::m_defaultRetentionTime = ConfigReadInt(_T("DefaultDCIRetentionTime"), 30);
289 g_defaultAgentCacheMode = (INT16)ConfigReadInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF);
290 if ((g_defaultAgentCacheMode != AGENT_CACHE_ON) && (g_defaultAgentCacheMode != AGENT_CACHE_OFF))
291 {
292 DbgPrintf(1, _T("Invalid value %d of DefaultAgentCacheMode: reset to %d (OFF)"), g_defaultAgentCacheMode, AGENT_CACHE_OFF);
293 ConfigWriteInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF, true, true, true);
294 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
295 }
296 if (ConfigReadInt(_T("DeleteEmptySubnets"), 1))
297 g_flags |= AF_DELETE_EMPTY_SUBNETS;
298 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
299 g_flags |= AF_ENABLE_SNMP_TRAPD;
300 if (ConfigReadInt(_T("ProcessTrapsFromUnmanagedNodes"), 0))
301 g_flags |= AF_TRAPS_FROM_UNMANAGED_NODES;
302 if (ConfigReadInt(_T("EnableZoning"), 0))
303 g_flags |= AF_ENABLE_ZONING;
304 if (ConfigReadInt(_T("EnableObjectTransactions"), 0))
305 g_flags |= AF_ENABLE_OBJECT_TRANSACTIONS;
306 if (ConfigReadInt(_T("RunNetworkDiscovery"), 0))
307 g_flags |= AF_ENABLE_NETWORK_DISCOVERY;
308 if (ConfigReadInt(_T("ActiveNetworkDiscovery"), 0))
309 g_flags |= AF_ACTIVE_NETWORK_DISCOVERY;
310 if (ConfigReadInt(_T("UseSNMPTrapsForDiscovery"), 0))
311 g_flags |= AF_SNMP_TRAP_DISCOVERY;
312 if (ConfigReadInt(_T("ResolveNodeNames"), 1))
313 g_flags |= AF_RESOLVE_NODE_NAMES;
314 if (ConfigReadInt(_T("SyncNodeNamesWithDNS"), 0))
315 g_flags |= AF_SYNC_NODE_NAMES_WITH_DNS;
316 if (ConfigReadInt(_T("CheckTrustedNodes"), 1))
317 g_flags |= AF_CHECK_TRUSTED_NODES;
318 if (ConfigReadInt(_T("EnableNXSLContainerFunctions"), 1))
319 g_flags |= AF_ENABLE_NXSL_CONTAINER_FUNCS;
320 if (ConfigReadInt(_T("UseFQDNForNodeNames"), 1))
321 g_flags |= AF_USE_FQDN_FOR_NODE_NAMES;
322 if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 1))
323 g_flags |= AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE;
324 if (ConfigReadInt(_T("ResolveDNSToIPOnStatusPoll"), 0))
325 g_flags |= AF_RESOLVE_IP_FOR_EACH_STATUS_POLL;
326 if (ConfigReadInt(_T("CaseInsensitiveLoginNames"), 0))
327 g_flags |= AF_CASE_INSENSITIVE_LOGINS;
328 if (ConfigReadInt(_T("TrapSourcesInAllZones"), 0))
329 g_flags |= AF_TRAP_SOURCES_IN_ALL_ZONES;
330
331 if (g_netxmsdDataDir[0] == 0)
332 {
333 GetNetXMSDirectory(nxDirData, g_netxmsdDataDir);
334 DbgPrintf(1, _T("Data directory set to %s"), g_netxmsdDataDir);
335 }
336 else
337 {
338 DbgPrintf(1, _T("Using data directory %s"), g_netxmsdDataDir);
339 }
340
341 g_icmpPingTimeout = ConfigReadInt(_T("IcmpPingTimeout"), 1500);
342 g_icmpPingSize = ConfigReadInt(_T("IcmpPingSize"), 46);
343 g_lockTimeout = ConfigReadInt(_T("LockTimeout"), 60000);
344 g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000);
345 g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
346 g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
347 g_offlineDataRelevanceTime = ConfigReadInt(_T("OfflineDataRelevanceTime"), 86400);
348
349 UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 1500);
350 SnmpSetDefaultTimeout(snmpTimeout);
351 }
352
353 /**
354 * Initialize cryptografic functions
355 */
356 static BOOL InitCryptografy()
357 {
358 #ifdef _WITH_ENCRYPTION
359 TCHAR szKeyFile[MAX_PATH];
360 BOOL bResult = FALSE;
361 int fd, iPolicy;
362 UINT32 dwLen;
363 BYTE *pBufPos, *pKeyBuffer, hash[SHA1_DIGEST_SIZE];
364
365 if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F)))
366 return FALSE;
367 nxlog_debug(4, _T("Supported ciphers: %s"), (const TCHAR *)NXCPGetSupportedCiphersAsText());
368
369 SSL_library_init();
370 SSL_load_error_strings();
371
372 _tcscpy(szKeyFile, g_netxmsdDataDir);
373 _tcscat(szKeyFile, DFILE_KEYS);
374 fd = _topen(szKeyFile, O_RDONLY | O_BINARY);
375 g_pServerKey = LoadRSAKeys(szKeyFile);
376 if (g_pServerKey == NULL)
377 {
378 nxlog_debug(1, _T("Generating RSA key pair..."));
379 g_pServerKey = RSA_generate_key(NETXMS_RSA_KEYLEN, 17, NULL, 0);
380 if (g_pServerKey != NULL)
381 {
382 fd = _topen(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600);
383 if (fd != -1)
384 {
385 dwLen = i2d_RSAPublicKey(g_pServerKey, NULL);
386 dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
387 pKeyBuffer = (BYTE *)malloc(dwLen);
388
389 pBufPos = pKeyBuffer;
390 i2d_RSAPublicKey(g_pServerKey, &pBufPos);
391 i2d_RSAPrivateKey(g_pServerKey, &pBufPos);
392 write(fd, &dwLen, sizeof(UINT32));
393 write(fd, pKeyBuffer, dwLen);
394
395 CalculateSHA1Hash(pKeyBuffer, dwLen, hash);
396 write(fd, hash, SHA1_DIGEST_SIZE);
397
398 close(fd);
399 free(pKeyBuffer);
400 bResult = TRUE;
401 }
402 else
403 {
404 nxlog_debug(0, _T("Failed to open %s for writing"), szKeyFile);
405 }
406 }
407 else
408 {
409 nxlog_debug(0, _T("Failed to generate RSA key"));
410 }
411 }
412 else
413 {
414 bResult = TRUE;
415 }
416
417 iPolicy = ConfigReadInt(_T("DefaultEncryptionPolicy"), 1);
418 if ((iPolicy < 0) || (iPolicy > 3))
419 iPolicy = 1;
420 SetAgentDEP(iPolicy);
421
422 return bResult;
423 #else
424 return TRUE;
425 #endif
426 }
427
428 /**
429 * Check if process with given PID exists and is a NetXMS server process
430 */
431 static BOOL IsNetxmsdProcess(UINT32 dwPID)
432 {
433 #ifdef _WIN32
434 HANDLE hProcess;
435 TCHAR szExtModule[MAX_PATH], szIntModule[MAX_PATH];
436 BOOL bRet = FALSE;
437
438 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
439 if (hProcess != NULL)
440 {
441 if ((GetModuleBaseName(hProcess, NULL, szExtModule, MAX_PATH) > 0) &&
442 (GetModuleBaseName(GetCurrentProcess(), NULL, szIntModule, MAX_PATH) > 0))
443 {
444 bRet = !_tcsicmp(szExtModule, szIntModule);
445 }
446 else
447 {
448 // Cannot read process name, for safety assume that it's a server process
449 bRet = TRUE;
450 }
451 CloseHandle(hProcess);
452 }
453 return bRet;
454 #else
455 return (kill((pid_t)dwPID, 0) != -1);
456 #endif
457 }
458
459 /**
460 * Database event handler
461 */
462 static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, bool connLost, void *userArg)
463 {
464 if (!(g_flags & AF_SERVER_INITIALIZED))
465 return; // Don't try to do anything if server is not ready yet
466
467 switch(dwEvent)
468 {
469 case DBEVENT_CONNECTION_LOST:
470 PostEvent(EVENT_DB_CONNECTION_LOST, g_dwMgmtNode, NULL);
471 g_flags |= AF_DB_CONNECTION_LOST;
472 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, FALSE);
473 break;
474 case DBEVENT_CONNECTION_RESTORED:
475 PostEvent(EVENT_DB_CONNECTION_RESTORED, g_dwMgmtNode, NULL);
476 g_flags &= ~AF_DB_CONNECTION_LOST;
477 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, TRUE);
478 break;
479 case DBEVENT_QUERY_FAILED:
480 PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uud", pszArg1, pszArg2, connLost ? 1 : 0);
481 break;
482 default:
483 break;
484 }
485 }
486
487 /**
488 * Send console message to session with open console
489 */
490 static void SendConsoleMessage(ClientSession *session, void *arg)
491 {
492 if (session->isConsoleOpen())
493 {
494 NXCPMessage msg;
495
496 msg.setCode(CMD_ADM_MESSAGE);
497 msg.setField(VID_MESSAGE, (TCHAR *)arg);
498 session->postMessage(&msg);
499 }
500 }
501
502 /**
503 * Console writer
504 */
505 static void LogConsoleWriter(const TCHAR *format, ...)
506 {
507 TCHAR buffer[8192];
508 va_list args;
509
510 va_start(args, format);
511 _vsntprintf(buffer, 8192, format, args);
512 buffer[8191] = 0;
513 va_end(args);
514
515 WriteToTerminal(buffer);
516
517 EnumerateClientSessions(SendConsoleMessage, buffer);
518 }
519
520 /**
521 * Oracle session init callback
522 */
523 static void OracleSessionInitCallback(DB_HANDLE hdb)
524 {
525 DBQuery(hdb, _T("ALTER SESSION SET DDL_LOCK_TIMEOUT = 60"));
526 }
527
528 /**
529 * Server initialization
530 */
531 BOOL NXCORE_EXPORTABLE Initialize()
532 {
533 int i, iDBVersion;
534 TCHAR szInfo[256];
535
536 g_serverStartTime = time(NULL);
537 srand((unsigned int)g_serverStartTime);
538
539 if (!(g_flags & AF_USE_SYSLOG))
540 {
541 if (!nxlog_set_rotation_policy((int)g_dwLogRotationMode, (int)g_dwMaxLogSize, (int)g_dwLogHistorySize, g_szDailyLogFileSuffix))
542 if (!(g_flags & AF_DAEMON))
543 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
544 }
545 if (!nxlog_open((g_flags & AF_USE_SYSLOG) ? NETXMSD_SYSLOG_NAME : g_szLogFile,
546 ((g_flags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
547 ((g_flags & AF_BACKGROUND_LOG_WRITER) ? NXLOG_BACKGROUND_WRITER : 0) |
548 ((g_flags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
549 _T("LIBNXSRV.DLL"),
550 #ifdef _WIN32
551 0, NULL, MSG_DEBUG))
552 #else
553 g_dwNumMessages, g_szMessages, MSG_DEBUG))
554 #endif
555 {
556 _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
557 return FALSE;
558 }
559 nxlog_set_console_writer(LogConsoleWriter);
560
561 if (g_netxmsdLibDir[0] == 0)
562 {
563 GetNetXMSDirectory(nxDirLib, g_netxmsdLibDir);
564 nxlog_debug(1, _T("LIB directory set to %s"), g_netxmsdLibDir);
565 }
566
567 // Set code page
568 #ifndef _WIN32
569 if (SetDefaultCodepage(g_szCodePage))
570 {
571 DbgPrintf(1, _T("Code page set to %hs"), g_szCodePage);
572 }
573 else
574 {
575 nxlog_write(MSG_CODEPAGE_ERROR, EVENTLOG_WARNING_TYPE, "m", g_szCodePage);
576 }
577 #endif
578
579 // Set process affinity mask
580 if (g_processAffinityMask != DEFAULT_AFFINITY_MASK)
581 {
582 #ifdef _WIN32
583 if (SetProcessAffinityMask(GetCurrentProcess(), g_processAffinityMask))
584 nxlog_debug(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask);
585 #else
586 nxlog_write(MSG_SET_PROCESS_AFFINITY_NOT_SUPPORTED, EVENTLOG_WARNING_TYPE, NULL);
587 #endif
588 }
589
590 #ifdef _WIN32
591 WSADATA wsaData;
592 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
593 if (wrc != 0)
594 {
595 nxlog_write(MSG_WSASTARTUP_FAILED, EVENTLOG_ERROR_TYPE, "e", wrc);
596 return FALSE;
597 }
598 #endif
599
600 InitLocalNetInfo();
601 SnmpSetMessageIds(MSG_OID_PARSE_ERROR, MSG_SNMP_UNKNOWN_TYPE, MSG_SNMP_GET_ERROR);
602
603 // Create queue for delayed SQL queries
604 g_dbWriterQueue = new Queue(256, 64);
605 g_dciDataWriterQueue = new Queue(1024, 1024);
606 g_dciRawDataWriterQueue = new Queue(1024, 1024);
607
608 // Initialize database driver and connect to database
609 if (!DBInit(MSG_OTHER, (g_flags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0))
610 return FALSE;
611 g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (nxlog_get_debug_level() >= 9), DBEventHandler, NULL);
612 if (g_dbDriver == NULL)
613 return FALSE;
614
615 // Connect to database
616 DB_HANDLE hdbBootstrap = NULL;
617 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
618 for(i = 0; ; i++)
619 {
620 hdbBootstrap = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText);
621 if ((hdbBootstrap != NULL) || (i == 5))
622 break;
623 ThreadSleep(5);
624 }
625 if (hdbBootstrap == NULL)
626 {
627 nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, "s", errorText);
628 return FALSE;
629 }
630 nxlog_debug(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer);
631
632 // Check database version
633 iDBVersion = DBGetSchemaVersion(hdbBootstrap);
634 if (iDBVersion != DB_FORMAT_VERSION)
635 {
636 nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", iDBVersion, DB_FORMAT_VERSION);
637 DBDisconnect(hdbBootstrap);
638 return FALSE;
639 }
640
641 // Read database syntax
642 g_dbSyntax = DBGetSyntax(hdbBootstrap);
643 if (g_dbSyntax == DB_SYNTAX_ORACLE)
644 {
645 DBSetSessionInitCallback(OracleSessionInitCallback);
646 }
647
648 int baseSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolBaseSize"), 10);
649 int maxSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxSize"), 30);
650 int cooldownTime = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolCooldownTime"), 300);
651 int ttl = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxLifetime"), 14400);
652
653 DBDisconnect(hdbBootstrap);
654
655 if (!DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, ttl))
656 {
657 nxlog_write(MSG_DBCONNPOOL_INIT_FAILED, EVENTLOG_ERROR_TYPE, NULL);
658 return FALSE;
659 }
660
661 UINT32 lrt = ConfigReadULong(_T("LongRunningQueryThreshold"), 0);
662 if (lrt != 0)
663 DBSetLongRunningThreshold(lrt);
664
665 // Read server ID
666 MetaDataReadStr(_T("ServerID"), szInfo, 256, _T(""));
667 StrStrip(szInfo);
668 if (szInfo[0] != 0)
669 {
670 g_serverId = _tcstoull(szInfo, NULL, 16);
671 }
672 else
673 {
674 // Generate new ID
675 g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF);
676 _sntprintf(szInfo, 256, UINT64X_FMT(_T("016")), g_serverId);
677 MetaDataWriteStr(_T("ServerID"), szInfo);
678 }
679 nxlog_debug(1, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
680
681 // Initialize locks
682 retry_db_lock:
683 InetAddress addr;
684 if (!InitLocks(&addr, szInfo))
685 {
686 if (!addr.isValid()) // Some SQL problems
687 {
688 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
689 }
690 else // Database already locked by another server instance
691 {
692 // Check for lock from crashed/terminated local process
693 if (GetLocalIpAddr().equals(addr))
694 {
695 UINT32 dwPID;
696
697 dwPID = ConfigReadULong(_T("DBLockPID"), 0);
698 if (!IsNetxmsdProcess(dwPID) || (dwPID == GetCurrentProcessId()))
699 {
700 UnlockDB();
701 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
702 goto retry_db_lock;
703 }
704 }
705 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "As", &addr, szInfo);
706 }
707 return FALSE;
708 }
709 g_flags |= AF_DB_LOCKED;
710
711 // Load global configuration parameters
712 LoadGlobalConfig();
713 CASReadSettings();
714 nxlog_debug(1, _T("Global configuration loaded"));
715
716 // Check data directory
717 if (!CheckDataDir())
718 return FALSE;
719
720 // Initialize cryptografy
721 if (!InitCryptografy())
722 {
723 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
724 return FALSE;
725 }
726
727 // Initialize certificate store and CA
728 InitCertificates();
729
730 // Create synchronization stuff
731 m_condShutdown = ConditionCreate(TRUE);
732
733 // Create thread pools
734 nxlog_debug(2, _T("Creating thread pools"));
735 g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN"));
736 g_agentConnectionThreadPool = ThreadPoolCreate(4, 256, _T("AGENT"));
737
738 // Setup unique identifiers table
739 if (!InitIdTable())
740 return FALSE;
741 nxlog_debug(2, _T("ID table created"));
742
743 // Update status for unfinished jobs in job history
744 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
745 DBQuery(hdb, _T("UPDATE job_history SET status=4,failure_message='Aborted due to server shutdown or crash' WHERE status NOT IN (3,4,5)"));
746 DBConnectionPoolReleaseConnection(hdb);
747
748 // Load and compile scripts
749 LoadScripts();
750
751 // Initialize watchdog
752 WatchdogInit();
753
754 // Load modules
755 if (!LoadNetXMSModules())
756 return FALSE; // Mandatory module not loaded
757
758 // Initialize mailer and SMS sender
759 InitMailer();
760 InitSMSSender();
761
762 // Load users from database
763 InitUsers();
764 if (!LoadUsers())
765 {
766 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
767 return FALSE;
768 }
769 nxlog_debug(2, _T("User accounts loaded"));
770
771 // Initialize audit
772 InitAuditLog();
773
774 // Initialize event handling subsystem
775 if (!InitEventSubsystem())
776 return FALSE;
777
778 // Initialize alarms
779 if (!InitAlarmManager())
780 return FALSE;
781
782 // Initialize objects infrastructure and load objects from database
783 LoadNetworkDeviceDrivers();
784 ObjectsInit();
785 if (!LoadObjects())
786 return FALSE;
787 nxlog_debug(1, _T("Objects loaded and initialized"));
788
789 // Initialize situations
790 if (!SituationsInit())
791 return FALSE;
792 nxlog_debug(1, _T("Situations loaded and initialized"));
793
794 // Initialize and load event actions
795 if (!InitActions())
796 {
797 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
798 return FALSE;
799 }
800
801 // Initialize helpdesk link
802 SetHDLinkEntryPoints(ResolveAlarmByHDRef, TerminateAlarmByHDRef);
803 LoadHelpDeskLink();
804
805 // Initialize data collection subsystem
806 LoadPerfDataStorageDrivers();
807 if (!InitDataCollector())
808 return FALSE;
809
810 InitLogAccess();
811 FileUploadJob::init();
812 InitMappingTables();
813
814 InitClientListeners();
815 if (ConfigReadInt(_T("ImportConfigurationOnStartup"), 1))
816 ImportLocalConfiguration();
817
818 // Check if management node object presented in database
819 CheckForMgmtNode();
820 if (g_dwMgmtNode == 0)
821 {
822 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
823 return FALSE;
824 }
825
826 // Start threads
827 ThreadCreate(WatchdogThread, 0, NULL);
828 ThreadCreate(NodePoller, 0, NULL);
829 ThreadCreate(JobManagerThread, 0, NULL);
830 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
831 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
832
833 StartHouseKeeper();
834
835 // Start event processor
836 ThreadCreate(EventProcessor, 0, NULL);
837
838 // Start SNMP trapper
839 InitTraps();
840 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
841 ThreadCreate(SNMPTrapReceiver, 0, NULL);
842
843 // Start built-in syslog daemon
844 if (ConfigReadInt(_T("EnableSyslogDaemon"), 0))
845 StartSyslogServer();
846
847 // Start database _T("lazy") write thread
848 StartDBWriter();
849
850 // Start local administartive interface listener if required
851 if (ConfigReadInt(_T("EnableAdminInterface"), 1))
852 ThreadCreate(LocalAdminListener, 0, NULL);
853
854 // Start beacon host poller
855 ThreadCreate(BeaconPoller, 0, NULL);
856
857 // Start inter-server communication listener
858 if (ConfigReadInt(_T("EnableISCListener"), 0))
859 ThreadCreate(ISCListener, 0, NULL);
860
861 // Start reporting server connector
862 if (ConfigReadInt(_T("EnableReportingServer"), 0))
863 ThreadCreate(ReportingServerConnector, 0, NULL);
864
865 //Start ldap synchronization
866 if (ConfigReadInt(_T("LdapSyncInterval"), 0))
867 ThreadCreate(SyncLDAPUsers, 0, NULL);
868
869 RegisterSchedulerTaskHandler(_T("Execute.Script"), ExecuteScheduledScript, SYSTEM_ACCESS_SCHEDULE_SCRIPT);
870 RegisterSchedulerTaskHandler(_T("Maintenance.Enter"), MaintenanceModeEnter, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
871 RegisterSchedulerTaskHandler(_T("Maintenance.Leave"), MaintenanceModeLeave, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
872 InitializeTaskScheduler();
873
874 // Allow clients to connect
875 ThreadCreate(ClientListener, 0, NULL);
876 #ifdef WITH_IPV6
877 ThreadCreate(ClientListenerIPv6, 0, NULL);
878 #endif
879
880 // Allow mobile devices to connect
881 InitMobileDeviceListeners();
882 ThreadCreate(MobileDeviceListener, 0, NULL);
883 #ifdef WITH_IPV6
884 ThreadCreate(MobileDeviceListenerIPv6, 0, NULL);
885 #endif
886
887 // Start uptime calculator for SLM
888 ThreadCreate(UptimeCalculator, 0, NULL);
889
890 nxlog_debug(2, _T("LIBDIR: %s"), g_netxmsdLibDir);
891
892 // Call startup functions for the modules
893 CALL_ALL_MODULES(pfServerStarted, ());
894
895 #if XMPP_SUPPORTED
896 if (ConfigReadInt(_T("EnableXMPPConnector"), 1))
897 {
898 StartXMPPConnector();
899 }
900 #endif
901
902 #if WITH_ZMQ
903 StartZMQConnector();
904 #endif
905
906 g_flags |= AF_SERVER_INITIALIZED;
907 nxlog_debug(1, _T("Server initialization completed"));
908 return TRUE;
909 }
910
911 /**
912 * Server shutdown
913 */
914 void NXCORE_EXPORTABLE Shutdown()
915 {
916 // Notify clients
917 NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0);
918
919 nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
920 g_flags |= AF_SHUTDOWN; // Set shutdown flag
921 ConditionSet(m_condShutdown);
922
923 CloseTaskScheduler();
924
925 // Stop DCI cache loading thread
926 g_dciCacheLoaderQueue.setShutdownMode();
927
928 #if XMPP_SUPPORTED
929 StopXMPPConnector();
930 #endif
931
932 #if WITH_ZMQ
933 StopZMQConnector();
934 #endif
935
936 g_pEventQueue->clear();
937 g_pEventQueue->put(INVALID_POINTER_VALUE);
938
939 ShutdownMailer();
940 ShutdownSMSSender();
941
942 ThreadSleep(1); // Give other threads a chance to terminate in a safe way
943 nxlog_debug(2, _T("All threads was notified, continue with shutdown"));
944
945 StopSyslogServer();
946 StopHouseKeeper();
947
948 // Wait for critical threads
949 ThreadJoin(m_thPollManager);
950 ThreadJoin(m_thSyncer);
951
952 // Call shutdown functions for the modules
953 // CALL_ALL_MODULES cannot be used here because it checks for shutdown flag
954 for(UINT32 i = 0; i < g_dwNumModules; i++)
955 {
956 if (g_pModuleList[i].pfShutdown != NULL)
957 g_pModuleList[i].pfShutdown();
958 }
959
960 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
961 SaveObjects(hdb);
962 nxlog_debug(2, _T("All objects saved to database"));
963 SaveUsers(hdb);
964 nxlog_debug(2, _T("All users saved to database"));
965 DBConnectionPoolReleaseConnection(hdb);
966
967 StopDBWriter();
968 nxlog_debug(1, _T("Database writer stopped"));
969
970 CleanupUsers();
971
972 // Remove database lock
973 UnlockDB();
974
975 DBConnectionPoolShutdown();
976 DBUnloadDriver(g_dbDriver);
977 nxlog_debug(1, _T("Database driver unloaded"));
978
979 CleanupActions();
980 ShutdownEventSubsystem();
981 ShutdownAlarmManager();
982 nxlog_debug(1, _T("Event processing stopped"));
983
984 ThreadPoolDestroy(g_agentConnectionThreadPool);
985 ThreadPoolDestroy(g_mainThreadPool);
986 MsgWaitQueue::shutdown();
987
988 delete g_pScriptLibrary;
989
990 nxlog_debug(1, _T("Server shutdown complete"));
991 nxlog_close();
992
993 // Remove PID file
994 #ifndef _WIN32
995 _tremove(g_szPIDFile);
996 #endif
997
998 // Terminate process
999 #ifdef _WIN32
1000 if (!(g_flags & AF_DAEMON))
1001 ExitProcess(0);
1002 #else
1003 exit(0);
1004 #endif
1005 }
1006
1007 /**
1008 * Fast server shutdown - normally called only by Windows service on system shutdown
1009 */
1010 void NXCORE_EXPORTABLE FastShutdown()
1011 {
1012 DbgPrintf(1, _T("Using fast shutdown procedure"));
1013
1014 g_flags |= AF_SHUTDOWN; // Set shutdown flag
1015 ConditionSet(m_condShutdown);
1016
1017 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1018 SaveObjects(hdb);
1019 DbgPrintf(2, _T("All objects saved to database"));
1020 SaveUsers(hdb);
1021 DbgPrintf(2, _T("All users saved to database"));
1022 DBConnectionPoolReleaseConnection(hdb);
1023
1024 // Remove database lock first, because we have a chance to lose DB connection
1025 UnlockDB();
1026
1027 // Stop database writers
1028 StopDBWriter();
1029 DbgPrintf(1, _T("Database writer stopped"));
1030
1031 DbgPrintf(1, _T("Server shutdown complete"));
1032 nxlog_close();
1033 }
1034
1035 /**
1036 * Compare given string to command template with abbreviation possibility
1037 */
1038 static bool IsCommand(const TCHAR *cmdTemplate, TCHAR *pszString, int iMinChars)
1039 {
1040 int i;
1041
1042 // Convert given string to uppercase
1043 _tcsupr(pszString);
1044
1045 for(i = 0; pszString[i] != 0; i++)
1046 if (pszString[i] != cmdTemplate[i])
1047 return false;
1048 if (i < iMinChars)
1049 return false;
1050 return true;
1051 }
1052
1053 /**
1054 * Dump index callback (by IP address)
1055 */
1056 static void DumpIndexCallbackByInetAddr(const InetAddress& addr, NetObj *object, void *data)
1057 {
1058 TCHAR buffer[64];
1059 ConsolePrintf((CONSOLE_CTX)data, _T("%-40s %p %s [%d]\n"), addr.toString(buffer), object, object->getName(), (int)object->getId());
1060 }
1061
1062 /**
1063 * Dump index (by IP address)
1064 */
1065 static void DumpIndex(CONSOLE_CTX pCtx, InetAddressIndex *index)
1066 {
1067 index->forEach(DumpIndexCallbackByInetAddr, pCtx);
1068 }
1069
1070 /**
1071 * Dump index callback (by ID)
1072 */
1073 static void DumpIndexCallbackById(NetObj *object, void *data)
1074 {
1075 ConsolePrintf((CONSOLE_CTX)data, _T("%08X %p %s\n"), object->getId(), object, object->getName());
1076 }
1077
1078 /**
1079 * Dump index (by ID)
1080 */
1081 static void DumpIndex(CONSOLE_CTX pCtx, ObjectIndex *index)
1082 {
1083 index->forEach(DumpIndexCallbackById, pCtx);
1084 }
1085
1086 /**
1087 * Process command entered from command line in standalone mode
1088 * Return TRUE if command was _T("down")
1089 */
1090 int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
1091 {
1092 const TCHAR *pArg;
1093 TCHAR szBuffer[256], *eptr;
1094 int nExitCode = CMD_EXIT_CONTINUE;
1095
1096 // Get command
1097 pArg = ExtractWord(pszCmdLine, szBuffer);
1098
1099 if (IsCommand(_T("AT"), szBuffer, 2))
1100 {
1101 pArg = ExtractWord(pArg, szBuffer);
1102 if (szBuffer[0] == _T('+'))
1103 {
1104 int offset = _tcstoul(&szBuffer[1], NULL, 0);
1105 AddOneTimeScheduledTask(_T("Execute.Script"), time(NULL) + offset, pArg, 0, 0, SYSTEM_ACCESS_FULL);//TODO: change to correct user
1106 }
1107 else
1108 {
1109 AddScheduledTask(_T("Execute.Script"), szBuffer, pArg, 0, 0, SYSTEM_ACCESS_FULL); //TODO: change to correct user
1110 }
1111 }
1112 if (IsCommand(_T("DEBUG"), szBuffer, 2))
1113 {
1114 // Get argument
1115 pArg = ExtractWord(pArg, szBuffer);
1116 int level = (int)_tcstol(szBuffer, &eptr, 0);
1117 if ((*eptr == 0) && (level >= 0) && (level <= 9))
1118 {
1119 nxlog_set_debug_level(level);
1120 ConsolePrintf(pCtx, (level == 0) ? _T("Debug mode turned off\n") : _T("Debug level set to %d\n"), level);
1121 }
1122 else if (IsCommand(_T("OFF"), szBuffer, 2))
1123 {
1124 nxlog_set_debug_level(0);
1125 ConsoleWrite(pCtx, _T("Debug mode turned off\n"));
1126 }
1127 else
1128 {
1129 if (szBuffer[0] == 0)
1130 ConsoleWrite(pCtx, _T("ERROR: Missing argument\n\n"));
1131 else
1132 ConsoleWrite(pCtx, _T("ERROR: Invalid debug level\n\n"));
1133 }
1134 }
1135 else if (IsCommand(_T("DOWN"), szBuffer, 4))
1136 {
1137 ConsoleWrite(pCtx, _T("Proceeding with server shutdown...\n"));
1138 nExitCode = CMD_EXIT_SHUTDOWN;
1139 }
1140 else if (IsCommand(_T("DUMP"), szBuffer, 4))
1141 {
1142 DumpProcess(pCtx);
1143 }
1144 else if (IsCommand(_T("GET"), szBuffer, 3))
1145 {
1146 pArg = ExtractWord(pArg, szBuffer);
1147 if (szBuffer[0] != 0)
1148 {
1149 TCHAR value[MAX_CONFIG_VALUE];
1150 ConfigReadStr(szBuffer, value, MAX_CONFIG_VALUE, _T(""));
1151 ConsolePrintf(pCtx, _T("%s = %s\n"), szBuffer, value);
1152 }
1153 else
1154 {
1155 ConsoleWrite(pCtx, _T("Variable name missing\n"));
1156 }
1157 }
1158 else if (IsCommand(_T("HKRUN"), szBuffer, 2))
1159 {
1160 ConsoleWrite(pCtx, _T("Starting housekeeper\n"));
1161 RunHouseKeeper();
1162 }
1163 else if (IsCommand(_T("LDAPSYNC"), szBuffer, 4))
1164 {
1165 LDAPConnection conn;
1166 conn.syncUsers();
1167 }
1168 else if (IsCommand(_T("LOG"), szBuffer, 3))
1169 {
1170 while(_istspace(*pArg))
1171 pArg++;
1172 if (*pArg != 0)
1173 DbgPrintf(0, _T("%s"), pArg);
1174 }
1175 else if (IsCommand(_T("LOGMARK"), szBuffer, 4))
1176 {
1177 DbgPrintf(0, _T("******* MARK *******"));
1178 }
1179 else if (IsCommand(_T("RAISE"), szBuffer, 5))
1180 {
1181 // Get argument
1182 pArg = ExtractWord(pArg, szBuffer);
1183
1184 if (IsCommand(_T("ACCESS"), szBuffer, 6))
1185 {
1186 ConsoleWrite(pCtx, _T("Raising exception...\n"));
1187 char *p = NULL;
1188 *p = 0;
1189 }
1190 else if (IsCommand(_T("BREAKPOINT"), szBuffer, 5))
1191 {
1192 #ifdef _WIN32
1193 ConsoleWrite(pCtx, _T("Raising exception...\n"));
1194 RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
1195 #else
1196 ConsoleWrite(pCtx, _T("ERROR: Not supported on current platform\n"));
1197 #endif
1198 }
1199 else
1200 {
1201 ConsoleWrite(pCtx, _T("Invalid exception name; possible names are:\nACCESS BREAKPOINT\n"));
1202 }
1203 }
1204 else if (IsCommand(_T("EXIT"), szBuffer, 4))
1205 {
1206 if ((pCtx->hSocket != -1) || (pCtx->session != NULL))
1207 {
1208 ConsoleWrite(pCtx, _T("Closing session...\n"));
1209 nExitCode = CMD_EXIT_CLOSE_SESSION;
1210 }
1211 else
1212 {
1213 ConsoleWrite(pCtx, _T("Cannot exit from local server console\n"));
1214 }
1215 }
1216 else if (IsCommand(_T("KILL"), szBuffer, 4))
1217 {
1218 pArg = ExtractWord(pArg, szBuffer);
1219 if (szBuffer[0] != 0)
1220 {
1221 int id = _tcstol(szBuffer, &eptr, 10);
1222 if (*eptr == 0)
1223 {
1224 if (KillClientSession(id))
1225 {
1226 ConsoleWrite(pCtx, _T("Session killed\n"));
1227 }
1228 else
1229 {
1230 ConsoleWrite(pCtx, _T("Invalid session ID\n"));
1231 }
1232 }
1233 else
1234 {
1235 ConsoleWrite(pCtx, _T("Invalid session ID\n"));
1236 }
1237 }
1238 else
1239 {
1240 ConsoleWrite(pCtx, _T("Session ID missing\n"));
1241 }
1242 }
1243 else if (IsCommand(_T("PING"), szBuffer, 4))
1244 {
1245 pArg = ExtractWord(pArg, szBuffer);
1246 if (szBuffer[0] != 0)
1247 {
1248 InetAddress addr = InetAddress::parse(szBuffer);
1249 if (addr.isValid())
1250 {
1251 UINT32 rtt;
1252 UINT32 rc = IcmpPing(addr, 1, 2000, &rtt, 128);
1253 switch(rc)
1254 {
1255 case ICMP_SUCCESS:
1256 ConsolePrintf(pCtx, _T("Success, RTT = %d ms\n"), (int)rtt);
1257 break;
1258 case ICMP_UNREACHEABLE:
1259 ConsolePrintf(pCtx, _T("Destination unreachable\n"));
1260 break;
1261 case ICMP_TIMEOUT:
1262 ConsolePrintf(pCtx, _T("Request timeout\n"));
1263 break;
1264 case ICMP_RAW_SOCK_FAILED:
1265 ConsolePrintf(pCtx, _T("Cannot create raw socket\n"));
1266 break;
1267 case ICMP_API_ERROR:
1268 ConsolePrintf(pCtx, _T("API error\n"));
1269 break;
1270 default:
1271 ConsolePrintf(pCtx, _T("ERROR %d\n"), (int)rc);
1272 break;
1273 }
1274 }
1275 else
1276 {
1277 ConsoleWrite(pCtx, _T("Invalid IP address\n"));
1278 }
1279 }
1280 else
1281 {
1282 ConsoleWrite(pCtx, _T("Usage: PING <address>\n"));
1283 }
1284 }
1285 else if (IsCommand(_T("POLL"), szBuffer, 2))
1286 {
1287 pArg = ExtractWord(pArg, szBuffer);
1288 if (szBuffer[0] != 0)
1289 {
1290 int pollType;
1291 if (IsCommand(_T("CONFIGURATION"), szBuffer, 1))
1292 {
1293 pollType = 1;
1294 }
1295 else if (IsCommand(_T("STATUS"), szBuffer, 1))
1296 {
1297 pollType = 2;
1298 }
1299 else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
1300 {
1301 pollType = 3;
1302 }
1303 else
1304 {
1305 pollType = 0;
1306 }
1307
1308 if (pollType > 0)
1309 {
1310 pArg = ExtractWord(pArg, szBuffer);
1311 UINT32 id = _tcstoul(szBuffer, NULL, 0);
1312 if (id != 0)
1313 {
1314 Node *node = (Node *)FindObjectById(id, OBJECT_NODE);
1315 if (node != NULL)
1316 {
1317 switch(pollType)
1318 {
1319 case 1:
1320 node->lockForConfigurationPoll();
1321 ThreadPoolExecute(g_pollerThreadPool, node, &Node::configurationPoll, RegisterPoller(POLLER_TYPE_CONFIGURATION, node));
1322 break;
1323 case 2:
1324 node->lockForStatusPoll();
1325 ThreadPoolExecute(g_pollerThreadPool, node, &Node::statusPoll, RegisterPoller(POLLER_TYPE_STATUS, node));
1326 break;
1327 case 3:
1328 node->lockForTopologyPoll();
1329 ThreadPoolExecute(g_pollerThreadPool, node, &Node::topologyPoll, RegisterPoller(POLLER_TYPE_TOPOLOGY, node));
1330 break;
1331 }
1332 }
1333 else
1334 {
1335 ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), id);
1336 }
1337 }
1338 else
1339 {
1340 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1341 }
1342 }
1343 else
1344 {
1345 ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|STATUS|TOPOLOGY] <node>\n"));
1346 }
1347 }
1348 else
1349 {
1350 ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|STATUS|TOPOLOGY] <node>\n"));
1351 }
1352 }
1353 else if (IsCommand(_T("SET"), szBuffer, 3))
1354 {
1355 pArg = ExtractWord(pArg, szBuffer);
1356 if (szBuffer[0] != 0)
1357 {
1358 TCHAR value[256];
1359 pArg = ExtractWord(pArg, value);
1360 if (ConfigWriteStr(szBuffer, value, TRUE, TRUE, TRUE))
1361 {
1362 ConsolePrintf(pCtx, _T("Configuration variable %s updated\n"), szBuffer);
1363 }
1364 else
1365 {
1366 ConsolePrintf(pCtx, _T("ERROR: cannot update configuration variable %s\n"), szBuffer);
1367 }
1368 }
1369 else
1370 {
1371 ConsolePrintf(pCtx, _T("Variable name missing\n"));
1372 }
1373 }
1374 else if (IsCommand(_T("SHOW"), szBuffer, 2))
1375 {
1376 // Get argument
1377 pArg = ExtractWord(pArg, szBuffer);
1378
1379 if (IsCommand(_T("COMPONENTS"), szBuffer, 1))
1380 {
1381 // Get argument
1382 pArg = ExtractWord(pArg, szBuffer);
1383 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
1384 if (dwNode != 0)
1385 {
1386 NetObj *pObject = FindObjectById(dwNode);
1387 if (pObject != NULL)
1388 {
1389 if (pObject->getObjectClass() == OBJECT_NODE)
1390 {
1391 ComponentTree *components = ((Node *)pObject)->getComponents();
1392 if (components != NULL)
1393 {
1394 components->print(pCtx);
1395 components->decRefCount();
1396 }
1397 else
1398 {
1399 ConsoleWrite(pCtx, _T("ERROR: Node does not have physical component information\n\n"));
1400 }
1401 }
1402 else
1403 {
1404 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
1405 }
1406 }
1407 else
1408 {
1409 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1410 }
1411 }
1412 else
1413 {
1414 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1415 }
1416 }
1417 else if (IsCommand(_T("DBCP"), szBuffer, 4))
1418 {
1419 ObjectArray<PoolConnectionInfo> *list = DBConnectionPoolGetConnectionList();
1420 for(int i = 0; i < list->size(); i++)
1421 {
1422 PoolConnectionInfo *c = list->get(i);
1423 TCHAR accessTime[64];
1424 struct tm *ltm = localtime(&c->lastAccessTime);
1425 _tcsftime(accessTime, 64, _T("%d.%b.%Y %H:%M:%S"), ltm);
1426 ConsolePrintf(pCtx, _T("%p %s %hs:%d\n"), c->handle, accessTime, c->srcFile, c->srcLine);
1427 }
1428 ConsolePrintf(pCtx, _T("%d database connections in use\n\n"), list->size());
1429 delete list;
1430 }
1431 else if (IsCommand(_T("DBSTATS"), szBuffer, 3))
1432 {
1433 LIBNXDB_PERF_COUNTERS counters;
1434 DBGetPerfCounters(&counters);
1435 ConsolePrintf(pCtx, _T("SQL query counters:\n"));
1436 ConsolePrintf(pCtx, _T(" Total .......... ") INT64_FMT _T("\n"), counters.totalQueries);
1437 ConsolePrintf(pCtx, _T(" SELECT ......... ") INT64_FMT _T("\n"), counters.selectQueries);
1438 ConsolePrintf(pCtx, _T(" Non-SELECT ..... ") INT64_FMT _T("\n"), counters.nonSelectQueries);
1439 ConsolePrintf(pCtx, _T(" Long running ... ") INT64_FMT _T("\n"), counters.longRunningQueries);
1440 ConsolePrintf(pCtx, _T(" Failed ......... ") INT64_FMT _T("\n"), counters.failedQueries);
1441
1442 ConsolePrintf(pCtx, _T("Background writer requests:\n"));
1443 ConsolePrintf(pCtx, _T(" DCI data ....... ") INT64_FMT _T("\n"), g_idataWriteRequests);
1444 ConsolePrintf(pCtx, _T(" DCI raw data ... ") INT64_FMT _T("\n"), g_rawDataWriteRequests);
1445 ConsolePrintf(pCtx, _T(" Others ......... ") INT64_FMT _T("\n"), g_otherWriteRequests);
1446 }
1447 else if (IsCommand(_T("FDB"), szBuffer, 3))
1448 {
1449 // Get argument
1450 pArg = ExtractWord(pArg, szBuffer);
1451 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
1452 if (dwNode != 0)
1453 {
1454 NetObj *pObject = FindObjectById(dwNode);
1455 if (pObject != NULL)
1456 {
1457 if (pObject->getObjectClass() == OBJECT_NODE)
1458 {
1459 ForwardingDatabase *fdb = ((Node *)pObject)->getSwitchForwardingDatabase();
1460 if (fdb != NULL)
1461 {
1462 fdb->print(pCtx, (Node *)pObject);
1463 fdb->decRefCount();
1464 }
1465 else
1466 {
1467 ConsoleWrite(pCtx, _T("ERROR: Node does not have forwarding database information\n\n"));
1468 }
1469 }
1470 else
1471 {
1472 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
1473 }
1474 }
1475 else
1476 {
1477 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1478 }
1479 }
1480 else
1481 {
1482 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1483 }
1484 }
1485 else if (IsCommand(_T("FLAGS"), szBuffer, 1))
1486 {
1487 ConsolePrintf(pCtx, _T("Flags: 0x") UINT64X_FMT(_T("016")) _T("\n"), g_flags);
1488 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DAEMON));
1489 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSLOG));
1490 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NETWORK_DISCOVERY));
1491 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ACTIVE_NETWORK_DISCOVERY));
1492 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_SQL_ERRORS));
1493 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DELETE_EMPTY_SUBNETS));
1494 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_SNMP_TRAPD));
1495 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_ZONING));
1496 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYNC_NODE_NAMES_WITH_DNS));
1497 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CHECK_TRUSTED_NODES));
1498 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NXSL_CONTAINER_FUNCS));
1499 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_FQDN_FOR_NODE_NAMES));
1500 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE));
1501 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DEBUG_CONSOLE_DISABLED));
1502 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_OBJECT_TRANSACTIONS));
1503 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_WRITE_FULL_DUMP));
1504 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_NODE_NAMES));
1505 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CATCH_EXCEPTIONS));
1506 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_HELPDESK_LINK_ACTIVE));
1507 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_LOCKED));
1508 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_CONNECTION_LOST));
1509 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_NO_NETWORK_CONNECTIVITY));
1510 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_EVENT_STORM_DETECTED));
1511 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SNMP_TRAP_DISCOVERY));
1512 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAPS_FROM_UNMANAGED_NODES));
1513 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_IP_FOR_EACH_STATUS_POLL));
1514 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_PERFDATA_STORAGE_DRIVER_LOADED));
1515 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_BACKGROUND_LOG_WRITER));
1516 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CASE_INSENSITIVE_LOGINS));
1517 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAP_SOURCES_IN_ALL_ZONES));
1518 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SERVER_INITIALIZED));
1519 ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SHUTDOWN));
1520 ConsolePrintf(pCtx, _T("\n"));
1521 }
1522 else if (IsCommand(_T("HEAP"), szBuffer, 1))
1523 {
1524 TCHAR *text = GetHeapInfo();
1525 if (text != NULL)
1526 {
1527 ConsoleWrite(pCtx, text);
1528 ConsoleWrite(pCtx, _T("\n"));
1529 free(text);
1530 }
1531 else
1532 {
1533 ConsoleWrite(pCtx, _T("Error reading heap information\n"));
1534 }
1535 }
1536 else if (IsCommand(_T("INDEX"), szBuffer, 1))
1537 {
1538 // Get argument
1539 pArg = ExtractWord(pArg, szBuffer);
1540
1541 if (IsCommand(_T("CONDITION"), szBuffer, 1))
1542 {
1543 DumpIndex(pCtx, &g_idxConditionById);
1544 }
1545 else if (IsCommand(_T("ID"), szBuffer, 2))
1546 {
1547 DumpIndex(pCtx, &g_idxObjectById);
1548 }
1549 else if (IsCommand(_T("INTERFACE"), szBuffer, 2))
1550 {
1551 DumpIndex(pCtx, &g_idxInterfaceByAddr);
1552 }
1553 else if (IsCommand(_T("NODEADDR"), szBuffer, 5))
1554 {
1555 DumpIndex(pCtx, &g_idxNodeByAddr);
1556 }
1557 else if (IsCommand(_T("NODEID"), szBuffer, 5))
1558 {
1559 DumpIndex(pCtx, &g_idxNodeById);
1560 }
1561 else if (IsCommand(_T("SUBNET"), szBuffer, 1))
1562 {
1563 DumpIndex(pCtx, &g_idxSubnetByAddr);
1564 }
1565 else if (IsCommand(_T("ZONE"), szBuffer, 1))
1566 {
1567 DumpIndex(pCtx, &g_idxZoneByGUID);
1568 }
1569 else
1570 {
1571 if (szBuffer[0] == 0)
1572 ConsoleWrite(pCtx, _T("ERROR: Missing index name\n")
1573 _T("Valid names are: CONDITION, ID, INTERFACE, NODEADDR, NODEID, SUBNET, ZONE\n\n"));
1574 else
1575 ConsoleWrite(pCtx, _T("ERROR: Invalid index name\n\n"));
1576 }
1577 }
1578 else if (IsCommand(_T("LLDP"), szBuffer, 4))
1579 {
1580 // Get argument
1581 pArg = ExtractWord(pArg, szBuffer);
1582 UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
1583 if (dwNode != 0)
1584 {
1585 NetObj *pObject = FindObjectById(dwNode);
1586 if (pObject != NULL)
1587 {
1588 if (pObject->getObjectClass() == OBJECT_NODE)
1589 {
1590 ((Node *)pObject)->showLLDPInfo(pCtx);
1591 }
1592 else
1593 {
1594 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
1595 }
1596 }
1597 else
1598 {
1599 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1600 }
1601 }
1602 else
1603 {
1604 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1605 }
1606 }
1607 else if (IsCommand(_T("MODULES"), szBuffer, 3))
1608 {
1609 ConsoleWrite(pCtx, _T("Loaded server modules:\n"));
1610 for(UINT32 i = 0; i < g_dwNumModules; i++)
1611 {
1612 ConsolePrintf(pCtx, _T(" %s\n"), g_pModuleList[i].szName);
1613 }
1614 ConsolePrintf(pCtx, _T("%d modules loaded\n"), g_dwNumModules);
1615 }
1616 else if (IsCommand(_T("MSGWQ"), szBuffer, 2))
1617 {
1618 String text = MsgWaitQueue::getDiagInfo();
1619 ConsoleWrite(pCtx, text);
1620 ConsoleWrite(pCtx, _T("\n"));
1621 }
1622 else if (IsCommand(_T("OBJECTS"), szBuffer, 1))
1623 {
1624 // Get filter
1625 pArg = ExtractWord(pArg, szBuffer);
1626 StrStrip(szBuffer);
1627 DumpObjects(pCtx, (szBuffer[0] != 0) ? szBuffer : NULL);
1628 }
1629 else if (IsCommand(_T("POLLERS"), szBuffer, 1))
1630 {
1631 ShowPollers(pCtx);
1632 }
1633 else if (IsCommand(_T("QUEUES"), szBuffer, 1))
1634 {
1635 ShowQueueStats(pCtx, &g_dataCollectionQueue, _T("Data collector"));
1636 ShowQueueStats(pCtx, &g_dciCacheLoaderQueue, _T("DCI cache loader"));
1637 ShowQueueStats(pCtx, g_dbWriterQueue, _T("Database writer"));
1638 ShowQueueStats(pCtx, g_dciDataWriterQueue, _T("Database writer (IData)"));
1639 ShowQueueStats(pCtx, g_dciRawDataWriterQueue, _T("Database writer (raw DCI values)"));
1640 ShowQueueStats(pCtx, g_pEventQueue, _T("Event processor"));
1641 ShowQueueStats(pCtx, &g_nodePollerQueue, _T("Node poller"));
1642 ShowQueueStats(pCtx, &g_syslogProcessingQueue, _T("Syslog processing"));
1643 ShowQueueStats(pCtx, &g_syslogWriteQueue, _T("Syslog writer"));
1644 ConsolePrintf(pCtx, _T("\n"));
1645 }
1646 else if (IsCommand(_T("ROUTING-TABLE"), szBuffer, 1))
1647 {
1648 UINT32 dwNode;
1649 NetObj *pObject;
1650
1651 pArg = ExtractWord(pArg, szBuffer);
1652 dwNode = _tcstoul(szBuffer, NULL, 0);
1653 if (dwNode != 0)
1654 {
1655 pObject = FindObjectById(dwNode);
1656 if (pObject != NULL)
1657 {
1658 if (pObject->getObjectClass() == OBJECT_NODE)
1659 {
1660 ROUTING_TABLE *pRT;
1661 TCHAR szIpAddr[16];
1662 int i;
1663
1664 ConsolePrintf(pCtx, _T("Routing table for node %s:\n\n"), pObject->getName());
1665 pRT = ((Node *)pObject)->getCachedRoutingTable();
1666 if (pRT != NULL)
1667 {
1668 for(i = 0; i < pRT->iNumEntries; i++)
1669 {
1670 _sntprintf(szBuffer, 256, _T("%s/%d"), IpToStr(pRT->pRoutes[i].dwDestAddr, szIpAddr),
1671 BitsInMask(pRT->pRoutes[i].dwDestMask));
1672 ConsolePrintf(pCtx, _T("%-18s %-15s %-6d %d\n"), szBuffer,
1673 IpToStr(pRT->pRoutes[i].dwNextHop, szIpAddr),
1674 pRT->pRoutes[i].dwIfIndex, pRT->pRoutes[i].dwRouteType);
1675 }
1676 ConsoleWrite(pCtx, _T("\n"));
1677 }
1678 else
1679 {
1680 ConsoleWrite(pCtx, _T("Node doesn't have cached routing table\n\n"));
1681 }
1682 }
1683 else
1684 {
1685 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
1686 }
1687 }
1688 else
1689 {
1690 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
1691 }
1692 }
1693 else
1694 {
1695 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1696 }
1697 }
1698 else if (IsCommand(_T("SESSIONS"), szBuffer, 2))
1699 {
1700 ConsoleWrite(pCtx, _T("\x1b[1mCLIENT SESSIONS\x1b[0m\n============================================================\n"));
1701 DumpClientSessions(pCtx);
1702 ConsoleWrite(pCtx, _T("\n\x1b[1mMOBILE DEVICE SESSIONS\x1b[0m\n============================================================\n"));
1703 DumpMobileDeviceSessions(pCtx);
1704 }
1705 else if (IsCommand(_T("STATS"), szBuffer, 2))
1706 {
1707 ShowServerStats(pCtx);
1708 }
1709 else if (IsCommand(_T("THREADS"), szBuffer, 2))
1710 {
1711 ShowThreadPool(pCtx, g_mainThreadPool);
1712 ShowThreadPool(pCtx, g_pollerThreadPool);
1713 ShowThreadPool(pCtx, g_schedulerThreadPool);
1714 ShowThreadPool(pCtx, g_agentConnectionThreadPool);
1715 }
1716 else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
1717 {
1718 pArg = ExtractWord(pArg, szBuffer);
1719 UINT32 nodeId = _tcstoul(szBuffer, NULL, 0);
1720 if (nodeId != 0)
1721 {
1722 Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
1723 if (node != NULL)
1724 {
1725 LinkLayerNeighbors *nbs = BuildLinkLayerNeighborList(node);
1726 if (nbs != NULL)
1727 {
1728 ConsolePrintf(pCtx, _T("Proto | PtP | ifLocal | ifRemote | Peer\n")
1729 _T("--------+-----+---------+----------+------------------------------------\n"));
1730 for(int i = 0; i < nbs->size(); i++)
1731 {
1732 LL_NEIGHBOR_INFO *ni = nbs->getConnection(i);
1733 TCHAR peer[256];
1734 if (ni->objectId != 0)
1735 {
1736 NetObj *object = FindObjectById(ni->objectId);
1737 if (object != NULL)
1738 _sntprintf(peer, 256, _T("%s [%d]"), object->getName(), ni->objectId);
1739 else
1740 _sntprintf(peer, 256, _T("[%d]"), ni->objectId);
1741 }
1742 else
1743 {
1744 peer[0] = 0;
1745 }
1746 ConsolePrintf(pCtx, _T("%-7s | %c | %7d | %7d | %s\n"),
1747 GetLinkLayerProtocolName(ni->protocol), ni->isPtToPt ? _T('Y') : _T('N'), ni->ifLocal, ni->ifRemote, peer);
1748 }
1749 nbs->decRefCount();
1750 }
1751 else
1752 {
1753 ConsoleWrite(pCtx, _T("ERROR: call to BuildLinkLayerNeighborList failed\n\n"));
1754 }
1755 }
1756 else
1757 {
1758 ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), nodeId);
1759 }
1760 }
1761 else
1762 {
1763 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
1764 }
1765 }
1766 else if (IsCommand(_T("USERS"), szBuffer, 1))
1767 {
1768 DumpUsers(pCtx);
1769 }
1770 else if (IsCommand(_T("VLANS"), szBuffer, 1))
1771 {
1772 UINT32 dwNode;
1773 NetObj *pObject;
1774
1775 pArg = ExtractWord(pArg, szBuffer);
1776 dwNode = _tcstoul(szBuffer, NULL, 0);
1777 if (dwNode != 0)
1778 {
1779 pObject = FindObjectById(dwNode);
1780 if (pObject != NULL)
1781 {
1782 if (pObject->getObjectClass() == OBJECT_NODE)
1783 {
1784 VlanList *vlans = ((Node *)pObject)->getVlans();
1785 if (vlans != NULL)
1786 {
1787 ConsoleWrite(pCtx, _T("\x1b[1mVLAN\x1b[0m | \x1b[1mName\x1b[0m | \x1b[1mPorts\x1b[0m\n")
1788 _T("-----+------------------+-----------------------------------------------------------------\n"));
1789 for(int i = 0; i < vlans->size(); i++)
1790 {
1791 VlanInfo *vlan = vlans->get(i);
1792 ConsolePrintf(pCtx, _T("%4d | %-16s |"), vlan->getVlanId(), vlan->getName());
1793 for(int j = 0; j < vlan->getNumPorts(); j++)
1794 ConsolePrintf(pCtx, _T(" %d.%d"), (int)(vlan->getPorts()[j] >> 16), (int)(vlan->getPorts()[j] & 0xFFFF));
1795 ConsolePrintf(pCtx, _T("\n"));
1796 }
1797 ConsolePrintf(pCtx, _T("\n"));
1798 vlans->decRefCount();
1799 }
1800 else
1801 {
1802 ConsoleWrite(pCtx, _T("\x1b[31mNode doesn't have VLAN information\x1b[0m\n\n"));
1803 }
1804 }
1805 else
1806 {
1807 ConsoleWrite(pCtx, _T("\x1b[31mERROR: Object is not a node\x1b[0m\n\n"));
1808 }
1809 }
1810 else
1811 {
1812 ConsolePrintf(pCtx, _T("\x1b[31mERROR: Object with ID %d does not exist\x1b[0m\n\n"), dwNode);
1813 }
1814 }
1815 else
1816 {
1817 ConsoleWrite(pCtx, _T("\x1b[31mERROR: Invalid or missing node ID\x1b[0m\n\n"));
1818 }
1819 }
1820 else if (IsCommand(_T("WATCHDOG"), szBuffer, 1))
1821 {
1822 WatchdogPrintStatus(pCtx);
1823 ConsoleWrite(pCtx, _T("\n"));
1824 }
1825 else
1826 {
1827 if (szBuffer[0] == 0)
1828 ConsoleWrite(pCtx, _T("ERROR: Missing subcommand\n\n"));
1829 else
1830 ConsoleWrite(pCtx, _T("ERROR: Invalid SHOW subcommand\n\n"));
1831 }
1832 }
1833 else if (IsCommand(_T("EXEC"), szBuffer, 3))
1834 {
1835 pArg = ExtractWord(pArg, szBuffer);
1836
1837 bool libraryLocked = true;
1838 bool destroyCompiledScript = false;
1839 g_pScriptLibrary->lock();
1840
1841 NXSL_Program *compiledScript = g_pScriptLibrary->findScript(szBuffer);
1842 if (compiledScript == NULL)
1843 {
1844 g_pScriptLibrary->unlock();
1845 libraryLocked = false;
1846 destroyCompiledScript = true;
1847 char *script;
1848 UINT32 fileSize;
1849 if ((script = (char *)LoadFile(szBuffer, &fileSize)) != NULL)
1850 {
1851 const int errorMsgLen = 512;
1852 TCHAR errorMsg[errorMsgLen];
1853 #ifdef UNICODE
1854 WCHAR *wscript = WideStringFromMBString(script);
1855 compiledScript = NXSLCompile(wscript, errorMsg, errorMsgLen, NULL);
1856 free(wscript);
1857 #else
1858 compiledScript = NXSLCompile(script, errorMsg, errorMsgLen, NULL);
1859 #endif
1860 free(script);
1861 if (compiledScript == NULL)
1862 {
1863 ConsolePrintf(pCtx, _T("ERROR: Script compilation error: %s\n\n"), errorMsg);
1864 }
1865 }
1866 else
1867 {
1868 ConsolePrintf(pCtx, _T("ERROR: Script \"%s\" not found\n\n"), szBuffer);
1869 }
1870 }
1871
1872 if (compiledScript != NULL)
1873 {
1874 NXSL_ServerEnv *pEnv = new NXSL_ServerEnv;
1875 pEnv->setConsole(pCtx);
1876
1877 NXSL_VM *vm = new NXSL_VM(pEnv);
1878 if (vm->load(compiledScript))
1879 {
1880 if (libraryLocked)
1881 {
1882 g_pScriptLibrary->unlock();
1883 libraryLocked = false;
1884 }
1885
1886 NXSL_Value *argv[32];
1887 int argc = 0;
1888 while(argc < 32)
1889 {
1890 pArg = ExtractWord(pArg, szBuffer);
1891 if (szBuffer[0] == 0)
1892 break;
1893 argv[argc++] = new NXSL_Value(szBuffer);
1894 }
1895
1896 if (vm->run(argc, argv))
1897 {
1898 NXSL_Value *pValue = vm->getResult();
1899 int retCode = pValue->getValueAsInt32();
1900 ConsolePrintf(pCtx, _T("INFO: Script finished with rc=%d\n\n"), retCode);
1901 }
1902 else
1903 {
1904 ConsolePrintf(pCtx, _T("ERROR: Script finished with error: %s\n\n"), vm->getErrorText());
1905 }
1906 }
1907 else
1908 {
1909 ConsolePrintf(pCtx, _T("ERROR: VM creation failed: %s\n\n"), vm->getErrorText());
1910 }
1911 delete vm;
1912 if (destroyCompiledScript)
1913 delete compiledScript;
1914 }
1915 if (libraryLocked)
1916 g_pScriptLibrary->unlock();
1917 }
1918 else if (IsCommand(_T("TRACE"), szBuffer, 1))
1919 {
1920 UINT32 dwNode1, dwNode2;
1921 NetObj *pObject1, *pObject2;
1922 NetworkPath *pTrace;
1923 TCHAR szNextHop[16];
1924 int i;
1925
1926 // Get arguments
1927 pArg = ExtractWord(pArg, szBuffer);
1928 dwNode1 = _tcstoul(szBuffer, NULL, 0);
1929
1930 pArg = ExtractWord(pArg, szBuffer);
1931 dwNode2 = _tcstoul(szBuffer, NULL, 0);
1932
1933 if ((dwNode1 != 0) && (dwNode2 != 0))
1934 {
1935 pObject1 = FindObjectById(dwNode1);
1936 if (pObject1 == NULL)
1937 {
1938 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode1);
1939 }
1940 else
1941 {
1942 pObject2 = FindObjectById(dwNode2);
1943 if (pObject2 == NULL)
1944 {
1945 ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode2);
1946 }
1947 else
1948 {
1949 if ((pObject1->getObjectClass() == OBJECT_NODE) && (pObject2->getObjectClass() == OBJECT_NODE))
1950 {
1951 pTrace = TraceRoute((Node *)pObject1, (Node *)pObject2);
1952 if (pTrace != NULL)
1953 {
1954 TCHAR sourceIp[32];
1955 ConsolePrintf(pCtx, _T("Trace from %s to %s (%d hops, %s, source IP %s):\n"),
1956 pObject1->getName(), pObject2->getName(), pTrace->getHopCount(),
1957 pTrace->isComplete() ? _T("complete") : _T("incomplete"),
1958 pTrace->getSourceAddress().toString(sourceIp));
1959 for(i = 0; i < pTrace->getHopCount(); i++)
1960 {
1961 HOP_INFO *hop = pTrace->getHopInfo(i);
1962 ConsolePrintf(pCtx, _T("[%d] %s %s %s %d\n"),
1963 hop->object->getId(),
1964 hop->object->getName(),
1965 hop->nextHop.toString(szNextHop),
1966 hop->isVpn ? _T("VPN Connector ID:") : _T("Interface Index: "),
1967 hop->ifIndex);
1968 }
1969 delete pTrace;
1970 ConsolePrintf(pCtx, _T("\n"));
1971 }
1972 else
1973 {
1974 ConsoleWrite(pCtx, _T("ERROR: Call to TraceRoute() failed\n\n"));
1975 }
1976 }
1977 else
1978 {
1979 ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
1980 }
1981 }
1982 }
1983 }
1984 else
1985 {
1986 ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node id(s)\n\n"));
1987 }
1988 }
1989 else if (IsCommand(_T("HELP"), szBuffer, 2) || IsCommand(_T("?"), szBuffer, 1))
1990 {
1991 ConsoleWrite(pCtx,
1992 _T("Valid commands are:\n")
1993 _T(" at +<seconds>|<schedule> <script> [<parameters>]\n")
1994 _T(" - Schedule script execution task\n")
1995 _T(" debug [<level>|off] - Set debug level (valid range is 0..9)\n")
1996 _T(" down - Shutdown NetXMS server\n")
1997 _T(" exec <script> [<params>] - Executes NXSL script from script library\n")
1998 _T(" exit - Exit from remote session\n")
1999 _T(" kill <session> - Kill client session\n")
2000 _T(" get <variable> - Get value of server configuration variable\n")
2001 _T(" help - Display this help\n")
2002 _T(" hkrun - Run housekeeper immediately\n")
2003 _T(" ldapsync - Synchronize ldap users with local user database\n")
2004 _T(" log <text> - Write given text to server log file\n")
2005 _T(" logmark - Write marker ******* MARK ******* to server log file\n")
2006 _T(" ping <address> - Send ICMP echo request to given IP address\n")
2007 _T(" poll <type> <node> - Initiate node poll\n")
2008 _T(" raise <exception> - Raise exception\n")
2009 _T(" set <variable> <value> - Set value of server configuration variable\n")
2010 _T(" show components <node> - Show physical components of given node\n")
2011 _T(" show dbcp - Show active sessions in database connection pool\n")
2012 _T(" show dbstats - Show DB library statistics\n")
2013 _T(" show fdb <node> - Show forwarding database for node\n")
2014 _T(" show flags - Show internal server flags\n")
2015 _T(" show heap - Show heap information\n")
2016 _T(" show index <index> - Show internal index\n")
2017 _T(" show modules - Show loaded server modules\n")
2018 _T(" show msgwq - Show message wait queues information\n")
2019 _T(" show objects [<filter>] - Dump network objects to screen\n")
2020 _T(" show pollers - Show poller threads state information\n")
2021 _T(" show queues - Show internal queues statistics\n")
2022 _T(" show routing-table <node> - Show cached routing table for node\n")
2023 _T(" show sessions - Show active client sessions\n")
2024 _T(" show stats - Show server statistics\n")
2025 _T(" show topology <node> - Collect and show link layer topology for node\n")
2026 _T(" show users - Show users\n")
2027 _T(" show vlans <node> - Show cached VLAN information for node\n")
2028 _T(" show watchdog - Display watchdog information\n")
2029 _T(" trace <node1> <node2> - Show network path trace between two nodes\n")
2030 _T("\nAlmost all commands can be abbreviated to 2 or 3 characters\n")
2031 _T("\n"));
2032 }
2033 else
2034 {
2035 ConsoleWrite(pCtx, _T("UNKNOWN COMMAND\n\n"));
2036 }
2037
2038 return nExitCode;
2039 }
2040
2041 /**
2042 * Signal handler for UNIX platforms
2043 */
2044 #ifndef _WIN32
2045
2046 void SignalHandlerStub(int nSignal)
2047 {
2048 // should be unused, but JIC...
2049 if (nSignal == SIGCHLD)
2050 {
2051 while (waitpid(-1, NULL, WNOHANG) > 0)
2052 ;
2053 }
2054 }
2055
2056 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
2057 {
2058 sigset_t signals;
2059 int nSignal;
2060
2061 m_signalHandlerThread = pthread_self();
2062
2063 // default for SIGCHLD: ignore
2064 signal(SIGCHLD, &SignalHandlerStub);
2065
2066 sigemptyset(&signals);
2067 sigaddset(&signals, SIGTERM);
2068 sigaddset(&signals, SIGINT);
2069 sigaddset(&signals, SIGSEGV);
2070 sigaddset(&signals, SIGCHLD);
2071 sigaddset(&signals, SIGHUP);
2072 sigaddset(&signals, SIGUSR1);
2073 sigaddset(&signals, SIGUSR2);
2074 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
2075 sigaddset(&signals, SIGPIPE);
2076 #endif
2077
2078 sigprocmask(SIG_BLOCK, &signals, NULL);
2079
2080 while(1)
2081 {
2082 if (sigwait(&signals, &nSignal) == 0)
2083 {
2084 switch(nSignal)
2085 {
2086 case SIGTERM:
2087 case SIGINT:
2088 // avoid repeat Shutdown() call
2089 if (!(g_flags & AF_SHUTDOWN))
2090 {
2091 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
2092 if (IsStandalone())
2093 Shutdown(); // will never return
2094 else
2095 ConditionSet(m_condShutdown);
2096 }
2097 break;
2098 case SIGSEGV:
2099 abort();
2100 break;
2101 case SIGCHLD:
2102 while (waitpid(-1, NULL, WNOHANG) > 0)
2103 ;
2104 break;
2105 case SIGUSR1:
2106 if (g_flags & AF_SHUTDOWN)
2107 goto stop_handler;
2108 break;
2109 default:
2110 break;
2111 }
2112 }
2113 else
2114 {
2115 ThreadSleepMs(100);
2116 }
2117 }
2118
2119 stop_handler:
2120 sigprocmask(SIG_UNBLOCK, &signals, NULL);
2121 return THREAD_OK;
2122 }
2123
2124 #endif
2125
2126 /**
2127 * Common main()
2128 */
2129 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
2130 {
2131 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
2132
2133 if (IsStandalone())
2134 {
2135 if (!(g_flags & AF_DEBUG_CONSOLE_DISABLED))
2136 {
2137 char *ptr, szCommand[256];
2138 struct __console_ctx ctx;
2139 #ifdef UNICODE
2140 WCHAR wcCommand[256];
2141 #endif
2142
2143 ctx.hSocket = -1;
2144 ctx.socketMutex = INVALID_MUTEX_HANDLE;
2145 ctx.pMsg = NULL;
2146 ctx.session = NULL;
2147 ctx.output = NULL;
2148 WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T(" Ready\n")
2149 _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n")
2150 _T("System Console\n\n"));
2151
2152 #if USE_READLINE
2153 // Initialize readline library if we use it
2154 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
2155 #endif
2156
2157 while(1)
2158 {
2159 #if USE_READLINE
2160 ptr = readline("\x1b[33mnetxmsd:\x1b[0m ");
2161 #else
2162 WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m "));
2163 fflush(stdout);
2164 if (fgets(szCommand, 255, stdin) == NULL)
2165 break; // Error reading stdin
2166 ptr = strchr(szCommand, '\n');
2167 if (ptr != NULL)
2168 *ptr = 0;
2169 ptr = szCommand;
2170 #endif
2171
2172 if (ptr != NULL)
2173 {
2174 #ifdef UNICODE
2175 #if HAVE_MBSTOWCS
2176 mbstowcs(wcCommand, ptr, 255);
2177 #else
2178 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
2179 #endif
2180 wcCommand[255] = 0;
2181 StrStrip(wcCommand);
2182 if (wcCommand[0] != 0)
2183 {
2184 if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN)
2185 #else
2186 StrStrip(ptr);
2187 if (*ptr != 0)
2188 {
2189 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
2190 #endif
2191 break;
2192 #if USE_READLINE
2193 add_history(ptr);
2194 #endif
2195 }
2196 #if USE_READLINE
2197 free(ptr);
2198 #endif
2199 }
2200 else
2201 {
2202 _tprintf(_T("\n"));
2203 }
2204 }
2205
2206 #if USE_READLINE
2207 free(ptr);
2208 #endif
2209 if (!(g_flags & AF_SHUTDOWN))
2210 {
2211 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
2212 Shutdown();
2213 }
2214 }
2215 else
2216 {
2217 // standalone with debug console disabled
2218 #ifdef _WIN32
2219 _tprintf(_T("Server running. Press ESC to shutdown.\n"));
2220 while(1)
2221 {
2222 if (_getch() == 27)
2223 break;
2224 }
2225 _tprintf(_T("Server shutting down...\n"));
2226 Shutdown();
2227 #else
2228 _tprintf(_T("Server running. Press Ctrl+C to shutdown.\n"));
2229 // Shutdown will be called from signal handler
2230 ConditionWait(m_condShutdown, INFINITE);
2231 #endif
2232 }
2233 }
2234 else
2235 {
2236 ConditionWait(m_condShutdown, INFINITE);
2237 // On Win32, Shutdown() will be called by service control handler
2238 #ifndef _WIN32
2239 Shutdown();
2240 #endif
2241 }
2242 return THREAD_OK;
2243 }
2244
2245 /**
2246 * Initiate server shutdown
2247 */
2248 void InitiateShutdown()
2249 {
2250 #ifdef _WIN32
2251 Shutdown();
2252 #else
2253 if (IsStandalone())
2254 {
2255 Shutdown();
2256 }
2257 else
2258 {
2259 pthread_kill(m_signalHandlerThread, SIGTERM);
2260 }
2261 #endif
2262 }
2263
2264 /**
2265 *DLL Entry point
2266 */
2267 #ifdef _WIN32
2268
2269 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
2270 {
2271 if (dwReason == DLL_PROCESS_ATTACH)
2272 DisableThreadLibraryCalls(hInstance);
2273 return TRUE;
2274 }
2275
2276 #endif