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