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