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