added check for istalled peer node DB lock in active/passive cluster (issue #185)
[public/netxms.git] / src / server / core / main.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Raden Solutions
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: main.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <netxmsdb.h>
25 #include <netxms_mt.h>
26 #include <hdlink.h>
27
28 #if !defined(_WIN32) && HAVE_READLINE_READLINE_H && HAVE_READLINE && !defined(UNICODE)
29 #include <readline/readline.h>
30 #include <readline/history.h>
31 #define USE_READLINE 1
32 #endif
33
34 #ifdef _WIN32
35 #include <errno.h>
36 #include <psapi.h>
37 #include <conio.h>
38 #define open _open
39 #define write _write
40 #define close _close
41 #else
42 #include <signal.h>
43 #include <sys/wait.h>
44 #endif
45
46 #ifdef WITH_ZMQ
47 #include "zeromq.h"
48 #endif
49
50 /**
51 * Messages generated by mc.pl (for UNIX version only)
52 */
53 #ifndef _WIN32
54 extern unsigned int g_dwNumMessages;
55 extern const TCHAR *g_szMessages[];
56 #endif
57
58 /**
59 * Shutdown reasons
60 */
61 #define SHUTDOWN_DEFAULT 0
62 #define SHUTDOWN_FROM_CONSOLE 1
63 #define SHUTDOWN_BY_SIGNAL 2
64
65 /**
66 * Externals
67 */
68 extern Queue g_dciCacheLoaderQueue;
69
70 void InitClientListeners();
71 void InitMobileDeviceListeners();
72 void InitCertificates();
73 void InitUsers();
74 void CleanupUsers();
75 void LoadPerfDataStorageDrivers();
76 void ImportLocalConfiguration();
77
78 void ExecuteScheduledScript(const ScheduledTaskParameters *param);
79 void MaintenanceModeEnter(const ScheduledTaskParameters *params);
80 void MaintenanceModeLeave(const ScheduledTaskParameters *params);
81 void ScheduleDeployPolicy(const ScheduledTaskParameters *params);
82 void ScheduleUninstallPolicy(const ScheduledTaskParameters * params);
83
84 void InitCountryList();
85 void InitCurrencyList();
86
87 #if XMPP_SUPPORTED
88 void StartXMPPConnector();
89 void StopXMPPConnector();
90 #endif
91
92 /**
93 * Syslog server control
94 */
95 void StartSyslogServer();
96 void StopSyslogServer();
97
98 /**
99 * Thread functions
100 */
101 THREAD_RESULT THREAD_CALL Syncer(void *);
102 THREAD_RESULT THREAD_CALL NodePoller(void *);
103 THREAD_RESULT THREAD_CALL PollManager(void *);
104 THREAD_RESULT THREAD_CALL EventProcessor(void *);
105 THREAD_RESULT THREAD_CALL WatchdogThread(void *);
106 THREAD_RESULT THREAD_CALL ClientListener(void *);
107 THREAD_RESULT THREAD_CALL ClientListenerIPv6(void *);
108 THREAD_RESULT THREAD_CALL MobileDeviceListener(void *);
109 THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *);
110 THREAD_RESULT THREAD_CALL ISCListener(void *);
111 THREAD_RESULT THREAD_CALL LocalAdminListener(void *);
112 THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *);
113 THREAD_RESULT THREAD_CALL BeaconPoller(void *);
114 THREAD_RESULT THREAD_CALL JobManagerThread(void *);
115 THREAD_RESULT THREAD_CALL UptimeCalculator(void *);
116 THREAD_RESULT THREAD_CALL ReportingServerConnector(void *);
117
118 /**
119 * Global variables
120 */
121 TCHAR NXCORE_EXPORTABLE g_szConfigFile[MAX_PATH] = _T("{search}");
122 TCHAR NXCORE_EXPORTABLE g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
123 UINT32 g_logRotationMode = NXLOG_ROTATION_BY_SIZE;
124 UINT64 g_maxLogSize = 16384 * 1024;
125 UINT32 g_logHistorySize = 4;
126 TCHAR g_szDailyLogFileSuffix[64] = _T("");
127 TCHAR NXCORE_EXPORTABLE g_szDumpDir[MAX_PATH] = DEFAULT_DUMP_DIR;
128 char g_szCodePage[256] = ICONV_DEFAULT_CODEPAGE;
129 TCHAR NXCORE_EXPORTABLE g_szListenAddress[MAX_PATH] = _T("*");
130 #ifndef _WIN32
131 TCHAR NXCORE_EXPORTABLE g_szPIDFile[MAX_PATH] = _T("/var/run/netxmsd.pid");
132 #endif
133 UINT32 g_dwDiscoveryPollingInterval;
134 UINT32 g_dwStatusPollingInterval;
135 UINT32 g_dwConfigurationPollingInterval;
136 UINT32 g_dwRoutingTableUpdateInterval;
137 UINT32 g_dwTopologyPollingInterval;
138 UINT32 g_dwConditionPollingInterval;
139 UINT32 g_instancePollingInterval;
140 UINT32 g_icmpPingSize;
141 UINT32 g_icmpPingTimeout = 1500; // ICMP ping timeout (milliseconds)
142 UINT32 g_auditFlags;
143 UINT32 g_slmPollingInterval;
144 UINT32 g_offlineDataRelevanceTime = 86400;
145 TCHAR NXCORE_EXPORTABLE g_netxmsdDataDir[MAX_PATH] = _T("");
146 TCHAR NXCORE_EXPORTABLE g_netxmsdLibDir[MAX_PATH] = _T("");
147 int g_dbSyntax = DB_SYNTAX_UNKNOWN;
148 UINT32 NXCORE_EXPORTABLE g_processAffinityMask = DEFAULT_AFFINITY_MASK;
149 UINT64 g_serverId = 0;
150 RSA *g_pServerKey = NULL;
151 time_t g_serverStartTime = 0;
152 UINT32 g_lockTimeout = 60000; // Default timeout for acquiring mutex
153 UINT32 g_agentCommandTimeout = 4000; // Default timeout for requests to agent
154 UINT32 g_thresholdRepeatInterval = 0; // Disabled by default
155 int g_requiredPolls = 1;
156 DB_DRIVER g_dbDriver = NULL;
157 ThreadPool NXCORE_EXPORTABLE *g_mainThreadPool = NULL;
158 INT16 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
159 InetAddressList g_peerNodeAddrList;
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_thSyncer = INVALID_THREAD_HANDLE;
167 static int m_nShutdownReason = SHUTDOWN_DEFAULT;
168 static StringSet s_components;
169
170 #ifndef _WIN32
171 static pthread_t m_signalHandlerThread;
172 #endif
173
174 /**
175 * Register component
176 */
177 void NXCORE_EXPORTABLE RegisterComponent(const TCHAR *id)
178 {
179 s_components.add(id);
180 }
181
182 /**
183 * Check if component with given ID is registered
184 */
185 bool NXCORE_EXPORTABLE IsComponentRegistered(const TCHAR *id)
186 {
187 return s_components.contains(id);
188 }
189
190 /**
191 * Fill NXCP message with components data
192 */
193 void FillComponentsMessage(NXCPMessage *msg)
194 {
195 msg->setField(VID_NUM_COMPONENTS, (INT32)s_components.size());
196 UINT32 fieldId = VID_COMPONENT_LIST_BASE;
197 Iterator<const TCHAR> *it = s_components.iterator();
198 while(it->hasNext())
199 {
200 msg->setField(fieldId++, it->next());
201 }
202 delete it;
203 }
204
205 /**
206 * Sleep for specified number of seconds or until system shutdown arrives
207 * Function will return TRUE if shutdown event occurs
208 *
209 * @param seconds seconds to sleep
210 * @return true if server is shutting down
211 */
212 bool NXCORE_EXPORTABLE SleepAndCheckForShutdown(int seconds)
213 {
214 return ConditionWait(m_condShutdown, seconds * 1000);
215 }
216
217 /**
218 * Disconnect from database (exportable function for startup module)
219 */
220 void NXCORE_EXPORTABLE ShutdownDB()
221 {
222 DBConnectionPoolShutdown();
223 DBUnloadDriver(g_dbDriver);
224 }
225
226 /**
227 * Check data directory for existence
228 */
229 static BOOL CheckDataDir()
230 {
231 TCHAR szBuffer[MAX_PATH];
232
233 if (_tchdir(g_netxmsdDataDir) == -1)
234 {
235 nxlog_write(MSG_INVALID_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", g_netxmsdDataDir);
236 return FALSE;
237 }
238
239 #ifdef _WIN32
240 #define MKDIR(name) _tmkdir(name)
241 #else
242 #define MKDIR(name) _tmkdir(name, 0700)
243 #endif
244
245 // Create directory for package files if it doesn't exist
246 _tcscpy(szBuffer, g_netxmsdDataDir);
247 _tcscat(szBuffer, DDIR_PACKAGES);
248 if (MKDIR(szBuffer) == -1)
249 if (errno != EEXIST)
250 {
251 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
252 return FALSE;
253 }
254
255 // Create directory for map background images if it doesn't exist
256 _tcscpy(szBuffer, g_netxmsdDataDir);
257 _tcscat(szBuffer, DDIR_BACKGROUNDS);
258 if (MKDIR(szBuffer) == -1)
259 if (errno != EEXIST)
260 {
261 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
262 return FALSE;
263 }
264
265 // Create directory for image library is if does't exists
266 _tcscpy(szBuffer, g_netxmsdDataDir);
267 _tcscat(szBuffer, DDIR_IMAGES);
268 if (MKDIR(szBuffer) == -1)
269 {
270 if (errno != EEXIST)
271 {
272 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
273 return FALSE;
274 }
275 }
276
277 // Create directory for file store if does't exists
278 _tcscpy(szBuffer, g_netxmsdDataDir);
279 _tcscat(szBuffer, DDIR_FILES);
280 if (MKDIR(szBuffer) == -1)
281 {
282 if (errno != EEXIST)
283 {
284 nxlog_write(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer);
285 return FALSE;
286 }
287 }
288
289 #undef MKDIR
290
291 return TRUE;
292 }
293
294 /**
295 * Load global configuration parameters
296 */
297 static void LoadGlobalConfig()
298 {
299 g_dwDiscoveryPollingInterval = ConfigReadInt(_T("DiscoveryPollingInterval"), 900);
300 g_dwStatusPollingInterval = ConfigReadInt(_T("StatusPollingInterval"), 60);
301 g_dwConfigurationPollingInterval = ConfigReadInt(_T("ConfigurationPollingInterval"), 3600);
302 g_instancePollingInterval = ConfigReadInt(_T("InstancePollingInterval"), 600);
303 g_dwRoutingTableUpdateInterval = ConfigReadInt(_T("RoutingTableUpdateInterval"), 300);
304 g_dwTopologyPollingInterval = ConfigReadInt(_T("TopologyPollingInterval"), 1800);
305 g_dwConditionPollingInterval = ConfigReadInt(_T("ConditionPollingInterval"), 60);
306 g_slmPollingInterval = ConfigReadInt(_T("SlmPollingInterval"), 60);
307 DCObject::m_defaultPollingInterval = ConfigReadInt(_T("DefaultDCIPollingInterval"), 60);
308 DCObject::m_defaultRetentionTime = ConfigReadInt(_T("DefaultDCIRetentionTime"), 30);
309 g_defaultAgentCacheMode = (INT16)ConfigReadInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF);
310 if ((g_defaultAgentCacheMode != AGENT_CACHE_ON) && (g_defaultAgentCacheMode != AGENT_CACHE_OFF))
311 {
312 DbgPrintf(1, _T("Invalid value %d of DefaultAgentCacheMode: reset to %d (OFF)"), g_defaultAgentCacheMode, AGENT_CACHE_OFF);
313 ConfigWriteInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF, true, true, true);
314 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
315 }
316 if (ConfigReadInt(_T("DeleteEmptySubnets"), 1))
317 g_flags |= AF_DELETE_EMPTY_SUBNETS;
318 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
319 g_flags |= AF_ENABLE_SNMP_TRAPD;
320 if (ConfigReadInt(_T("ProcessTrapsFromUnmanagedNodes"), 0))
321 g_flags |= AF_TRAPS_FROM_UNMANAGED_NODES;
322 if (ConfigReadInt(_T("EnableZoning"), 0))
323 g_flags |= AF_ENABLE_ZONING;
324 if (ConfigReadInt(_T("EnableObjectTransactions"), 0))
325 g_flags |= AF_ENABLE_OBJECT_TRANSACTIONS;
326 if (ConfigReadInt(_T("RunNetworkDiscovery"), 0))
327 g_flags |= AF_ENABLE_NETWORK_DISCOVERY;
328 if (ConfigReadInt(_T("ActiveNetworkDiscovery"), 0))
329 g_flags |= AF_ACTIVE_NETWORK_DISCOVERY;
330 if (ConfigReadInt(_T("UseSNMPTrapsForDiscovery"), 0))
331 g_flags |= AF_SNMP_TRAP_DISCOVERY;
332 if (ConfigReadInt(_T("ResolveNodeNames"), 1))
333 g_flags |= AF_RESOLVE_NODE_NAMES;
334 if (ConfigReadInt(_T("SyncNodeNamesWithDNS"), 0))
335 g_flags |= AF_SYNC_NODE_NAMES_WITH_DNS;
336 if (ConfigReadInt(_T("CheckTrustedNodes"), 1))
337 g_flags |= AF_CHECK_TRUSTED_NODES;
338 if (ConfigReadInt(_T("EnableNXSLContainerFunctions"), 1))
339 g_flags |= AF_ENABLE_NXSL_CONTAINER_FUNCS;
340 if (ConfigReadInt(_T("UseFQDNForNodeNames"), 1))
341 g_flags |= AF_USE_FQDN_FOR_NODE_NAMES;
342 if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 1))
343 g_flags |= AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE;
344 if (ConfigReadInt(_T("ResolveDNSToIPOnStatusPoll"), 0))
345 g_flags |= AF_RESOLVE_IP_FOR_EACH_STATUS_POLL;
346 if (ConfigReadInt(_T("CaseInsensitiveLoginNames"), 0))
347 g_flags |= AF_CASE_INSENSITIVE_LOGINS;
348 if (ConfigReadInt(_T("TrapSourcesInAllZones"), 0))
349 g_flags |= AF_TRAP_SOURCES_IN_ALL_ZONES;
350
351 if (g_netxmsdDataDir[0] == 0)
352 {
353 GetNetXMSDirectory(nxDirData, g_netxmsdDataDir);
354 DbgPrintf(1, _T("Data directory set to %s"), g_netxmsdDataDir);
355 }
356 else
357 {
358 DbgPrintf(1, _T("Using data directory %s"), g_netxmsdDataDir);
359 }
360
361 g_icmpPingTimeout = ConfigReadInt(_T("IcmpPingTimeout"), 1500);
362 g_icmpPingSize = ConfigReadInt(_T("IcmpPingSize"), 46);
363 g_lockTimeout = ConfigReadInt(_T("LockTimeout"), 60000);
364 g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000);
365 g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
366 g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
367 g_offlineDataRelevanceTime = ConfigReadInt(_T("OfflineDataRelevanceTime"), 86400);
368
369 UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 1500);
370 SnmpSetDefaultTimeout(snmpTimeout);
371 }
372
373 /**
374 * Initialize cryptografic functions
375 */
376 static BOOL InitCryptografy()
377 {
378 #ifdef _WITH_ENCRYPTION
379 BOOL bResult = FALSE;
380
381 if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F)))
382 return FALSE;
383 nxlog_debug(4, _T("Supported ciphers: %s"), (const TCHAR *)NXCPGetSupportedCiphersAsText());
384
385 SSL_library_init();
386 SSL_load_error_strings();
387
388 TCHAR szKeyFile[MAX_PATH];
389 _tcscpy(szKeyFile, g_netxmsdDataDir);
390 _tcscat(szKeyFile, DFILE_KEYS);
391 g_pServerKey = LoadRSAKeys(szKeyFile);
392 if (g_pServerKey == NULL)
393 {
394 nxlog_debug(1, _T("Generating RSA key pair..."));
395 g_pServerKey = RSA_generate_key(NETXMS_RSA_KEYLEN, 17, NULL, 0);
396 if (g_pServerKey != NULL)
397 {
398 int fd = _topen(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600);
399 if (fd != -1)
400 {
401 UINT32 dwLen = i2d_RSAPublicKey(g_pServerKey, NULL);
402 dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
403 BYTE *pKeyBuffer = (BYTE *)malloc(dwLen);
404
405 BYTE *pBufPos = pKeyBuffer;
406 i2d_RSAPublicKey(g_pServerKey, &pBufPos);
407 i2d_RSAPrivateKey(g_pServerKey, &pBufPos);
408 write(fd, &dwLen, sizeof(UINT32));
409 write(fd, pKeyBuffer, dwLen);
410
411 BYTE hash[SHA1_DIGEST_SIZE];
412 CalculateSHA1Hash(pKeyBuffer, dwLen, hash);
413 write(fd, hash, SHA1_DIGEST_SIZE);
414
415 close(fd);
416 free(pKeyBuffer);
417 bResult = TRUE;
418 }
419 else
420 {
421 nxlog_debug(0, _T("Failed to open %s for writing"), szKeyFile);
422 }
423 }
424 else
425 {
426 nxlog_debug(0, _T("Failed to generate RSA key"));
427 }
428 }
429 else
430 {
431 bResult = TRUE;
432 }
433
434 int iPolicy = ConfigReadInt(_T("DefaultEncryptionPolicy"), 1);
435 if ((iPolicy < 0) || (iPolicy > 3))
436 iPolicy = 1;
437 SetAgentDEP(iPolicy);
438
439 return bResult;
440 #else
441 return TRUE;
442 #endif
443 }
444
445 /**
446 * Check if process with given PID exists and is a NetXMS server process
447 */
448 static bool IsNetxmsdProcess(UINT32 pid)
449 {
450 #ifdef _WIN32
451 bool result = false;
452 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
453 if (hProcess != NULL)
454 {
455 TCHAR szExtModule[MAX_PATH], szIntModule[MAX_PATH];
456 if ((GetModuleBaseName(hProcess, NULL, szExtModule, MAX_PATH) > 0) &&
457 (GetModuleBaseName(GetCurrentProcess(), NULL, szIntModule, MAX_PATH) > 0))
458 {
459 result = (_tcsicmp(szExtModule, szIntModule) == 0);
460 }
461 else
462 {
463 // Cannot read process name, for safety assume that it's a server process
464 result = true;
465 }
466 CloseHandle(hProcess);
467 }
468 return result;
469 #else
470 return kill((pid_t)pid, 0) != -1;
471 #endif
472 }
473
474 /**
475 * Check if remote netxmsd is running
476 */
477 static bool PeerNodeIsRunning(const InetAddress& addr)
478 {
479 bool result = false;
480
481 TCHAR keyFile[MAX_PATH];
482 _tcscpy(keyFile, g_netxmsdDataDir);
483 _tcscat(keyFile, DFILE_KEYS);
484 RSA *key = LoadRSAKeys(keyFile);
485
486 AgentConnection *ac = new AgentConnection(addr);
487 if (ac->connect(key))
488 {
489 TCHAR result[MAX_RESULT_LENGTH];
490 #ifdef _WIN32
491 UINT32 rcc = ac->getParameter(_T("Process.Count(netxmsd.exe)"), MAX_RESULT_LENGTH, result);
492 #else
493 UINT32 rcc = ac->getParameter(_T("Process.Count(netxmsd)"), MAX_RESULT_LENGTH, result);
494 #endif
495 ac->decRefCount();
496 if (key != NULL)
497 RSA_free(key);
498 if (rcc == ERR_SUCCESS)
499 {
500 return _tcstol(result, NULL, 10) > 0;
501 }
502 }
503 else
504 {
505 ac->decRefCount();
506 if (key != NULL)
507 RSA_free(key);
508 }
509
510 UINT16 port = (UINT16)ConfigReadInt(_T("ClientListenerPort"), SERVER_LISTEN_PORT_FOR_CLIENTS);
511 SOCKET s = ConnectToHost(addr, port, 5000);
512 if (s != INVALID_SOCKET)
513 {
514 shutdown(s, SHUT_RDWR);
515 closesocket(s);
516 result = true;
517 }
518 return result;
519 }
520
521 /**
522 * Database event handler
523 */
524 static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, bool connLost, void *userArg)
525 {
526 if (!(g_flags & AF_SERVER_INITIALIZED))
527 return; // Don't try to do anything if server is not ready yet
528
529 switch(dwEvent)
530 {
531 case DBEVENT_CONNECTION_LOST:
532 PostEvent(EVENT_DB_CONNECTION_LOST, g_dwMgmtNode, NULL);
533 g_flags |= AF_DB_CONNECTION_LOST;
534 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, FALSE);
535 break;
536 case DBEVENT_CONNECTION_RESTORED:
537 PostEvent(EVENT_DB_CONNECTION_RESTORED, g_dwMgmtNode, NULL);
538 g_flags &= ~AF_DB_CONNECTION_LOST;
539 NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, TRUE);
540 break;
541 case DBEVENT_QUERY_FAILED:
542 PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uud", pszArg1, pszArg2, connLost ? 1 : 0);
543 break;
544 default:
545 break;
546 }
547 }
548
549 /**
550 * Send console message to session with open console
551 */
552 static void SendConsoleMessage(ClientSession *session, void *arg)
553 {
554 if (session->isConsoleOpen())
555 {
556 NXCPMessage msg;
557
558 msg.setCode(CMD_ADM_MESSAGE);
559 msg.setField(VID_MESSAGE, (TCHAR *)arg);
560 session->postMessage(&msg);
561 }
562 }
563
564 /**
565 * Console writer
566 */
567 static void LogConsoleWriter(const TCHAR *format, ...)
568 {
569 TCHAR buffer[8192];
570 va_list args;
571
572 va_start(args, format);
573 _vsntprintf(buffer, 8192, format, args);
574 buffer[8191] = 0;
575 va_end(args);
576
577 WriteToTerminal(buffer);
578
579 EnumerateClientSessions(SendConsoleMessage, buffer);
580 }
581
582 /**
583 * Oracle session init callback
584 */
585 static void OracleSessionInitCallback(DB_HANDLE hdb)
586 {
587 DBQuery(hdb, _T("ALTER SESSION SET DDL_LOCK_TIMEOUT = 60"));
588 }
589
590 /**
591 * Server initialization
592 */
593 BOOL NXCORE_EXPORTABLE Initialize()
594 {
595 s_components.add(_T("CORE"));
596
597 g_serverStartTime = time(NULL);
598 srand((unsigned int)g_serverStartTime);
599
600 if (!(g_flags & AF_USE_SYSLOG))
601 {
602 if (!nxlog_set_rotation_policy((int)g_logRotationMode, g_maxLogSize, (int)g_logHistorySize, g_szDailyLogFileSuffix))
603 if (!(g_flags & AF_DAEMON))
604 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
605 }
606 if (!nxlog_open((g_flags & AF_USE_SYSLOG) ? NETXMSD_SYSLOG_NAME : g_szLogFile,
607 ((g_flags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
608 ((g_flags & AF_BACKGROUND_LOG_WRITER) ? NXLOG_BACKGROUND_WRITER : 0) |
609 ((g_flags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
610 _T("LIBNXSRV.DLL"),
611 #ifdef _WIN32
612 0, NULL, MSG_DEBUG))
613 #else
614 g_dwNumMessages, g_szMessages, MSG_DEBUG))
615 #endif
616 {
617 _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
618 return FALSE;
619 }
620 nxlog_set_console_writer(LogConsoleWriter);
621
622 if (g_netxmsdLibDir[0] == 0)
623 {
624 GetNetXMSDirectory(nxDirLib, g_netxmsdLibDir);
625 nxlog_debug(1, _T("LIB directory set to %s"), g_netxmsdLibDir);
626 }
627
628 // Set code page
629 #ifndef _WIN32
630 if (SetDefaultCodepage(g_szCodePage))
631 {
632 DbgPrintf(1, _T("Code page set to %hs"), g_szCodePage);
633 }
634 else
635 {
636 nxlog_write(MSG_CODEPAGE_ERROR, EVENTLOG_WARNING_TYPE, "m", g_szCodePage);
637 }
638 #endif
639
640 // Set process affinity mask
641 if (g_processAffinityMask != DEFAULT_AFFINITY_MASK)
642 {
643 #ifdef _WIN32
644 if (SetProcessAffinityMask(GetCurrentProcess(), g_processAffinityMask))
645 nxlog_debug(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask);
646 #else
647 nxlog_write(MSG_SET_PROCESS_AFFINITY_NOT_SUPPORTED, EVENTLOG_WARNING_TYPE, NULL);
648 #endif
649 }
650
651 #ifdef _WIN32
652 WSADATA wsaData;
653 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
654 if (wrc != 0)
655 {
656 nxlog_write(MSG_WSASTARTUP_FAILED, EVENTLOG_ERROR_TYPE, "e", wrc);
657 return FALSE;
658 }
659 #endif
660
661 InitLocalNetInfo();
662 SnmpSetMessageIds(MSG_OID_PARSE_ERROR, MSG_SNMP_UNKNOWN_TYPE, MSG_SNMP_GET_ERROR);
663
664 // Create queue for delayed SQL queries
665 g_dbWriterQueue = new Queue(256, 64);
666 g_dciDataWriterQueue = new Queue(1024, 1024);
667 g_dciRawDataWriterQueue = new Queue(1024, 1024);
668
669 // Initialize database driver and connect to database
670 if (!DBInit(MSG_OTHER, (g_flags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0))
671 return FALSE;
672 g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (nxlog_get_debug_level() >= 9), DBEventHandler, NULL);
673 if (g_dbDriver == NULL)
674 return FALSE;
675
676 // Connect to database
677 DB_HANDLE hdbBootstrap = NULL;
678 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
679 for(int i = 0; ; i++)
680 {
681 hdbBootstrap = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText);
682 if ((hdbBootstrap != NULL) || (i == 5))
683 break;
684 ThreadSleep(5);
685 }
686 if (hdbBootstrap == NULL)
687 {
688 nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, "s", errorText);
689 return FALSE;
690 }
691 nxlog_debug(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer);
692
693 // Check database schema version
694 int schemaVersion = DBGetSchemaVersion(hdbBootstrap);
695 if (schemaVersion != DB_FORMAT_VERSION)
696 {
697 nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", schemaVersion, DB_FORMAT_VERSION);
698 DBDisconnect(hdbBootstrap);
699 return FALSE;
700 }
701
702 // Read database syntax
703 g_dbSyntax = DBGetSyntax(hdbBootstrap);
704 if (g_dbSyntax == DB_SYNTAX_ORACLE)
705 {
706 DBSetSessionInitCallback(OracleSessionInitCallback);
707 }
708
709 int baseSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolBaseSize"), 10);
710 int maxSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxSize"), 30);
711 int cooldownTime = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolCooldownTime"), 300);
712 int ttl = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxLifetime"), 14400);
713
714 DBDisconnect(hdbBootstrap);
715
716 if (!DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, ttl))
717 {
718 nxlog_write(MSG_DBCONNPOOL_INIT_FAILED, EVENTLOG_ERROR_TYPE, NULL);
719 return FALSE;
720 }
721
722 UINT32 lrt = ConfigReadULong(_T("LongRunningQueryThreshold"), 0);
723 if (lrt != 0)
724 DBSetLongRunningThreshold(lrt);
725
726 MetaDataPreLoad();
727
728 // Read server ID
729 TCHAR buffer[256];
730 MetaDataReadStr(_T("ServerID"), buffer, 256, _T(""));
731 StrStrip(buffer);
732 if (buffer[0] != 0)
733 {
734 g_serverId = _tcstoull(buffer, NULL, 16);
735 }
736 else
737 {
738 // Generate new ID
739 g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF);
740 _sntprintf(buffer, 256, UINT64X_FMT(_T("016")), g_serverId);
741 MetaDataWriteStr(_T("ServerID"), buffer);
742 }
743 nxlog_debug(1, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
744
745 // Initialize locks
746 retry_db_lock:
747 InetAddress addr;
748 if (!InitLocks(&addr, buffer))
749 {
750 if (addr.isValidUnicast()) // Database already locked by another server instance
751 {
752 // Check for lock from crashed/terminated local process
753 if (GetLocalIpAddr().equals(addr))
754 {
755 UINT32 pid = ConfigReadULong(_T("DBLockPID"), 0);
756 if (!IsNetxmsdProcess(pid) || (pid == GetCurrentProcessId()))
757 {
758 UnlockDB();
759 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
760 goto retry_db_lock;
761 }
762 }
763 else if (g_peerNodeAddrList.hasAddress(addr))
764 {
765 if (!PeerNodeIsRunning(addr))
766 {
767 UnlockDB();
768 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
769 goto retry_db_lock;
770 }
771 }
772 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "As", &addr, buffer);
773 }
774 else
775 {
776 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
777 }
778 return FALSE;
779 }
780 g_flags |= AF_DB_LOCKED;
781
782 // Load global configuration parameters
783 LoadGlobalConfig();
784 CASReadSettings();
785 nxlog_debug(1, _T("Global configuration loaded"));
786
787 // Check data directory
788 if (!CheckDataDir())
789 return FALSE;
790
791 // Initialize cryptografy
792 if (!InitCryptografy())
793 {
794 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
795 return FALSE;
796 }
797
798 // Initialize certificate store and CA
799 InitCertificates();
800
801 // Create synchronization stuff
802 m_condShutdown = ConditionCreate(TRUE);
803
804 // Create thread pools
805 nxlog_debug(2, _T("Creating thread pools"));
806 g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN"));
807 g_agentConnectionThreadPool = ThreadPoolCreate(4, 256, _T("AGENT"));
808
809 // Setup unique identifiers table
810 if (!InitIdTable())
811 return FALSE;
812 nxlog_debug(2, _T("ID table created"));
813
814 InitCountryList();
815 InitCurrencyList();
816
817 // Update status for unfinished jobs in job history
818 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
819 DBQuery(hdb, _T("UPDATE job_history SET status=4,failure_message='Aborted due to server shutdown or crash' WHERE status NOT IN (3,4,5)"));
820 DBConnectionPoolReleaseConnection(hdb);
821
822 // Load and compile scripts
823 LoadScripts();
824
825 // Initialize watchdog
826 WatchdogInit();
827
828 // Load modules
829 if (!LoadNetXMSModules())
830 return FALSE; // Mandatory module not loaded
831
832 // Initialize mailer and SMS sender
833 InitMailer();
834 InitSMSSender();
835
836 // Load users from database
837 InitUsers();
838 if (!LoadUsers())
839 {
840 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
841 return FALSE;
842 }
843 nxlog_debug(2, _T("User accounts loaded"));
844
845 // Initialize audit
846 InitAuditLog();
847
848 // Initialize event handling subsystem
849 if (!InitEventSubsystem())
850 return FALSE;
851
852 // Initialize alarms
853 LoadAlarmCategories();
854 if (!InitAlarmManager())
855 return FALSE;
856
857 // Initialize objects infrastructure and load objects from database
858 LoadNetworkDeviceDrivers();
859 ObjectsInit();
860 if (!LoadObjects())
861 return FALSE;
862 nxlog_debug(1, _T("Objects loaded and initialized"));
863
864 // Initialize situations
865 if (!SituationsInit())
866 return FALSE;
867 nxlog_debug(1, _T("Situations loaded and initialized"));
868
869 // Initialize and load event actions
870 if (!InitActions())
871 {
872 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
873 return FALSE;
874 }
875
876 // Initialize helpdesk link
877 SetHDLinkEntryPoints(ResolveAlarmByHDRef, TerminateAlarmByHDRef);
878 LoadHelpDeskLink();
879
880 // Initialize data collection subsystem
881 LoadPerfDataStorageDrivers();
882 if (!InitDataCollector())
883 return FALSE;
884
885 InitLogAccess();
886 FileUploadJob::init();
887 InitMappingTables();
888
889 InitClientListeners();
890 if (ConfigReadInt(_T("ImportConfigurationOnStartup"), 1))
891 ImportLocalConfiguration();
892
893 // Check if management node object presented in database
894 CheckForMgmtNode();
895 if (g_dwMgmtNode == 0)
896 {
897 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
898 return FALSE;
899 }
900
901 // Start threads
902 ThreadCreate(WatchdogThread, 0, NULL);
903 ThreadCreate(NodePoller, 0, NULL);
904 ThreadCreate(JobManagerThread, 0, NULL);
905 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
906 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
907
908 StartHouseKeeper();
909
910 // Start event processor
911 ThreadCreate(EventProcessor, 0, NULL);
912
913 // Start SNMP trapper
914 InitTraps();
915 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
916 ThreadCreate(SNMPTrapReceiver, 0, NULL);
917
918 // Start built-in syslog daemon
919 StartSyslogServer();
920
921 // Start database _T("lazy") write thread
922 StartDBWriter();
923
924 // Start local administartive interface listener if required
925 if (ConfigReadInt(_T("EnableAdminInterface"), 1))
926 ThreadCreate(LocalAdminListener, 0, NULL);
927
928 // Start beacon host poller
929 ThreadCreate(BeaconPoller, 0, NULL);
930
931 // Start inter-server communication listener
932 if (ConfigReadInt(_T("EnableISCListener"), 0))
933 ThreadCreate(ISCListener, 0, NULL);
934
935 // Start reporting server connector
936 if (ConfigReadInt(_T("EnableReportingServer"), 0))
937 ThreadCreate(ReportingServerConnector, 0, NULL);
938
939 //Start ldap synchronization
940 if (ConfigReadInt(_T("LdapSyncInterval"), 0))
941 ThreadCreate(SyncLDAPUsers, 0, NULL);
942
943 RegisterSchedulerTaskHandler(_T("Execute.Script"), ExecuteScheduledScript, SYSTEM_ACCESS_SCHEDULE_SCRIPT);
944 RegisterSchedulerTaskHandler(_T("Maintenance.Enter"), MaintenanceModeEnter, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
945 RegisterSchedulerTaskHandler(_T("Maintenance.Leave"), MaintenanceModeLeave, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
946 RegisterSchedulerTaskHandler(_T("Policy.Deploy"), ScheduleDeployPolicy, 0); //No access right beacause it will be used only by server
947 RegisterSchedulerTaskHandler(_T("Policy.Uninstall"), ScheduleUninstallPolicy, 0); //No access right beacause it will be used only by server
948 InitializeTaskScheduler();
949
950 // Allow clients to connect
951 ThreadCreate(ClientListener, 0, NULL);
952 #ifdef WITH_IPV6
953 ThreadCreate(ClientListenerIPv6, 0, NULL);
954 #endif
955
956 // Allow mobile devices to connect
957 InitMobileDeviceListeners();
958 ThreadCreate(MobileDeviceListener, 0, NULL);
959 #ifdef WITH_IPV6
960 ThreadCreate(MobileDeviceListenerIPv6, 0, NULL);
961 #endif
962
963 // Start uptime calculator for SLM
964 ThreadCreate(UptimeCalculator, 0, NULL);
965
966 nxlog_debug(2, _T("LIBDIR: %s"), g_netxmsdLibDir);
967
968 // Call startup functions for the modules
969 CALL_ALL_MODULES(pfServerStarted, ());
970
971 #if XMPP_SUPPORTED
972 if (ConfigReadInt(_T("EnableXMPPConnector"), 1))
973 {
974 StartXMPPConnector();
975 }
976 #endif
977
978 #if WITH_ZMQ
979 StartZMQConnector();
980 #endif
981
982 g_flags |= AF_SERVER_INITIALIZED;
983 nxlog_debug(1, _T("Server initialization completed"));
984 return TRUE;
985 }
986
987 /**
988 * Server shutdown
989 */
990 void NXCORE_EXPORTABLE Shutdown()
991 {
992 // Notify clients
993 NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0);
994
995 nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
996 g_flags |= AF_SHUTDOWN; // Set shutdown flag
997 ConditionSet(m_condShutdown);
998
999 CloseTaskScheduler();
1000
1001 // Stop DCI cache loading thread
1002 g_dciCacheLoaderQueue.setShutdownMode();
1003
1004 #if XMPP_SUPPORTED
1005 StopXMPPConnector();
1006 #endif
1007
1008 #if WITH_ZMQ
1009 StopZMQConnector();
1010 #endif
1011
1012 g_pEventQueue->clear();
1013 g_pEventQueue->put(INVALID_POINTER_VALUE);
1014
1015 ShutdownMailer();
1016 ShutdownSMSSender();
1017
1018 ThreadSleep(1); // Give other threads a chance to terminate in a safe way
1019 nxlog_debug(2, _T("All threads was notified, continue with shutdown"));
1020
1021 StopSyslogServer();
1022 StopHouseKeeper();
1023
1024 // Wait for critical threads
1025 ThreadJoin(m_thPollManager);
1026 ThreadJoin(m_thSyncer);
1027
1028 // Call shutdown functions for the modules
1029 // CALL_ALL_MODULES cannot be used here because it checks for shutdown flag
1030 for(UINT32 i = 0; i < g_dwNumModules; i++)
1031 {
1032 if (g_pModuleList[i].pfShutdown != NULL)
1033 g_pModuleList[i].pfShutdown();
1034 }
1035
1036 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1037 SaveObjects(hdb);
1038 nxlog_debug(2, _T("All objects saved to database"));
1039 SaveUsers(hdb);
1040 nxlog_debug(2, _T("All users saved to database"));
1041 DBConnectionPoolReleaseConnection(hdb);
1042
1043 StopDBWriter();
1044 nxlog_debug(1, _T("Database writer stopped"));
1045
1046 CleanupUsers();
1047
1048 // Remove database lock
1049 UnlockDB();
1050
1051 DBConnectionPoolShutdown();
1052 DBUnloadDriver(g_dbDriver);
1053 nxlog_debug(1, _T("Database driver unloaded"));
1054
1055 CleanupActions();
1056 ShutdownEventSubsystem();
1057 ShutdownAlarmManager();
1058 nxlog_debug(1, _T("Event processing stopped"));
1059
1060 ThreadPoolDestroy(g_agentConnectionThreadPool);
1061 ThreadPoolDestroy(g_mainThreadPool);
1062 MsgWaitQueue::shutdown();
1063
1064 delete g_pScriptLibrary;
1065
1066 nxlog_debug(1, _T("Server shutdown complete"));
1067 nxlog_close();
1068
1069 // Remove PID file
1070 #ifndef _WIN32
1071 _tremove(g_szPIDFile);
1072 #endif
1073
1074 // Terminate process
1075 #ifdef _WIN32
1076 if (!(g_flags & AF_DAEMON))
1077 ExitProcess(0);
1078 #else
1079 exit(0);
1080 #endif
1081 }
1082
1083 /**
1084 * Fast server shutdown - normally called only by Windows service on system shutdown
1085 */
1086 void NXCORE_EXPORTABLE FastShutdown()
1087 {
1088 DbgPrintf(1, _T("Using fast shutdown procedure"));
1089
1090 g_flags |= AF_SHUTDOWN; // Set shutdown flag
1091 ConditionSet(m_condShutdown);
1092
1093 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1094 SaveObjects(hdb);
1095 DbgPrintf(2, _T("All objects saved to database"));
1096 SaveUsers(hdb);
1097 DbgPrintf(2, _T("All users saved to database"));
1098 DBConnectionPoolReleaseConnection(hdb);
1099
1100 // Remove database lock first, because we have a chance to lose DB connection
1101 UnlockDB();
1102
1103 // Stop database writers
1104 StopDBWriter();
1105 DbgPrintf(1, _T("Database writer stopped"));
1106
1107 DbgPrintf(1, _T("Server shutdown complete"));
1108 nxlog_close();
1109 }
1110
1111 /**
1112 * Signal handler for UNIX platforms
1113 */
1114 #ifndef _WIN32
1115
1116 void SignalHandlerStub(int nSignal)
1117 {
1118 // should be unused, but JIC...
1119 if (nSignal == SIGCHLD)
1120 {
1121 while (waitpid(-1, NULL, WNOHANG) > 0)
1122 ;
1123 }
1124 }
1125
1126 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
1127 {
1128 sigset_t signals;
1129 int nSignal;
1130
1131 m_signalHandlerThread = pthread_self();
1132
1133 // default for SIGCHLD: ignore
1134 signal(SIGCHLD, &SignalHandlerStub);
1135
1136 sigemptyset(&signals);
1137 sigaddset(&signals, SIGTERM);
1138 sigaddset(&signals, SIGINT);
1139 sigaddset(&signals, SIGSEGV);
1140 sigaddset(&signals, SIGCHLD);
1141 sigaddset(&signals, SIGHUP);
1142 sigaddset(&signals, SIGUSR1);
1143 sigaddset(&signals, SIGUSR2);
1144 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
1145 sigaddset(&signals, SIGPIPE);
1146 #endif
1147
1148 sigprocmask(SIG_BLOCK, &signals, NULL);
1149
1150 while(1)
1151 {
1152 if (sigwait(&signals, &nSignal) == 0)
1153 {
1154 switch(nSignal)
1155 {
1156 case SIGTERM:
1157 case SIGINT:
1158 // avoid repeat Shutdown() call
1159 if (!(g_flags & AF_SHUTDOWN))
1160 {
1161 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
1162 if (IsStandalone())
1163 Shutdown(); // will never return
1164 else
1165 ConditionSet(m_condShutdown);
1166 }
1167 break;
1168 case SIGSEGV:
1169 abort();
1170 break;
1171 case SIGCHLD:
1172 while (waitpid(-1, NULL, WNOHANG) > 0)
1173 ;
1174 break;
1175 case SIGUSR1:
1176 if (g_flags & AF_SHUTDOWN)
1177 goto stop_handler;
1178 break;
1179 default:
1180 break;
1181 }
1182 }
1183 else
1184 {
1185 ThreadSleepMs(100);
1186 }
1187 }
1188
1189 stop_handler:
1190 sigprocmask(SIG_UNBLOCK, &signals, NULL);
1191 return THREAD_OK;
1192 }
1193
1194 #endif
1195
1196 /**
1197 * Common main()
1198 */
1199 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
1200 {
1201 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
1202
1203 if (IsStandalone())
1204 {
1205 if (!(g_flags & AF_DEBUG_CONSOLE_DISABLED))
1206 {
1207 char *ptr, szCommand[256];
1208 struct __console_ctx ctx;
1209 #ifdef UNICODE
1210 WCHAR wcCommand[256];
1211 #endif
1212
1213 ctx.hSocket = -1;
1214 ctx.socketMutex = INVALID_MUTEX_HANDLE;
1215 ctx.pMsg = NULL;
1216 ctx.session = NULL;
1217 ctx.output = NULL;
1218 WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T(" Ready\n")
1219 _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n")
1220 _T("System Console\n\n"));
1221
1222 #if USE_READLINE
1223 // Initialize readline library if we use it
1224 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
1225 #endif
1226
1227 while(1)
1228 {
1229 #if USE_READLINE
1230 ptr = readline("\x1b[33mnetxmsd:\x1b[0m ");
1231 #else
1232 WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m "));
1233 fflush(stdout);
1234 if (fgets(szCommand, 255, stdin) == NULL)
1235 break; // Error reading stdin
1236 ptr = strchr(szCommand, '\n');
1237 if (ptr != NULL)
1238 *ptr = 0;
1239 ptr = szCommand;
1240 #endif
1241
1242 if (ptr != NULL)
1243 {
1244 #ifdef UNICODE
1245 #if HAVE_MBSTOWCS
1246 mbstowcs(wcCommand, ptr, 255);
1247 #else
1248 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
1249 #endif
1250 wcCommand[255] = 0;
1251 StrStrip(wcCommand);
1252 if (wcCommand[0] != 0)
1253 {
1254 if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN)
1255 #else
1256 StrStrip(ptr);
1257 if (*ptr != 0)
1258 {
1259 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
1260 #endif
1261 break;
1262 #if USE_READLINE
1263 add_history(ptr);
1264 #endif
1265 }
1266 #if USE_READLINE
1267 free(ptr);
1268 #endif
1269 }
1270 else
1271 {
1272 _tprintf(_T("\n"));
1273 }
1274 }
1275
1276 #if USE_READLINE
1277 free(ptr);
1278 #endif
1279 if (!(g_flags & AF_SHUTDOWN))
1280 {
1281 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
1282 Shutdown();
1283 }
1284 }
1285 else
1286 {
1287 // standalone with debug console disabled
1288 #ifdef _WIN32
1289 _tprintf(_T("Server running. Press ESC to shutdown.\n"));
1290 while(1)
1291 {
1292 if (_getch() == 27)
1293 break;
1294 }
1295 _tprintf(_T("Server shutting down...\n"));
1296 Shutdown();
1297 #else
1298 _tprintf(_T("Server running. Press Ctrl+C to shutdown.\n"));
1299 // Shutdown will be called from signal handler
1300 ConditionWait(m_condShutdown, INFINITE);
1301 #endif
1302 }
1303 }
1304 else
1305 {
1306 ConditionWait(m_condShutdown, INFINITE);
1307 // On Win32, Shutdown() will be called by service control handler
1308 #ifndef _WIN32
1309 Shutdown();
1310 #endif
1311 }
1312 return THREAD_OK;
1313 }
1314
1315 /**
1316 * Initiate server shutdown
1317 */
1318 void InitiateShutdown()
1319 {
1320 #ifdef _WIN32
1321 Shutdown();
1322 #else
1323 if (IsStandalone())
1324 {
1325 Shutdown();
1326 }
1327 else
1328 {
1329 pthread_kill(m_signalHandlerThread, SIGTERM);
1330 }
1331 #endif
1332 }
1333
1334 /**
1335 *DLL Entry point
1336 */
1337 #ifdef _WIN32
1338
1339 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
1340 {
1341 if (dwReason == DLL_PROCESS_ATTACH)
1342 DisableThreadLibraryCalls(hInstance);
1343 return TRUE;
1344 }
1345
1346 #endif