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