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