fixed Windows build error
[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_OTHER))
644 #else
645 g_dwNumMessages, g_szMessages, MSG_DEBUG, 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 DBSetLongRunningThreshold(lrt);
763
764 MetaDataPreLoad();
765
766 // Read server ID
767 TCHAR buffer[256];
768 MetaDataReadStr(_T("ServerID"), buffer, 256, _T(""));
769 StrStrip(buffer);
770 if (buffer[0] != 0)
771 {
772 g_serverId = _tcstoull(buffer, NULL, 16);
773 }
774 else
775 {
776 // Generate new ID
777 g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF);
778 _sntprintf(buffer, 256, UINT64X_FMT(_T("016")), g_serverId);
779 MetaDataWriteStr(_T("ServerID"), buffer);
780 }
781 nxlog_debug(1, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
782
783 // Initialize locks
784 retry_db_lock:
785 InetAddress addr;
786 if (!InitLocks(&addr, buffer))
787 {
788 if (addr.isValidUnicast()) // Database already locked by another server instance
789 {
790 // Check for lock from crashed/terminated local process
791 if (GetLocalIpAddr().equals(addr))
792 {
793 UINT32 pid = ConfigReadULong(_T("DBLockPID"), 0);
794 if (!IsNetxmsdProcess(pid) || (pid == GetCurrentProcessId()))
795 {
796 UnlockDB();
797 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
798 goto retry_db_lock;
799 }
800 }
801 else if (g_peerNodeAddrList.hasAddress(addr))
802 {
803 if (!PeerNodeIsRunning(addr))
804 {
805 UnlockDB();
806 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
807 goto retry_db_lock;
808 }
809 }
810 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "Is", &addr, buffer);
811 }
812 else
813 {
814 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
815 }
816 return FALSE;
817 }
818 g_flags |= AF_DB_LOCKED;
819
820 // Load global configuration parameters
821 LoadGlobalConfig();
822 CASReadSettings();
823 nxlog_debug(1, _T("Global configuration loaded"));
824
825 // Check data directory
826 if (!CheckDataDir())
827 return FALSE;
828
829 // Initialize cryptografy
830 if (!InitCryptografy())
831 {
832 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
833 return FALSE;
834 }
835
836 // Initialize certificate store and CA
837 InitCertificates();
838
839 // Create synchronization stuff
840 m_condShutdown = ConditionCreate(TRUE);
841
842 // Create thread pools
843 nxlog_debug(2, _T("Creating thread pools"));
844 g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN"));
845 g_agentConnectionThreadPool = ThreadPoolCreate(4, 256, _T("AGENT"));
846
847 // Setup unique identifiers table
848 if (!InitIdTable())
849 return FALSE;
850 nxlog_debug(2, _T("ID table created"));
851
852 InitCountryList();
853 InitCurrencyList();
854
855 // Update status for unfinished jobs in job history
856 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
857 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)"));
858 DBConnectionPoolReleaseConnection(hdb);
859
860 // Load and compile scripts
861 LoadScripts();
862
863 // Initialize persistent storage
864 PersistentStorageInit();
865
866 // Initialize watchdog
867 WatchdogInit();
868
869 // Load modules
870 if (!LoadNetXMSModules())
871 return FALSE; // Mandatory module not loaded
872 RegisterPredictionEngines();
873
874 // Initialize mailer and SMS sender
875 InitMailer();
876 InitSMSSender();
877
878 // Load users from database
879 InitUsers();
880 if (!LoadUsers())
881 {
882 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
883 return FALSE;
884 }
885 nxlog_debug(2, _T("User accounts loaded"));
886
887 // Initialize audit
888 InitAuditLog();
889
890 // Initialize event handling subsystem
891 if (!InitEventSubsystem())
892 return FALSE;
893
894 // Initialize alarms
895 LoadAlarmCategories();
896 if (!InitAlarmManager())
897 return FALSE;
898
899 // Initialize objects infrastructure and load objects from database
900 LoadNetworkDeviceDrivers();
901 ObjectsInit();
902 if (!LoadObjects())
903 return FALSE;
904 nxlog_debug(1, _T("Objects loaded and initialized"));
905
906 // Initialize and load event actions
907 if (!InitActions())
908 {
909 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
910 return FALSE;
911 }
912
913 // Initialize helpdesk link
914 SetHDLinkEntryPoints(ResolveAlarmByHDRef, TerminateAlarmByHDRef);
915 LoadHelpDeskLink();
916
917 // Initialize data collection subsystem
918 LoadPerfDataStorageDrivers();
919 if (!InitDataCollector())
920 return FALSE;
921
922 InitLogAccess();
923 FileUploadJob::init();
924 InitMappingTables();
925
926 InitClientListeners();
927 if (ConfigReadInt(_T("ImportConfigurationOnStartup"), 1))
928 ImportLocalConfiguration();
929
930 // Check if management node object presented in database
931 CheckForMgmtNode();
932 if (g_dwMgmtNode == 0)
933 {
934 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
935 return FALSE;
936 }
937
938 // Start threads
939 ThreadCreate(WatchdogThread, 0, NULL);
940 ThreadCreate(NodePoller, 0, NULL);
941 ThreadCreate(JobManagerThread, 0, NULL);
942 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
943 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
944
945 StartHouseKeeper();
946
947 // Start event processor
948 ThreadCreate(EventProcessor, 0, NULL);
949
950 // Start SNMP trapper
951 InitTraps();
952 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
953 ThreadCreate(SNMPTrapReceiver, 0, NULL);
954
955 // Start built-in syslog daemon
956 StartSyslogServer();
957
958 // Start database _T("lazy") write thread
959 StartDBWriter();
960
961 // Start beacon host poller
962 ThreadCreate(BeaconPoller, 0, NULL);
963
964 // Start inter-server communication listener
965 if (ConfigReadInt(_T("EnableISCListener"), 0))
966 ThreadCreate(ISCListener, 0, NULL);
967
968 // Start reporting server connector
969 if (ConfigReadInt(_T("EnableReportingServer"), 0))
970 ThreadCreate(ReportingServerConnector, 0, NULL);
971
972 //Start ldap synchronization
973 if (ConfigReadInt(_T("LdapSyncInterval"), 0))
974 ThreadCreate(SyncLDAPUsers, 0, NULL);
975
976 RegisterSchedulerTaskHandler(_T("Execute.Script"), ExecuteScheduledScript, SYSTEM_ACCESS_SCHEDULE_SCRIPT);
977 RegisterSchedulerTaskHandler(_T("Maintenance.Enter"), MaintenanceModeEnter, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
978 RegisterSchedulerTaskHandler(_T("Maintenance.Leave"), MaintenanceModeLeave, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
979 RegisterSchedulerTaskHandler(_T("Policy.Deploy"), ScheduleDeployPolicy, 0); //No access right beacause it will be used only by server
980 RegisterSchedulerTaskHandler(_T("Policy.Uninstall"), ScheduleUninstallPolicy, 0); //No access right beacause it will be used only by server
981 RegisterSchedulerTaskHandler(ALARM_SUMMARY_EMAIL_TASK_ID, SendAlarmSummaryEmail, 0); //No access right beacause it will be used only by server
982 InitializeTaskScheduler();
983
984 // Send summary emails
985 if (ConfigReadInt(_T("EnableAlarmSummaryEmails"), 0))
986 EnableAlarmSummaryEmails();
987 else
988 RemoveScheduledTaskByHandlerId(ALARM_SUMMARY_EMAIL_TASK_ID);
989
990 // Allow clients to connect
991 ThreadCreate(ClientListener, 0, NULL);
992 #ifdef WITH_IPV6
993 ThreadCreate(ClientListenerIPv6, 0, NULL);
994 #endif
995
996 // Allow mobile devices to connect
997 InitMobileDeviceListeners();
998 ThreadCreate(MobileDeviceListener, 0, NULL);
999 #ifdef WITH_IPV6
1000 ThreadCreate(MobileDeviceListenerIPv6, 0, NULL);
1001 #endif
1002
1003 // Agent tunnels
1004 s_tunnelListenerThread = ThreadCreateEx(TunnelListener, 0, NULL);
1005
1006 // Start uptime calculator for SLM
1007 ThreadCreate(UptimeCalculator, 0, NULL);
1008
1009 nxlog_debug(2, _T("LIBDIR: %s"), g_netxmsdLibDir);
1010
1011 // Call startup functions for the modules
1012 CALL_ALL_MODULES(pfServerStarted, ());
1013
1014 #if XMPP_SUPPORTED
1015 if (ConfigReadInt(_T("EnableXMPPConnector"), 1))
1016 {
1017 StartXMPPConnector();
1018 }
1019 #endif
1020
1021 #if WITH_ZMQ
1022 StartZMQConnector();
1023 #endif
1024
1025 ExecuteStartupScripts();
1026
1027 g_flags |= AF_SERVER_INITIALIZED;
1028 nxlog_debug(1, _T("Server initialization completed"));
1029 return TRUE;
1030 }
1031
1032 /**
1033 * Server shutdown
1034 */
1035 void NXCORE_EXPORTABLE Shutdown()
1036 {
1037 // Notify clients
1038 NotifyClientSessions(NX_NOTIFY_SHUTDOWN, 0);
1039
1040 nxlog_write(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
1041 g_flags |= AF_SHUTDOWN; // Set shutdown flag
1042 ConditionSet(m_condShutdown);
1043
1044 CloseTaskScheduler();
1045
1046 // Stop DCI cache loading thread
1047 g_dciCacheLoaderQueue.setShutdownMode();
1048
1049 #if XMPP_SUPPORTED
1050 StopXMPPConnector();
1051 #endif
1052
1053 #if WITH_ZMQ
1054 StopZMQConnector();
1055 #endif
1056
1057 g_pEventQueue->clear();
1058 g_pEventQueue->put(INVALID_POINTER_VALUE);
1059
1060 ShutdownMailer();
1061 ShutdownSMSSender();
1062
1063 ThreadSleep(1); // Give other threads a chance to terminate in a safe way
1064 nxlog_debug(2, _T("All threads was notified, continue with shutdown"));
1065
1066 StopSyslogServer();
1067 StopHouseKeeper();
1068
1069 // Wait for critical threads
1070 ThreadJoin(m_thPollManager);
1071 ThreadJoin(m_thSyncer);
1072 ThreadJoin(s_tunnelListenerThread);
1073
1074 CloseAgentTunnels();
1075
1076 // Call shutdown functions for the modules
1077 // CALL_ALL_MODULES cannot be used here because it checks for shutdown flag
1078 for(UINT32 i = 0; i < g_dwNumModules; i++)
1079 {
1080 if (g_pModuleList[i].pfShutdown != NULL)
1081 g_pModuleList[i].pfShutdown();
1082 }
1083
1084 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1085 SaveObjects(hdb, INVALID_INDEX);
1086 nxlog_debug(2, _T("All objects saved to database"));
1087 SaveUsers(hdb, INVALID_INDEX);
1088 nxlog_debug(2, _T("All users saved to database"));
1089 UpdatePStorageDatabase(hdb, INVALID_INDEX);
1090 nxlog_debug(2, _T("All persistent storage values saved"));
1091 DBConnectionPoolReleaseConnection(hdb);
1092
1093 StopDBWriter();
1094 nxlog_debug(1, _T("Database writer stopped"));
1095
1096 CleanupUsers();
1097 PersistentStorageDestroy();
1098
1099 // Remove database lock
1100 UnlockDB();
1101
1102 DBConnectionPoolShutdown();
1103 DBUnloadDriver(g_dbDriver);
1104 nxlog_debug(1, _T("Database driver unloaded"));
1105
1106 CleanupActions();
1107 ShutdownEventSubsystem();
1108 ShutdownAlarmManager();
1109 nxlog_debug(1, _T("Event processing stopped"));
1110
1111 ThreadPoolDestroy(g_agentConnectionThreadPool);
1112 ThreadPoolDestroy(g_mainThreadPool);
1113 MsgWaitQueue::shutdown();
1114 WatchdogShutdown();
1115
1116 nxlog_debug(1, _T("Server shutdown complete"));
1117 nxlog_close();
1118
1119 // Remove PID file
1120 #ifndef _WIN32
1121 _tremove(g_szPIDFile);
1122 #endif
1123
1124 // Terminate process
1125 #ifdef _WIN32
1126 if (!(g_flags & AF_DAEMON))
1127 ExitProcess(0);
1128 #else
1129 exit(0);
1130 #endif
1131 }
1132
1133 /**
1134 * Fast server shutdown - normally called only by Windows service on system shutdown
1135 */
1136 void NXCORE_EXPORTABLE FastShutdown()
1137 {
1138 DbgPrintf(1, _T("Using fast shutdown procedure"));
1139
1140 g_flags |= AF_SHUTDOWN; // Set shutdown flag
1141 ConditionSet(m_condShutdown);
1142
1143 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1144 SaveObjects(hdb, INVALID_INDEX);
1145 DbgPrintf(2, _T("All objects saved to database"));
1146 SaveUsers(hdb, INVALID_INDEX);
1147 DbgPrintf(2, _T("All users saved to database"));
1148 UpdatePStorageDatabase(hdb, INVALID_INDEX);
1149 DbgPrintf(2, _T("All persistent storage values saved"));
1150 DBConnectionPoolReleaseConnection(hdb);
1151
1152 // Remove database lock first, because we have a chance to lose DB connection
1153 UnlockDB();
1154
1155 // Stop database writers
1156 StopDBWriter();
1157 DbgPrintf(1, _T("Database writer stopped"));
1158
1159 DbgPrintf(1, _T("Server shutdown complete"));
1160 nxlog_close();
1161 }
1162
1163 /**
1164 * Signal handler for UNIX platforms
1165 */
1166 #ifndef _WIN32
1167
1168 void SignalHandlerStub(int nSignal)
1169 {
1170 // should be unused, but JIC...
1171 if (nSignal == SIGCHLD)
1172 {
1173 while (waitpid(-1, NULL, WNOHANG) > 0)
1174 ;
1175 }
1176 }
1177
1178 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
1179 {
1180 sigset_t signals;
1181 int nSignal;
1182
1183 m_signalHandlerThread = pthread_self();
1184
1185 // default for SIGCHLD: ignore
1186 signal(SIGCHLD, &SignalHandlerStub);
1187
1188 sigemptyset(&signals);
1189 sigaddset(&signals, SIGTERM);
1190 sigaddset(&signals, SIGINT);
1191 sigaddset(&signals, SIGSEGV);
1192 sigaddset(&signals, SIGCHLD);
1193 sigaddset(&signals, SIGHUP);
1194 sigaddset(&signals, SIGUSR1);
1195 sigaddset(&signals, SIGUSR2);
1196 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
1197 sigaddset(&signals, SIGPIPE);
1198 #endif
1199
1200 sigprocmask(SIG_BLOCK, &signals, NULL);
1201
1202 while(1)
1203 {
1204 if (sigwait(&signals, &nSignal) == 0)
1205 {
1206 switch(nSignal)
1207 {
1208 case SIGTERM:
1209 case SIGINT:
1210 // avoid repeat Shutdown() call
1211 if (!(g_flags & AF_SHUTDOWN))
1212 {
1213 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
1214 if (IsStandalone())
1215 Shutdown(); // will never return
1216 else
1217 ConditionSet(m_condShutdown);
1218 }
1219 break;
1220 case SIGSEGV:
1221 abort();
1222 break;
1223 case SIGCHLD:
1224 while (waitpid(-1, NULL, WNOHANG) > 0)
1225 ;
1226 break;
1227 case SIGUSR1:
1228 if (g_flags & AF_SHUTDOWN)
1229 goto stop_handler;
1230 break;
1231 default:
1232 break;
1233 }
1234 }
1235 else
1236 {
1237 ThreadSleepMs(100);
1238 }
1239 }
1240
1241 stop_handler:
1242 sigprocmask(SIG_UNBLOCK, &signals, NULL);
1243 return THREAD_OK;
1244 }
1245
1246 #endif
1247
1248 /**
1249 * Common main()
1250 */
1251 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
1252 {
1253 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
1254
1255 if (IsStandalone())
1256 {
1257 if (!(g_flags & AF_DEBUG_CONSOLE_DISABLED))
1258 {
1259 char *ptr, szCommand[256];
1260 struct __console_ctx ctx;
1261 #ifdef UNICODE
1262 WCHAR wcCommand[256];
1263 #endif
1264
1265 ctx.hSocket = -1;
1266 ctx.socketMutex = INVALID_MUTEX_HANDLE;
1267 ctx.pMsg = NULL;
1268 ctx.session = NULL;
1269 ctx.output = NULL;
1270 WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T(" Ready\n")
1271 _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n")
1272 _T("System Console\n\n"));
1273
1274 #if USE_READLINE
1275 // Initialize readline library if we use it
1276 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
1277 #endif
1278
1279 while(1)
1280 {
1281 #if USE_READLINE
1282 ptr = readline("\x1b[33mnetxmsd:\x1b[0m ");
1283 #else
1284 WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m "));
1285 fflush(stdout);
1286 if (fgets(szCommand, 255, stdin) == NULL)
1287 break; // Error reading stdin
1288 ptr = strchr(szCommand, '\n');
1289 if (ptr != NULL)
1290 *ptr = 0;
1291 ptr = szCommand;
1292 #endif
1293
1294 if (ptr != NULL)
1295 {
1296 #ifdef UNICODE
1297 #if HAVE_MBSTOWCS
1298 mbstowcs(wcCommand, ptr, 255);
1299 #else
1300 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
1301 #endif
1302 wcCommand[255] = 0;
1303 StrStrip(wcCommand);
1304 if (wcCommand[0] != 0)
1305 {
1306 if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN)
1307 #else
1308 StrStrip(ptr);
1309 if (*ptr != 0)
1310 {
1311 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
1312 #endif
1313 break;
1314 #if USE_READLINE
1315 add_history(ptr);
1316 #endif
1317 }
1318 #if USE_READLINE
1319 free(ptr);
1320 #endif
1321 }
1322 else
1323 {
1324 _tprintf(_T("\n"));
1325 }
1326 }
1327
1328 #if USE_READLINE
1329 free(ptr);
1330 #endif
1331 if (!(g_flags & AF_SHUTDOWN))
1332 {
1333 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
1334 Shutdown();
1335 }
1336 }
1337 else
1338 {
1339 // standalone with debug console disabled
1340 #ifdef _WIN32
1341 _tprintf(_T("Server running. Press ESC to shutdown.\n"));
1342 while(1)
1343 {
1344 if (_getch() == 27)
1345 break;
1346 }
1347 _tprintf(_T("Server shutting down...\n"));
1348 Shutdown();
1349 #else
1350 _tprintf(_T("Server running. Press Ctrl+C to shutdown.\n"));
1351 // Shutdown will be called from signal handler
1352 ConditionWait(m_condShutdown, INFINITE);
1353 #endif
1354 }
1355 }
1356 else
1357 {
1358 ConditionWait(m_condShutdown, INFINITE);
1359 // On Win32, Shutdown() will be called by service control handler
1360 #ifndef _WIN32
1361 Shutdown();
1362 #endif
1363 }
1364 return THREAD_OK;
1365 }
1366
1367 /**
1368 * Initiate server shutdown
1369 */
1370 void InitiateShutdown()
1371 {
1372 #ifdef _WIN32
1373 Shutdown();
1374 #else
1375 if (IsStandalone())
1376 {
1377 Shutdown();
1378 }
1379 else
1380 {
1381 pthread_kill(m_signalHandlerThread, SIGTERM);
1382 }
1383 #endif
1384 }
1385
1386 /**
1387 *DLL Entry point
1388 */
1389 #ifdef _WIN32
1390
1391 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
1392 {
1393 if (dwReason == DLL_PROCESS_ATTACH)
1394 DisableThreadLibraryCalls(hInstance);
1395 return TRUE;
1396 }
1397
1398 #endif