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