af535d4c657c100c6007634f72da4475c0acfe43
[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 void StopDataCollection();
79 void StopObjectMaintenanceThreads();
80
81 void ExecuteScheduledScript(const ScheduledTaskParameters *param);
82 void MaintenanceModeEnter(const ScheduledTaskParameters *params);
83 void MaintenanceModeLeave(const ScheduledTaskParameters *params);
84 void ScheduleDeployPolicy(const ScheduledTaskParameters *params);
85 void ScheduleUninstallPolicy(const ScheduledTaskParameters * params);
86
87 void InitCountryList();
88 void InitCurrencyList();
89
90 #if XMPP_SUPPORTED
91 void StartXMPPConnector();
92 void StopXMPPConnector();
93 #endif
94
95 /**
96 * Syslog server control
97 */
98 void StartSyslogServer();
99 void StopSyslogServer();
100
101 /**
102 * Thread functions
103 */
104 THREAD_RESULT THREAD_CALL Syncer(void *);
105 THREAD_RESULT THREAD_CALL NodePoller(void *);
106 THREAD_RESULT THREAD_CALL PollManager(void *);
107 THREAD_RESULT THREAD_CALL EventProcessor(void *);
108 THREAD_RESULT THREAD_CALL WatchdogThread(void *);
109 THREAD_RESULT THREAD_CALL ClientListenerThread(void *);
110 THREAD_RESULT THREAD_CALL MobileDeviceListenerThread(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 TunnelListenerThread(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 INT32 schemaVersionMajor, schemaVersionMinor;
733 if (!DBGetSchemaVersion(hdbBootstrap, &schemaVersionMajor, &schemaVersionMinor))
734 {
735 nxlog_write(MSG_UNABLE_TO_GET_DB_SCHEMA_VERSION, NXLOG_ERROR, NULL);
736 DBDisconnect(hdbBootstrap);
737 return FALSE;
738 }
739
740 if ((schemaVersionMajor != DB_SCHEMA_VERSION_MAJOR) || (schemaVersionMinor != DB_SCHEMA_VERSION_MINOR))
741 {
742 nxlog_write(MSG_WRONG_DB_SCHEMA_VERSION, NXLOG_ERROR, "dddd", schemaVersionMajor, schemaVersionMinor, DB_SCHEMA_VERSION_MAJOR, DB_SCHEMA_VERSION_MINOR);
743 DBDisconnect(hdbBootstrap);
744 return FALSE;
745 }
746
747 // Read database syntax
748 g_dbSyntax = DBGetSyntax(hdbBootstrap);
749 if (g_dbSyntax == DB_SYNTAX_ORACLE)
750 {
751 DBSetSessionInitCallback(OracleSessionInitCallback);
752 }
753
754 int baseSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolBaseSize"), 10);
755 int maxSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxSize"), 30);
756 int cooldownTime = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolCooldownTime"), 300);
757 int ttl = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxLifetime"), 14400);
758
759 DBDisconnect(hdbBootstrap);
760
761 if (!DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, ttl))
762 {
763 nxlog_write(MSG_DBCONNPOOL_INIT_FAILED, EVENTLOG_ERROR_TYPE, NULL);
764 return FALSE;
765 }
766
767 UINT32 lrt = ConfigReadULong(_T("LongRunningQueryThreshold"), 0);
768 if (lrt != 0)
769 {
770 DBSetLongRunningThreshold(lrt);
771 nxlog_write_generic(NXLOG_INFO, _T("Long running query threshold set at %d milliseconds"), lrt);
772 }
773
774 MetaDataPreLoad();
775
776 // Read server ID
777 TCHAR buffer[256];
778 MetaDataReadStr(_T("ServerID"), buffer, 256, _T(""));
779 StrStrip(buffer);
780 if (buffer[0] != 0)
781 {
782 g_serverId = _tcstoull(buffer, NULL, 16);
783 }
784 else
785 {
786 // Generate new ID
787 g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF);
788 _sntprintf(buffer, 256, UINT64X_FMT(_T("016")), g_serverId);
789 MetaDataWriteStr(_T("ServerID"), buffer);
790 }
791 nxlog_write_generic(NXLOG_INFO, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
792
793 // Initialize locks
794 retry_db_lock:
795 InetAddress addr;
796 if (!InitLocks(&addr, buffer))
797 {
798 if (addr.isValidUnicast()) // Database already locked by another server instance
799 {
800 // Check for lock from crashed/terminated local process
801 if (GetLocalIpAddr().equals(addr))
802 {
803 UINT32 pid = ConfigReadULong(_T("DBLockPID"), 0);
804 if (!IsNetxmsdProcess(pid) || (pid == GetCurrentProcessId()))
805 {
806 UnlockDB();
807 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
808 goto retry_db_lock;
809 }
810 }
811 else if (g_peerNodeAddrList.hasAddress(addr))
812 {
813 if (!PeerNodeIsRunning(addr))
814 {
815 UnlockDB();
816 nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
817 goto retry_db_lock;
818 }
819 }
820 nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "Is", &addr, buffer);
821 }
822 else
823 {
824 nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
825 }
826 return FALSE;
827 }
828 g_flags |= AF_DB_LOCKED;
829
830 // Load global configuration parameters
831 LoadGlobalConfig();
832 CASReadSettings();
833 nxlog_debug(1, _T("Global configuration loaded"));
834
835 // Check data directory
836 if (!CheckDataDir())
837 return FALSE;
838
839 // Initialize cryptografy
840 if (!InitCryptografy())
841 {
842 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, NULL);
843 return FALSE;
844 }
845
846 // Initialize certificate store and CA
847 InitCertificates();
848
849 // Create synchronization stuff
850 m_condShutdown = ConditionCreate(TRUE);
851
852 // Create thread pools
853 nxlog_debug(2, _T("Creating thread pools"));
854 g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN"));
855 g_agentConnectionThreadPool = ThreadPoolCreate(4, 256, _T("AGENT"));
856
857 // Setup unique identifiers table
858 if (!InitIdTable())
859 return FALSE;
860 nxlog_debug(2, _T("ID table created"));
861
862 InitCountryList();
863 InitCurrencyList();
864
865 // Update status for unfinished jobs in job history
866 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
867 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)"));
868 DBConnectionPoolReleaseConnection(hdb);
869
870 // Load and compile scripts
871 LoadScripts();
872
873 // Initialize persistent storage
874 PersistentStorageInit();
875
876 // Initialize watchdog
877 WatchdogInit();
878
879 // Load modules
880 if (!LoadNetXMSModules())
881 return FALSE; // Mandatory module not loaded
882 RegisterPredictionEngines();
883
884 // Initialize mailer and SMS sender
885 InitMailer();
886 InitSMSSender();
887
888 // Load users from database
889 InitUsers();
890 if (!LoadUsers())
891 {
892 nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
893 return FALSE;
894 }
895 nxlog_debug(2, _T("User accounts loaded"));
896
897 // Initialize audit
898 InitAuditLog();
899
900 // Initialize event handling subsystem
901 if (!InitEventSubsystem())
902 return FALSE;
903
904 // Initialize alarms
905 LoadAlarmCategories();
906 if (!InitAlarmManager())
907 return FALSE;
908
909 // Initialize objects infrastructure and load objects from database
910 LoadNetworkDeviceDrivers();
911 ObjectsInit();
912 if (!LoadObjects())
913 return FALSE;
914 nxlog_debug(1, _T("Objects loaded and initialized"));
915
916 // Initialize and load event actions
917 if (!InitActions())
918 {
919 nxlog_write(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL);
920 return FALSE;
921 }
922
923 // Initialize helpdesk link
924 SetHDLinkEntryPoints(ResolveAlarmByHDRef, TerminateAlarmByHDRef);
925 LoadHelpDeskLink();
926
927 // Initialize data collection subsystem
928 LoadPerfDataStorageDrivers();
929 InitDataCollector();
930
931 InitLogAccess();
932 FileUploadJob::init();
933 InitMappingTables();
934
935 InitClientListeners();
936 if (ConfigReadInt(_T("ImportConfigurationOnStartup"), 1))
937 ImportLocalConfiguration();
938
939 // Check if management node object presented in database
940 CheckForMgmtNode();
941 if (g_dwMgmtNode == 0)
942 {
943 nxlog_write(MSG_CANNOT_FIND_SELF, EVENTLOG_ERROR_TYPE, NULL);
944 return FALSE;
945 }
946
947 // Start threads
948 ThreadCreate(WatchdogThread, 0, NULL);
949 ThreadCreate(NodePoller, 0, NULL);
950 ThreadCreate(JobManagerThread, 0, NULL);
951 m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
952 m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
953
954 StartHouseKeeper();
955
956 // Start event processor
957 ThreadCreate(EventProcessor, 0, NULL);
958
959 // Start SNMP trapper
960 InitTraps();
961 if (ConfigReadInt(_T("EnableSNMPTraps"), 1))
962 ThreadCreate(SNMPTrapReceiver, 0, NULL);
963
964 // Start built-in syslog daemon
965 StartSyslogServer();
966
967 // Start database _T("lazy") write thread
968 StartDBWriter();
969
970 // Start beacon host poller
971 ThreadCreate(BeaconPoller, 0, NULL);
972
973 // Start inter-server communication listener
974 if (ConfigReadInt(_T("EnableISCListener"), 0))
975 ThreadCreate(ISCListener, 0, NULL);
976
977 // Start reporting server connector
978 if (ConfigReadInt(_T("EnableReportingServer"), 0))
979 ThreadCreate(ReportingServerConnector, 0, NULL);
980
981 //Start ldap synchronization
982 if (ConfigReadInt(_T("LdapSyncInterval"), 0))
983 ThreadCreate(SyncLDAPUsers, 0, NULL);
984
985 RegisterSchedulerTaskHandler(_T("Execute.Script"), ExecuteScheduledScript, SYSTEM_ACCESS_SCHEDULE_SCRIPT);
986 RegisterSchedulerTaskHandler(_T("Maintenance.Enter"), MaintenanceModeEnter, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
987 RegisterSchedulerTaskHandler(_T("Maintenance.Leave"), MaintenanceModeLeave, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
988 RegisterSchedulerTaskHandler(_T("Policy.Deploy"), ScheduleDeployPolicy, 0); //No access right beacause it will be used only by server
989 RegisterSchedulerTaskHandler(_T("Policy.Uninstall"), ScheduleUninstallPolicy, 0); //No access right beacause it will be used only by server
990 RegisterSchedulerTaskHandler(ALARM_SUMMARY_EMAIL_TASK_ID, SendAlarmSummaryEmail, 0); //No access right beacause it will be used only by server
991 InitializeTaskScheduler();
992
993 // Send summary emails
994 if (ConfigReadInt(_T("EnableAlarmSummaryEmails"), 0))
995 EnableAlarmSummaryEmails();
996 else
997 RemoveScheduledTaskByHandlerId(ALARM_SUMMARY_EMAIL_TASK_ID);
998
999 // Allow clients to connect
1000 ThreadCreate(ClientListenerThread, 0, NULL);
1001
1002 // Allow mobile devices to connect
1003 InitMobileDeviceListeners();
1004 ThreadCreate(MobileDeviceListenerThread, 0, NULL);
1005
1006 // Agent tunnels
1007 s_tunnelListenerThread = ThreadCreateEx(TunnelListenerThread, 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 StopDataCollection();
1088 StopObjectMaintenanceThreads();
1089
1090 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1091 SaveObjects(hdb, INVALID_INDEX, true);
1092 nxlog_debug(2, _T("All objects saved to database"));
1093 SaveUsers(hdb, INVALID_INDEX);
1094 nxlog_debug(2, _T("All users saved to database"));
1095 UpdatePStorageDatabase(hdb, INVALID_INDEX);
1096 nxlog_debug(2, _T("All persistent storage values saved"));
1097 DBConnectionPoolReleaseConnection(hdb);
1098
1099 StopDBWriter();
1100 nxlog_debug(1, _T("Database writer stopped"));
1101
1102 CleanupUsers();
1103 PersistentStorageDestroy();
1104
1105 // Remove database lock
1106 UnlockDB();
1107
1108 DBConnectionPoolShutdown();
1109 DBUnloadDriver(g_dbDriver);
1110 nxlog_debug(1, _T("Database driver unloaded"));
1111
1112 CleanupActions();
1113 ShutdownEventSubsystem();
1114 ShutdownAlarmManager();
1115 nxlog_debug(1, _T("Event processing stopped"));
1116
1117 ThreadPoolDestroy(g_agentConnectionThreadPool);
1118 ThreadPoolDestroy(g_mainThreadPool);
1119 MsgWaitQueue::shutdown();
1120 WatchdogShutdown();
1121
1122 nxlog_debug(1, _T("Server shutdown complete"));
1123 nxlog_close();
1124
1125 // Remove PID file
1126 #ifndef _WIN32
1127 _tremove(g_szPIDFile);
1128 #endif
1129
1130 // Terminate process
1131 #ifdef _WIN32
1132 if (!(g_flags & AF_DAEMON))
1133 ExitProcess(0);
1134 #else
1135 exit(0);
1136 #endif
1137 }
1138
1139 /**
1140 * Fast server shutdown - normally called only by Windows service on system shutdown
1141 */
1142 void NXCORE_EXPORTABLE FastShutdown()
1143 {
1144 DbgPrintf(1, _T("Using fast shutdown procedure"));
1145
1146 g_flags |= AF_SHUTDOWN; // Set shutdown flag
1147 ConditionSet(m_condShutdown);
1148
1149 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1150 SaveObjects(hdb, INVALID_INDEX, true);
1151 DbgPrintf(2, _T("All objects saved to database"));
1152 SaveUsers(hdb, INVALID_INDEX);
1153 DbgPrintf(2, _T("All users saved to database"));
1154 UpdatePStorageDatabase(hdb, INVALID_INDEX);
1155 DbgPrintf(2, _T("All persistent storage values saved"));
1156 DBConnectionPoolReleaseConnection(hdb);
1157
1158 // Remove database lock first, because we have a chance to lose DB connection
1159 UnlockDB();
1160
1161 // Stop database writers
1162 StopDBWriter();
1163 DbgPrintf(1, _T("Database writer stopped"));
1164
1165 DbgPrintf(1, _T("Server shutdown complete"));
1166 nxlog_close();
1167 }
1168
1169 /**
1170 * Signal handler for UNIX platforms
1171 */
1172 #ifndef _WIN32
1173
1174 void SignalHandlerStub(int nSignal)
1175 {
1176 // should be unused, but JIC...
1177 if (nSignal == SIGCHLD)
1178 {
1179 while (waitpid(-1, NULL, WNOHANG) > 0)
1180 ;
1181 }
1182 }
1183
1184 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
1185 {
1186 sigset_t signals;
1187 int nSignal;
1188
1189 m_signalHandlerThread = pthread_self();
1190
1191 // default for SIGCHLD: ignore
1192 signal(SIGCHLD, &SignalHandlerStub);
1193
1194 sigemptyset(&signals);
1195 sigaddset(&signals, SIGTERM);
1196 sigaddset(&signals, SIGINT);
1197 sigaddset(&signals, SIGSEGV);
1198 sigaddset(&signals, SIGCHLD);
1199 sigaddset(&signals, SIGHUP);
1200 sigaddset(&signals, SIGUSR1);
1201 sigaddset(&signals, SIGUSR2);
1202 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
1203 sigaddset(&signals, SIGPIPE);
1204 #endif
1205
1206 sigprocmask(SIG_BLOCK, &signals, NULL);
1207
1208 while(1)
1209 {
1210 if (sigwait(&signals, &nSignal) == 0)
1211 {
1212 switch(nSignal)
1213 {
1214 case SIGTERM:
1215 case SIGINT:
1216 // avoid repeat Shutdown() call
1217 if (!(g_flags & AF_SHUTDOWN))
1218 {
1219 m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
1220 if (IsStandalone())
1221 Shutdown(); // will never return
1222 else
1223 ConditionSet(m_condShutdown);
1224 }
1225 break;
1226 case SIGSEGV:
1227 abort();
1228 break;
1229 case SIGCHLD:
1230 while (waitpid(-1, NULL, WNOHANG) > 0)
1231 ;
1232 break;
1233 case SIGUSR1:
1234 if (g_flags & AF_SHUTDOWN)
1235 goto stop_handler;
1236 break;
1237 default:
1238 break;
1239 }
1240 }
1241 else
1242 {
1243 ThreadSleepMs(100);
1244 }
1245 }
1246
1247 stop_handler:
1248 sigprocmask(SIG_UNBLOCK, &signals, NULL);
1249 return THREAD_OK;
1250 }
1251
1252 #endif
1253
1254 /**
1255 * Common main()
1256 */
1257 THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
1258 {
1259 nxlog_write(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
1260
1261 if (IsStandalone())
1262 {
1263 if (!(g_flags & AF_DEBUG_CONSOLE_DISABLED))
1264 {
1265 char *ptr, szCommand[256];
1266 struct __console_ctx ctx;
1267 #ifdef UNICODE
1268 WCHAR wcCommand[256];
1269 #endif
1270
1271 ctx.hSocket = -1;
1272 ctx.socketMutex = INVALID_MUTEX_HANDLE;
1273 ctx.pMsg = NULL;
1274 ctx.session = NULL;
1275 ctx.output = NULL;
1276 WriteToTerminal(_T("\nNetXMS Server V") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T(" Ready\n")
1277 _T("Enter \"\x1b[1mhelp\x1b[0m\" for command list or \"\x1b[1mdown\x1b[0m\" for server shutdown\n")
1278 _T("System Console\n\n"));
1279
1280 #if USE_READLINE
1281 // Initialize readline library if we use it
1282 rl_bind_key('\t', RL_INSERT_CAST rl_insert);
1283 #endif
1284
1285 while(1)
1286 {
1287 #if USE_READLINE
1288 ptr = readline("\x1b[33mnetxmsd:\x1b[0m ");
1289 #else
1290 WriteToTerminal(_T("\x1b[33mnetxmsd:\x1b[0m "));
1291 fflush(stdout);
1292 if (fgets(szCommand, 255, stdin) == NULL)
1293 break; // Error reading stdin
1294 ptr = strchr(szCommand, '\n');
1295 if (ptr != NULL)
1296 *ptr = 0;
1297 ptr = szCommand;
1298 #endif
1299
1300 if (ptr != NULL)
1301 {
1302 #ifdef UNICODE
1303 #if HAVE_MBSTOWCS
1304 mbstowcs(wcCommand, ptr, 255);
1305 #else
1306 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
1307 #endif
1308 wcCommand[255] = 0;
1309 StrStrip(wcCommand);
1310 if (wcCommand[0] != 0)
1311 {
1312 if (ProcessConsoleCommand(wcCommand, &ctx) == CMD_EXIT_SHUTDOWN)
1313 #else
1314 StrStrip(ptr);
1315 if (*ptr != 0)
1316 {
1317 if (ProcessConsoleCommand(ptr, &ctx) == CMD_EXIT_SHUTDOWN)
1318 #endif
1319 break;
1320 #if USE_READLINE
1321 add_history(ptr);
1322 #endif
1323 }
1324 #if USE_READLINE
1325 free(ptr);
1326 #endif
1327 }
1328 else
1329 {
1330 _tprintf(_T("\n"));
1331 }
1332 }
1333
1334 #if USE_READLINE
1335 free(ptr);
1336 #endif
1337 if (!(g_flags & AF_SHUTDOWN))
1338 {
1339 m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
1340 Shutdown();
1341 }
1342 }
1343 else
1344 {
1345 // standalone with debug console disabled
1346 #ifdef _WIN32
1347 _tprintf(_T("Server running. Press ESC to shutdown.\n"));
1348 while(1)
1349 {
1350 if (_getch() == 27)
1351 break;
1352 }
1353 _tprintf(_T("Server shutting down...\n"));
1354 Shutdown();
1355 #else
1356 _tprintf(_T("Server running. Press Ctrl+C to shutdown.\n"));
1357 // Shutdown will be called from signal handler
1358 ConditionWait(m_condShutdown, INFINITE);
1359 #endif
1360 }
1361 }
1362 else
1363 {
1364 ConditionWait(m_condShutdown, INFINITE);
1365 // On Win32, Shutdown() will be called by service control handler
1366 #ifndef _WIN32
1367 Shutdown();
1368 #endif
1369 }
1370 return THREAD_OK;
1371 }
1372
1373 /**
1374 * Initiate server shutdown
1375 */
1376 void InitiateShutdown()
1377 {
1378 #ifdef _WIN32
1379 Shutdown();
1380 #else
1381 if (IsStandalone())
1382 {
1383 Shutdown();
1384 }
1385 else
1386 {
1387 pthread_kill(m_signalHandlerThread, SIGTERM);
1388 }
1389 #endif
1390 }
1391
1392 /**
1393 *DLL Entry point
1394 */
1395 #ifdef _WIN32
1396
1397 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
1398 {
1399 if (dwReason == DLL_PROCESS_ATTACH)
1400 DisableThreadLibraryCalls(hInstance);
1401 return TRUE;
1402 }
1403
1404 #endif