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