calls to functions deprecated in OpenSSL 1.1 replaced with compatible ones
[public/netxms.git] / src / server / core / main.cpp
index 23899b1..9378d9b 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ** NetXMS - Network Management System
-** Copyright (C) 2003-2015 NetXMS Team
+** Copyright (C) 2003-2017 Raden Solutions
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 #include <errno.h>
 #include <psapi.h>
 #include <conio.h>
-#define open   _open
-#define write  _write
-#define close  _close
 #else
 #include <signal.h>
 #include <sys/wait.h>
 #endif
 
-/**
- * Format string to show value of global flag
- */
-#define SHOW_FLAG_VALUE(x) _T("  %-38s = %d\n"), _T(#x), (g_flags & x) ? 1 : 0
+#ifdef WITH_ZMQ
+#include "zeromq.h"
+#endif
 
 /**
  * Messages generated by mc.pl (for UNIX version only)
@@ -66,60 +62,69 @@ extern const TCHAR *g_szMessages[];
 /**
  * Externals
  */
-extern Queue g_nodePollerQueue;
-extern Queue g_dataCollectionQueue;
 extern Queue g_dciCacheLoaderQueue;
-extern Queue g_syslogProcessingQueue;
-extern Queue g_syslogWriteQueue;
-extern ThreadPool *g_pollerThreadPool;
 
 void InitClientListeners();
 void InitMobileDeviceListeners();
 void InitCertificates();
+bool LoadServerCertificate(RSA **serverKey);
 void InitUsers();
 void CleanupUsers();
 void LoadPerfDataStorageDrivers();
-void InitializeTaskScheduler();
-void CloseTaskScheduler();
+void ImportLocalConfiguration();
+void RegisterPredictionEngines();
+void ExecuteStartupScripts();
+void CloseAgentTunnels();
+void StopDataCollection();
+void StopObjectMaintenanceThreads();
+
+void ExecuteScheduledScript(const ScheduledTaskParameters *param);
+void MaintenanceModeEnter(const ScheduledTaskParameters *params);
+void MaintenanceModeLeave(const ScheduledTaskParameters *params);
+void ScheduleDeployPolicy(const ScheduledTaskParameters *params);
+void ScheduleUninstallPolicy(const ScheduledTaskParameters * params);
+
+void InitCountryList();
+void InitCurrencyList();
 
 #if XMPP_SUPPORTED
+void StartXMPPConnector();
 void StopXMPPConnector();
 #endif
 
 /**
+ * Syslog server control
+ */
+void StartSyslogServer();
+void StopSyslogServer();
+
+/**
  * Thread functions
  */
-THREAD_RESULT THREAD_CALL HouseKeeper(void *);
 THREAD_RESULT THREAD_CALL Syncer(void *);
 THREAD_RESULT THREAD_CALL NodePoller(void *);
 THREAD_RESULT THREAD_CALL PollManager(void *);
 THREAD_RESULT THREAD_CALL EventProcessor(void *);
 THREAD_RESULT THREAD_CALL WatchdogThread(void *);
-THREAD_RESULT THREAD_CALL ClientListener(void *);
-THREAD_RESULT THREAD_CALL ClientListenerIPv6(void *);
-THREAD_RESULT THREAD_CALL MobileDeviceListener(void *);
-THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *);
+THREAD_RESULT THREAD_CALL ClientListenerThread(void *);
+THREAD_RESULT THREAD_CALL MobileDeviceListenerThread(void *);
 THREAD_RESULT THREAD_CALL ISCListener(void *);
 THREAD_RESULT THREAD_CALL LocalAdminListener(void *);
 THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *);
-THREAD_RESULT THREAD_CALL SyslogDaemon(void *);
 THREAD_RESULT THREAD_CALL BeaconPoller(void *);
 THREAD_RESULT THREAD_CALL JobManagerThread(void *);
 THREAD_RESULT THREAD_CALL UptimeCalculator(void *);
 THREAD_RESULT THREAD_CALL ReportingServerConnector(void *);
-
-#if XMPP_SUPPORTED
-THREAD_RESULT THREAD_CALL XMPPConnectionManager(void *);
-#endif
+THREAD_RESULT THREAD_CALL TunnelListenerThread(void *arg);
 
 /**
  * Global variables
  */
 TCHAR NXCORE_EXPORTABLE g_szConfigFile[MAX_PATH] = _T("{search}");
 TCHAR NXCORE_EXPORTABLE g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
-UINT32 g_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
-UINT32 g_dwMaxLogSize = 16384 * 1024;
-UINT32 g_dwLogHistorySize = 4;
+UINT32 g_logRotationMode = NXLOG_ROTATION_BY_SIZE;
+UINT64 g_maxLogSize = 16384 * 1024;
+UINT32 g_logHistorySize = 4;
 TCHAR g_szDailyLogFileSuffix[64] = _T("");
 TCHAR NXCORE_EXPORTABLE g_szDumpDir[MAX_PATH] = DEFAULT_DUMP_DIR;
 char g_szCodePage[256] = ICONV_DEFAULT_CODEPAGE;
@@ -127,7 +132,6 @@ TCHAR NXCORE_EXPORTABLE g_szListenAddress[MAX_PATH] = _T("*");
 #ifndef _WIN32
 TCHAR NXCORE_EXPORTABLE g_szPIDFile[MAX_PATH] = _T("/var/run/netxmsd.pid");
 #endif
-DB_HANDLE g_hCoreDB = 0;
 UINT32 g_dwDiscoveryPollingInterval;
 UINT32 g_dwStatusPollingInterval;
 UINT32 g_dwConfigurationPollingInterval;
@@ -139,6 +143,7 @@ UINT32 g_icmpPingSize;
 UINT32 g_icmpPingTimeout = 1500;    // ICMP ping timeout (milliseconds)
 UINT32 g_auditFlags;
 UINT32 g_slmPollingInterval;
+UINT32 g_offlineDataRelevanceTime = 86400;
 TCHAR NXCORE_EXPORTABLE g_netxmsdDataDir[MAX_PATH] = _T("");
 TCHAR NXCORE_EXPORTABLE g_netxmsdLibDir[MAX_PATH] = _T("");
 int g_dbSyntax = DB_SYNTAX_UNKNOWN;
@@ -151,27 +156,57 @@ UINT32 g_agentCommandTimeout = 4000;  // Default timeout for requests to agent
 UINT32 g_thresholdRepeatInterval = 0;  // Disabled by default
 int g_requiredPolls = 1;
 DB_DRIVER g_dbDriver = NULL;
-ThreadPool *g_mainThreadPool = NULL;
+ThreadPool NXCORE_EXPORTABLE *g_mainThreadPool = NULL;
 INT16 g_defaultAgentCacheMode = AGENT_CACHE_OFF;
+InetAddressList g_peerNodeAddrList;
+Condition g_dbPasswordReady(true);
 
 /**
  * Static data
  */
 static CONDITION m_condShutdown = INVALID_CONDITION_HANDLE;
 static THREAD m_thPollManager = INVALID_THREAD_HANDLE;
-static THREAD m_thHouseKeeper = INVALID_THREAD_HANDLE;
 static THREAD m_thSyncer = INVALID_THREAD_HANDLE;
-static THREAD m_thSyslogDaemon = INVALID_THREAD_HANDLE;
-#if XMPP_SUPPORTED
-static THREAD m_thXMPPConnector = INVALID_THREAD_HANDLE;
-#endif
+static THREAD s_tunnelListenerThread = INVALID_THREAD_HANDLE;
 static int m_nShutdownReason = SHUTDOWN_DEFAULT;
+static StringSet s_components;
 
 #ifndef _WIN32
 static pthread_t m_signalHandlerThread;
 #endif
 
 /**
+ * Register component
+ */
+void NXCORE_EXPORTABLE RegisterComponent(const TCHAR *id)
+{
+   s_components.add(id);
+}
+
+/**
+ * Check if component with given ID is registered
+ */
+bool NXCORE_EXPORTABLE IsComponentRegistered(const TCHAR *id)
+{
+   return s_components.contains(id);
+}
+
+/**
+ * Fill NXCP message with components data
+ */
+void FillComponentsMessage(NXCPMessage *msg)
+{
+   msg->setField(VID_NUM_COMPONENTS, (INT32)s_components.size());
+   UINT32 fieldId = VID_COMPONENT_LIST_BASE;
+   Iterator<const TCHAR> *it = s_components.iterator();
+   while(it->hasNext())
+   {
+      msg->setField(fieldId++, it->next());
+   }
+   delete it;
+}
+
+/**
  * Sleep for specified number of seconds or until system shutdown arrives
  * Function will return TRUE if shutdown event occurs
  *
@@ -188,8 +223,7 @@ bool NXCORE_EXPORTABLE SleepAndCheckForShutdown(int seconds)
  */
 void NXCORE_EXPORTABLE ShutdownDB()
 {
-       if (g_hCoreDB != NULL)
-               DBDisconnect(g_hCoreDB);
+   DBConnectionPoolShutdown();
        DBUnloadDriver(g_dbDriver);
 }
 
@@ -274,6 +308,8 @@ static void LoadGlobalConfig()
        g_dwTopologyPollingInterval = ConfigReadInt(_T("TopologyPollingInterval"), 1800);
        g_dwConditionPollingInterval = ConfigReadInt(_T("ConditionPollingInterval"), 60);
        g_slmPollingInterval = ConfigReadInt(_T("SlmPollingInterval"), 60);
+       DCObject::m_defaultPollingInterval = ConfigReadInt(_T("DefaultDCIPollingInterval"), 60);
+   DCObject::m_defaultRetentionTime = ConfigReadInt(_T("DefaultDCIRetentionTime"), 30);
    g_defaultAgentCacheMode = (INT16)ConfigReadInt(_T("DefaultAgentCacheMode"), AGENT_CACHE_OFF);
    if ((g_defaultAgentCacheMode != AGENT_CACHE_ON) && (g_defaultAgentCacheMode != AGENT_CACHE_OFF))
    {
@@ -291,14 +327,14 @@ static void LoadGlobalConfig()
                g_flags |= AF_ENABLE_ZONING;
        if (ConfigReadInt(_T("EnableObjectTransactions"), 0))
                g_flags |= AF_ENABLE_OBJECT_TRANSACTIONS;
-       if (ConfigReadInt(_T("EnableMultipleDBConnections"), 1))
-               g_flags |= AF_ENABLE_MULTIPLE_DB_CONN;
        if (ConfigReadInt(_T("RunNetworkDiscovery"), 0))
                g_flags |= AF_ENABLE_NETWORK_DISCOVERY;
        if (ConfigReadInt(_T("ActiveNetworkDiscovery"), 0))
                g_flags |= AF_ACTIVE_NETWORK_DISCOVERY;
    if (ConfigReadInt(_T("UseSNMPTrapsForDiscovery"), 0))
       g_flags |= AF_SNMP_TRAP_DISCOVERY;
+   if (ConfigReadInt(_T("UseSyslogForDiscovery"), 0))
+      g_flags |= AF_SYSLOG_DISCOVERY;
        if (ConfigReadInt(_T("ResolveNodeNames"), 1))
                g_flags |= AF_RESOLVE_NODE_NAMES;
        if (ConfigReadInt(_T("SyncNodeNamesWithDNS"), 0))
@@ -309,7 +345,7 @@ static void LoadGlobalConfig()
                g_flags |= AF_ENABLE_NXSL_CONTAINER_FUNCS;
    if (ConfigReadInt(_T("UseFQDNForNodeNames"), 1))
       g_flags |= AF_USE_FQDN_FOR_NODE_NAMES;
-   if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 0))
+   if (ConfigReadInt(_T("ApplyDCIFromTemplateToDisabledDCI"), 1))
       g_flags |= AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE;
    if (ConfigReadInt(_T("ResolveDNSToIPOnStatusPoll"), 0))
       g_flags |= AF_RESOLVE_IP_FOR_EACH_STATUS_POLL;
@@ -334,81 +370,95 @@ static void LoadGlobalConfig()
        g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000);
        g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
        g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
+       g_offlineDataRelevanceTime = ConfigReadInt(_T("OfflineDataRelevanceTime"), 86400);
 
-       UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 2000);
+       UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 1500);
    SnmpSetDefaultTimeout(snmpTimeout);
 }
 
 /**
  * Initialize cryptografic functions
  */
-static BOOL InitCryptografy()
+static bool InitCryptografy()
 {
 #ifdef _WITH_ENCRYPTION
-       TCHAR szKeyFile[MAX_PATH];
-       BOOL bResult = FALSE;
-       int fd, iPolicy;
-       UINT32 dwLen;
-       BYTE *pBufPos, *pKeyBuffer, hash[SHA1_DIGEST_SIZE];
+       bool success = false;
 
-   if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F), DbgPrintf2))
+   if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F)))
                return FALSE;
-   DbgPrintf(4, _T("Supported ciphers: %s"), (const TCHAR *)NXCPGetSupportedCiphersAsText());
+   nxlog_debug(4, _T("Supported ciphers: %s"), (const TCHAR *)NXCPGetSupportedCiphersAsText());
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+   OPENSSL_init_ssl(0, NULL);
+#else
    SSL_library_init();
    SSL_load_error_strings();
+#endif
 
-       _tcscpy(szKeyFile, g_netxmsdDataDir);
-       _tcscat(szKeyFile, DFILE_KEYS);
-       fd = _topen(szKeyFile, O_RDONLY | O_BINARY);
-       g_pServerKey = LoadRSAKeys(szKeyFile);
-       if (g_pServerKey == NULL)
-       {
-               DbgPrintf(1, _T("Generating RSA key pair..."));
-               g_pServerKey = RSA_generate_key(NETXMS_RSA_KEYLEN, 17, NULL, 0);
-               if (g_pServerKey != NULL)
-               {
-                       fd = _topen(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600);
-                       if (fd != -1)
-                       {
-                               dwLen = i2d_RSAPublicKey(g_pServerKey, NULL);
-                               dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
-                               pKeyBuffer = (BYTE *)malloc(dwLen);
-
-                               pBufPos = pKeyBuffer;
-                               i2d_RSAPublicKey(g_pServerKey, &pBufPos);
-                               i2d_RSAPrivateKey(g_pServerKey, &pBufPos);
-                               write(fd, &dwLen, sizeof(UINT32));
-                               write(fd, pKeyBuffer, dwLen);
-
-                               CalculateSHA1Hash(pKeyBuffer, dwLen, hash);
-                               write(fd, hash, SHA1_DIGEST_SIZE);
-
-                               close(fd);
-                               free(pKeyBuffer);
-                               bResult = TRUE;
-                       }
+   if (LoadServerCertificate(&g_pServerKey))
+   {
+      nxlog_debug(1, _T("Server certificate loaded"));
+   }
+   if (g_pServerKey != NULL)
+   {
+      nxlog_debug(1, _T("Using server certificate key"));
+      success = true;
+   }
+   else
+   {
+      TCHAR szKeyFile[MAX_PATH];
+      _tcscpy(szKeyFile, g_netxmsdDataDir);
+      _tcscat(szKeyFile, DFILE_KEYS);
+      g_pServerKey = LoadRSAKeys(szKeyFile);
+      if (g_pServerKey == NULL)
+      {
+         nxlog_debug(1, _T("Generating RSA key pair..."));
+         g_pServerKey = RSAGenerateKey(NETXMS_RSA_KEYLEN);
+         if (g_pServerKey != NULL)
+         {
+            int fd = _topen(szKeyFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0600);
+            if (fd != -1)
+            {
+               UINT32 dwLen = i2d_RSAPublicKey(g_pServerKey, NULL);
+               dwLen += i2d_RSAPrivateKey(g_pServerKey, NULL);
+               BYTE *pKeyBuffer = (BYTE *)malloc(dwLen);
+
+               BYTE *pBufPos = pKeyBuffer;
+               i2d_RSAPublicKey(g_pServerKey, &pBufPos);
+               i2d_RSAPrivateKey(g_pServerKey, &pBufPos);
+               _write(fd, &dwLen, sizeof(UINT32));
+               _write(fd, pKeyBuffer, dwLen);
+
+               BYTE hash[SHA1_DIGEST_SIZE];
+               CalculateSHA1Hash(pKeyBuffer, dwLen, hash);
+               _write(fd, hash, SHA1_DIGEST_SIZE);
+
+               _close(fd);
+               free(pKeyBuffer);
+               success = true;
+            }
+            else
+            {
+               nxlog_debug(0, _T("Failed to open %s for writing"), szKeyFile);
+            }
+         }
+         else
+         {
+            nxlog_debug(0, _T("Failed to generate RSA key"));
+         }
+      }
       else
       {
-        DbgPrintf(0, _T("Failed to open %s for writing"), szKeyFile);
+         success = true;
       }
-               }
-    else
-    {
-      DbgPrintf(0, _T("Failed to generate RSA key"));
-    }
-       }
-       else
-       {
-               bResult = TRUE;
-       }
+   }
 
-       iPolicy = ConfigReadInt(_T("DefaultEncryptionPolicy"), 1);
+       int iPolicy = ConfigReadInt(_T("DefaultEncryptionPolicy"), 1);
        if ((iPolicy < 0) || (iPolicy > 3))
                iPolicy = 1;
        SetAgentDEP(iPolicy);
 
-       return bResult;
+       return success;
 #else
        return TRUE;
 #endif
@@ -417,38 +467,83 @@ static BOOL InitCryptografy()
 /**
  * Check if process with given PID exists and is a NetXMS server process
  */
-static BOOL IsNetxmsdProcess(UINT32 dwPID)
+static bool IsNetxmsdProcess(UINT32 pid)
 {
 #ifdef _WIN32
-       HANDLE hProcess;
-       TCHAR szExtModule[MAX_PATH], szIntModule[MAX_PATH];
-       BOOL bRet = FALSE;
-
-       hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
+       bool result = false;
+       HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
        if (hProcess != NULL)
        {
+          TCHAR szExtModule[MAX_PATH], szIntModule[MAX_PATH];
                if ((GetModuleBaseName(hProcess, NULL, szExtModule, MAX_PATH) > 0) &&
-                               (GetModuleBaseName(GetCurrentProcess(), NULL, szIntModule, MAX_PATH) > 0))
+                        (GetModuleBaseName(GetCurrentProcess(), NULL, szIntModule, MAX_PATH) > 0))
                {
-                       bRet = !_tcsicmp(szExtModule, szIntModule);
+                       result = (_tcsicmp(szExtModule, szIntModule) == 0);
                }
                else
                {
                        // Cannot read process name, for safety assume that it's a server process
-                       bRet = TRUE;
+                       result = true;
                }
                CloseHandle(hProcess);
        }
-       return bRet;
+       return result;
+#else
+       return kill((pid_t)pid, 0) != -1;
+#endif
+}
+
+/**
+ * Check if remote netxmsd is running
+ */
+static bool PeerNodeIsRunning(const InetAddress& addr)
+{
+   bool result = false;
+
+   TCHAR keyFile[MAX_PATH];
+   _tcscpy(keyFile, g_netxmsdDataDir);
+   _tcscat(keyFile, DFILE_KEYS);
+   RSA *key = LoadRSAKeys(keyFile);
+
+   AgentConnection *ac = new AgentConnection(addr);
+   if (ac->connect(key))
+   {
+      TCHAR result[MAX_RESULT_LENGTH];
+#ifdef _WIN32
+      UINT32 rcc = ac->getParameter(_T("Process.Count(netxmsd.exe)"), MAX_RESULT_LENGTH, result);
 #else
-       return (kill((pid_t)dwPID, 0) != -1);
+      UINT32 rcc = ac->getParameter(_T("Process.Count(netxmsd)"), MAX_RESULT_LENGTH, result);
 #endif
+      ac->decRefCount();
+      if (key != NULL)
+         RSA_free(key);
+      if (rcc == ERR_SUCCESS)
+      {
+         return _tcstol(result, NULL, 10) > 0;
+      }
+   }
+   else
+   {
+      ac->decRefCount();
+      if (key != NULL)
+         RSA_free(key);
+   }
+
+   UINT16 port = (UINT16)ConfigReadInt(_T("ClientListenerPort"), SERVER_LISTEN_PORT_FOR_CLIENTS);
+   SOCKET s = ConnectToHost(addr, port, 5000);
+   if (s != INVALID_SOCKET)
+   {
+      shutdown(s, SHUT_RDWR);
+      closesocket(s);
+      result = true;
+   }
+   return result;
 }
 
 /**
  * Database event handler
  */
-static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, void *userArg)
+static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *pszArg2, bool connLost, void *userArg)
 {
        if (!(g_flags & AF_SERVER_INITIALIZED))
                return;     // Don't try to do anything if server is not ready yet
@@ -466,7 +561,7 @@ static void DBEventHandler(DWORD dwEvent, const WCHAR *pszArg1, const WCHAR *psz
                        NotifyClientSessions(NX_NOTIFY_DBCONN_STATUS, TRUE);
                        break;
                case DBEVENT_QUERY_FAILED:
-                       PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uu", pszArg1, pszArg2);
+                       PostEvent(EVENT_DB_QUERY_FAILED, g_dwMgmtNode, "uud", pszArg1, pszArg2, connLost ? 1 : 0);
                        break;
                default:
                        break;
@@ -515,25 +610,31 @@ static void OracleSessionInitCallback(DB_HANDLE hdb)
 }
 
 /**
+ * Get database password
+ */
+static void GetDatabasePassword()
+{
+   if (_tcscmp(g_szDbPassword, _T("?")))
+      return;
+
+   nxlog_write(MSG_WAITING_FOR_DB_PASSWORD, NXLOG_INFO, NULL);
+   g_dbPasswordReady.wait(INFINITE);
+   nxlog_debug(1, _T("Database password received"));
+}
+
+/**
  * Server initialization
  */
 BOOL NXCORE_EXPORTABLE Initialize()
 {
-       int i, iDBVersion;
-       TCHAR szInfo[256];
+       s_components.add(_T("CORE"));
 
        g_serverStartTime = time(NULL);
        srand((unsigned int)g_serverStartTime);
 
-   if (g_netxmsdLibDir[0] == 0)
-   {
-      GetNetXMSDirectory(nxDirLib, g_netxmsdLibDir);
-      DbgPrintf(1, _T("Lib directory set to %s"), g_netxmsdLibDir);
-   }
-
        if (!(g_flags & AF_USE_SYSLOG))
        {
-               if (!nxlog_set_rotation_policy((int)g_dwLogRotationMode, (int)g_dwMaxLogSize, (int)g_dwLogHistorySize, g_szDailyLogFileSuffix))
+               if (!nxlog_set_rotation_policy((int)g_logRotationMode, g_maxLogSize, (int)g_logHistorySize, g_szDailyLogFileSuffix))
                        if (!(g_flags & AF_DAEMON))
                                _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
        }
@@ -543,9 +644,9 @@ BOOL NXCORE_EXPORTABLE Initialize()
                    ((g_flags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
                    _T("LIBNXSRV.DLL"),
 #ifdef _WIN32
-                                      0, NULL))
+                                      0, NULL, MSG_DEBUG, MSG_DEBUG_TAG, MSG_OTHER))
 #else
-                                      g_dwNumMessages, g_szMessages))
+                                      g_dwNumMessages, g_szMessages, MSG_DEBUG, MSG_DEBUG_TAG, MSG_OTHER))
 #endif
    {
                _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
@@ -553,6 +654,12 @@ BOOL NXCORE_EXPORTABLE Initialize()
    }
        nxlog_set_console_writer(LogConsoleWriter);
 
+   if (g_netxmsdLibDir[0] == 0)
+   {
+      GetNetXMSDirectory(nxDirLib, g_netxmsdLibDir);
+      nxlog_debug(1, _T("LIB directory set to %s"), g_netxmsdLibDir);
+   }
+
        // Set code page
 #ifndef _WIN32
        if (SetDefaultCodepage(g_szCodePage))
@@ -570,7 +677,7 @@ BOOL NXCORE_EXPORTABLE Initialize()
        {
 #ifdef _WIN32
                if (SetProcessAffinityMask(GetCurrentProcess(), g_processAffinityMask))
-                       DbgPrintf(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask);
+                  nxlog_debug(1, _T("Process affinity mask set to 0x%08X"), g_processAffinityMask);
 #else
                nxlog_write(MSG_SET_PROCESS_AFFINITY_NOT_SUPPORTED, EVENTLOG_WARNING_TYPE, NULL);
 #endif
@@ -589,104 +696,137 @@ BOOL NXCORE_EXPORTABLE Initialize()
        InitLocalNetInfo();
    SnmpSetMessageIds(MSG_OID_PARSE_ERROR, MSG_SNMP_UNKNOWN_TYPE, MSG_SNMP_GET_ERROR);
 
-   Timer::globalInit();
-
        // Create queue for delayed SQL queries
        g_dbWriterQueue = new Queue(256, 64);
        g_dciDataWriterQueue = new Queue(1024, 1024);
        g_dciRawDataWriterQueue = new Queue(1024, 1024);
 
        // Initialize database driver and connect to database
-       DBSetDebugPrintCallback(DbgPrintf2);
        if (!DBInit(MSG_OTHER, (g_flags & AF_LOG_SQL_ERRORS) ? MSG_SQL_ERROR : 0))
                return FALSE;
-       g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (g_debugLevel >= 9), DBEventHandler, NULL);
+       g_dbDriver = DBLoadDriver(g_szDbDriver, g_szDbDrvParams, (nxlog_get_debug_level() >= 9), DBEventHandler, NULL);
        if (g_dbDriver == NULL)
                return FALSE;
 
+   // Start local administrative interface listener if required
+   if (g_flags & AF_ENABLE_LOCAL_CONSOLE)
+      ThreadCreate(LocalAdminListener, 0, NULL);
+
+       // Wait for database password if needed
+       GetDatabasePassword();
+
        // Connect to database
+       DB_HANDLE hdbBootstrap = NULL;
        TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
-       for(i = 0; ; i++)
+       for(int i = 0; ; i++)
        {
-               g_hCoreDB = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText);
-               if ((g_hCoreDB != NULL) || (i == 5))
+          hdbBootstrap = DBConnect(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, errorText);
+               if ((hdbBootstrap != NULL) || (i == 5))
                        break;
                ThreadSleep(5);
        }
-       if (g_hCoreDB == NULL)
+       if (hdbBootstrap == NULL)
        {
                nxlog_write(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, "s", errorText);
                return FALSE;
        }
-       DbgPrintf(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer);
+       nxlog_debug(1, _T("Successfully connected to database %s@%s"), g_szDbName, g_szDbServer);
 
-       // Check database version
-       iDBVersion = DBGetSchemaVersion(g_hCoreDB);
-       if (iDBVersion != DB_FORMAT_VERSION)
+       // Check database schema version
+       INT32 schemaVersionMajor, schemaVersionMinor;
+       if (!DBGetSchemaVersion(hdbBootstrap, &schemaVersionMajor, &schemaVersionMinor))
        {
-               nxlog_write(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", iDBVersion, DB_FORMAT_VERSION);
+          nxlog_write(MSG_UNABLE_TO_GET_DB_SCHEMA_VERSION, NXLOG_ERROR, NULL);
+      DBDisconnect(hdbBootstrap);
+      return FALSE;
+       }
+
+       if ((schemaVersionMajor != DB_SCHEMA_VERSION_MAJOR) || (schemaVersionMinor != DB_SCHEMA_VERSION_MINOR))
+       {
+               nxlog_write(MSG_WRONG_DB_SCHEMA_VERSION, NXLOG_ERROR, "dddd", schemaVersionMajor, schemaVersionMinor, DB_SCHEMA_VERSION_MAJOR, DB_SCHEMA_VERSION_MINOR);
+               DBDisconnect(hdbBootstrap);
                return FALSE;
        }
 
        // Read database syntax
-       g_dbSyntax = DBGetSyntax(g_hCoreDB);
+       g_dbSyntax = DBGetSyntax(hdbBootstrap);
    if (g_dbSyntax == DB_SYNTAX_ORACLE)
    {
       DBSetSessionInitCallback(OracleSessionInitCallback);
    }
 
-       int baseSize = ConfigReadInt(_T("ConnectionPoolBaseSize"), 5);
-       int maxSize = ConfigReadInt(_T("ConnectionPoolMaxSize"), 20);
-       int cooldownTime = ConfigReadInt(_T("ConnectionPoolCooldownTime"), 300);
-       DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, 0);
-   g_flags |= AF_DB_CONNECTION_POOL_READY;
+       int baseSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolBaseSize"), 10);
+       int maxSize = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxSize"), 30);
+       int cooldownTime = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolCooldownTime"), 300);
+       int ttl = ConfigReadIntEx(hdbBootstrap, _T("DBConnectionPoolMaxLifetime"), 14400);
+
+   DBDisconnect(hdbBootstrap);
+
+       if (!DBConnectionPoolStartup(g_dbDriver, g_szDbServer, g_szDbName, g_szDbLogin, g_szDbPassword, g_szDbSchema, baseSize, maxSize, cooldownTime, ttl))
+       {
+      nxlog_write(MSG_DBCONNPOOL_INIT_FAILED, EVENTLOG_ERROR_TYPE, NULL);
+          return FALSE;
+       }
 
    UINT32 lrt = ConfigReadULong(_T("LongRunningQueryThreshold"), 0);
    if (lrt != 0)
+   {
       DBSetLongRunningThreshold(lrt);
+      nxlog_write_generic(NXLOG_INFO, _T("Long running query threshold set at %d milliseconds"), lrt);
+   }
+
+   MetaDataPreLoad();
 
        // Read server ID
-       MetaDataReadStr(_T("ServerID"), szInfo, 256, _T(""));
-       StrStrip(szInfo);
-       if (szInfo[0] != 0)
+   TCHAR buffer[256];
+       MetaDataReadStr(_T("ServerID"), buffer, 256, _T(""));
+       StrStrip(buffer);
+       if (buffer[0] != 0)
        {
-      g_serverId = _tcstoull(szInfo, NULL, 16);
+      g_serverId = _tcstoull(buffer, NULL, 16);
        }
        else
        {
                // Generate new ID
                g_serverId = ((UINT64)time(NULL) << 31) | (UINT64)((UINT32)rand() & 0x7FFFFFFF);
-      _sntprintf(szInfo, 256, UINT64X_FMT(_T("016")), g_serverId);
-               MetaDataWriteStr(_T("ServerID"), szInfo);
+      _sntprintf(buffer, 256, UINT64X_FMT(_T("016")), g_serverId);
+               MetaDataWriteStr(_T("ServerID"), buffer);
        }
-   DbgPrintf(1, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
+       nxlog_write_generic(NXLOG_INFO, _T("Server ID ") UINT64X_FMT(_T("016")), g_serverId);
 
        // Initialize locks
 retry_db_lock:
    InetAddress addr;
-       if (!InitLocks(&addr, szInfo))
+       if (!InitLocks(&addr, buffer))
        {
-      if (!addr.isValid())    // Some SQL problems
-               {
-                       nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
-               }
-               else     // Database already locked by another server instance
+               if (addr.isValidUnicast())     // Database already locked by another server instance
                {
                        // Check for lock from crashed/terminated local process
                        if (GetLocalIpAddr().equals(addr))
                        {
-                               UINT32 dwPID;
-
-                               dwPID = ConfigReadULong(_T("DBLockPID"), 0);
-                               if (!IsNetxmsdProcess(dwPID) || (dwPID == GetCurrentProcessId()))
+                               UINT32 pid = ConfigReadULong(_T("DBLockPID"), 0);
+                               if (!IsNetxmsdProcess(pid) || (pid == GetCurrentProcessId()))
                                {
                                        UnlockDB();
                                        nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
                                        goto retry_db_lock;
                                }
                        }
-                       nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "As", &addr, szInfo);
+                       else if (g_peerNodeAddrList.hasAddress(addr))
+                       {
+                          if (!PeerNodeIsRunning(addr))
+                          {
+               UnlockDB();
+               nxlog_write(MSG_DB_LOCK_REMOVED, EVENTLOG_INFORMATION_TYPE, NULL);
+               goto retry_db_lock;
+                          }
+                       }
+                       nxlog_write(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "Is", &addr, buffer);
                }
+               else
+      {
+         nxlog_write(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
+      }
                return FALSE;
        }
        g_flags |= AF_DB_LOCKED;
@@ -694,7 +834,7 @@ retry_db_lock:
        // Load global configuration parameters
        LoadGlobalConfig();
    CASReadSettings();
-       DbgPrintf(1, _T("Global configuration loaded"));
+   nxlog_debug(1, _T("Global configuration loaded"));
 
        // Check data directory
        if (!CheckDataDir())
@@ -714,27 +854,36 @@ retry_db_lock:
        m_condShutdown = ConditionCreate(TRUE);
 
    // Create thread pools
-   DbgPrintf(2, _T("Creating thread pools"));
-   ThreadPoolSetDebugCallback(DbgPrintf2);
+       nxlog_debug(2, _T("Creating thread pools"));
    g_mainThreadPool = ThreadPoolCreate(8, 256, _T("MAIN"));
+   g_agentConnectionThreadPool = ThreadPoolCreate(4, 256, _T("AGENT"));
 
        // Setup unique identifiers table
        if (!InitIdTable())
                return FALSE;
-       DbgPrintf(2, _T("ID table created"));
+       nxlog_debug(2, _T("ID table created"));
+
+       InitCountryList();
+       InitCurrencyList();
 
        // Update status for unfinished jobs in job history
-       DBQuery(g_hCoreDB, _T("UPDATE job_history SET status=4,failure_message='Aborted due to server shutdown or crash' WHERE status NOT IN (3,4,5)"));
+       DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
+       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)"));
+       DBConnectionPoolReleaseConnection(hdb);
 
        // Load and compile scripts
        LoadScripts();
 
+       // Initialize persistent storage
+       PersistentStorageInit();
+
        // Initialize watchdog
        WatchdogInit();
 
        // Load modules
        if (!LoadNetXMSModules())
                return FALSE;   // Mandatory module not loaded
+       RegisterPredictionEngines();
 
        // Initialize mailer and SMS sender
        InitMailer();
@@ -747,7 +896,7 @@ retry_db_lock:
                nxlog_write(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
                return FALSE;
        }
-       DbgPrintf(2, _T("User accounts loaded"));
+       nxlog_debug(2, _T("User accounts loaded"));
 
        // Initialize audit
        InitAuditLog();
@@ -757,6 +906,7 @@ retry_db_lock:
                return FALSE;
 
        // Initialize alarms
+   LoadAlarmCategories();
        if (!InitAlarmManager())
                return FALSE;
 
@@ -765,12 +915,7 @@ retry_db_lock:
        ObjectsInit();
        if (!LoadObjects())
                return FALSE;
-       DbgPrintf(1, _T("Objects loaded and initialized"));
-
-       // Initialize situations
-       if (!SituationsInit())
-               return FALSE;
-       DbgPrintf(1, _T("Situations loaded and initialized"));
+       nxlog_debug(1, _T("Objects loaded and initialized"));
 
        // Initialize and load event actions
        if (!InitActions())
@@ -785,13 +930,16 @@ retry_db_lock:
 
        // Initialize data collection subsystem
    LoadPerfDataStorageDrivers();
-       if (!InitDataCollector())
-               return FALSE;
+       InitDataCollector();
 
        InitLogAccess();
        FileUploadJob::init();
        InitMappingTables();
 
+   InitClientListeners();
+       if (ConfigReadInt(_T("ImportConfigurationOnStartup"), 1))
+          ImportLocalConfiguration();
+
        // Check if management node object presented in database
        CheckForMgmtNode();
        if (g_dwMgmtNode == 0)
@@ -805,9 +953,10 @@ retry_db_lock:
        ThreadCreate(NodePoller, 0, NULL);
        ThreadCreate(JobManagerThread, 0, NULL);
        m_thSyncer = ThreadCreateEx(Syncer, 0, NULL);
-       m_thHouseKeeper = ThreadCreateEx(HouseKeeper, 0, NULL);
        m_thPollManager = ThreadCreateEx(PollManager, 0, NULL);
 
+   StartHouseKeeper();
+
        // Start event processor
        ThreadCreate(EventProcessor, 0, NULL);
 
@@ -817,16 +966,11 @@ retry_db_lock:
                ThreadCreate(SNMPTrapReceiver, 0, NULL);
 
        // Start built-in syslog daemon
-       if (ConfigReadInt(_T("EnableSyslogDaemon"), 0))
-               m_thSyslogDaemon = ThreadCreateEx(SyslogDaemon, 0, NULL);
+   StartSyslogServer();
 
        // Start database _T("lazy") write thread
        StartDBWriter();
 
-       // Start local administartive interface listener if required
-       if (ConfigReadInt(_T("EnableAdminInterface"), 1))
-               ThreadCreate(LocalAdminListener, 0, NULL);
-
        // Start beacon host poller
        ThreadCreate(BeaconPoller, 0, NULL);
 
@@ -842,30 +986,34 @@ retry_db_lock:
    if (ConfigReadInt(_T("LdapSyncInterval"), 0))
                ThreadCreate(SyncLDAPUsers, 0, NULL);
 
-   //Add schedule callbacks
-   AddSchedulleTaskHandler(_T("Execute.Script"), ExecuteScript);
-
-   //initialize shedule
+   RegisterSchedulerTaskHandler(_T("Execute.Script"), ExecuteScheduledScript, SYSTEM_ACCESS_SCHEDULE_SCRIPT);
+   RegisterSchedulerTaskHandler(_T("Maintenance.Enter"), MaintenanceModeEnter, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
+   RegisterSchedulerTaskHandler(_T("Maintenance.Leave"), MaintenanceModeLeave, SYSTEM_ACCESS_SCHEDULE_MAINTENANCE);
+       RegisterSchedulerTaskHandler(_T("Policy.Deploy"), ScheduleDeployPolicy, 0); //No access right beacause it will be used only by server
+       RegisterSchedulerTaskHandler(_T("Policy.Uninstall"), ScheduleUninstallPolicy, 0); //No access right beacause it will be used only by server
+   RegisterSchedulerTaskHandler(ALARM_SUMMARY_EMAIL_TASK_ID, SendAlarmSummaryEmail, 0); //No access right beacause it will be used only by server
    InitializeTaskScheduler();
 
+   // Send summary emails
+   if (ConfigReadInt(_T("EnableAlarmSummaryEmails"), 0))
+      EnableAlarmSummaryEmails();
+   else
+      RemoveScheduledTaskByHandlerId(ALARM_SUMMARY_EMAIL_TASK_ID);
+
        // Allow clients to connect
-       InitClientListeners();
-       ThreadCreate(ClientListener, 0, NULL);
-#ifdef WITH_IPV6
-       ThreadCreate(ClientListenerIPv6, 0, NULL);
-#endif
+       ThreadCreate(ClientListenerThread, 0, NULL);
 
        // Allow mobile devices to connect
        InitMobileDeviceListeners();
-       ThreadCreate(MobileDeviceListener, 0, NULL);
-#ifdef WITH_IPV6
-       ThreadCreate(MobileDeviceListenerIPv6, 0, NULL);
-#endif
+       ThreadCreate(MobileDeviceListenerThread, 0, NULL);
+
+       // Agent tunnels
+   s_tunnelListenerThread = ThreadCreateEx(TunnelListenerThread, 0, NULL);
 
        // Start uptime calculator for SLM
        ThreadCreate(UptimeCalculator, 0, NULL);
 
-       DbgPrintf(2, _T("LIBDIR: %s"), g_netxmsdLibDir);
+       nxlog_debug(2, _T("LIBDIR: %s"), g_netxmsdLibDir);
 
        // Call startup functions for the modules
    CALL_ALL_MODULES(pfServerStarted, ());
@@ -873,12 +1021,18 @@ retry_db_lock:
 #if XMPP_SUPPORTED
    if (ConfigReadInt(_T("EnableXMPPConnector"), 1))
    {
-      m_thXMPPConnector = ThreadCreateEx(XMPPConnectionManager, 0, NULL);
+      StartXMPPConnector();
    }
 #endif
 
+#if WITH_ZMQ
+   StartZMQConnector();
+#endif
+
+   ExecuteStartupScripts();
+
        g_flags |= AF_SERVER_INITIALIZED;
-       DbgPrintf(1, _T("Server initialization completed"));
+       nxlog_debug(1, _T("Server initialization completed"));
        return TRUE;
 }
 
@@ -894,7 +1048,6 @@ void NXCORE_EXPORTABLE Shutdown()
        g_flags |= AF_SHUTDOWN;     // Set shutdown flag
        ConditionSet(m_condShutdown);
 
-   //shutdown schedule
    CloseTaskScheduler();
 
    // Stop DCI cache loading thread
@@ -904,14 +1057,10 @@ void NXCORE_EXPORTABLE Shutdown()
    StopXMPPConnector();
 #endif
 
-#ifndef _WIN32
-       if (IsStandalone() && (m_nShutdownReason != SHUTDOWN_BY_SIGNAL))
-       {
-               pthread_kill(m_signalHandlerThread, SIGUSR1);   // Terminate signal handler
-       }
+#if WITH_ZMQ
+   StopZMQConnector();
 #endif
 
-       // Stop event processor
        g_pEventQueue->clear();
        g_pEventQueue->put(INVALID_POINTER_VALUE);
 
@@ -919,16 +1068,17 @@ void NXCORE_EXPORTABLE Shutdown()
        ShutdownSMSSender();
 
        ThreadSleep(1);     // Give other threads a chance to terminate in a safe way
-       DbgPrintf(2, _T("All threads was notified, continue with shutdown"));
+       nxlog_debug(2, _T("All threads was notified, continue with shutdown"));
+
+       StopSyslogServer();
+       StopHouseKeeper();
 
        // Wait for critical threads
-       ThreadJoin(m_thHouseKeeper);
        ThreadJoin(m_thPollManager);
        ThreadJoin(m_thSyncer);
-       ThreadJoin(m_thSyslogDaemon);
-#if XMPP_SUPPORTED
-   ThreadJoin(m_thXMPPConnector);
-#endif
+       ThreadJoin(s_tunnelListenerThread);
+
+       CloseAgentTunnels();
 
        // Call shutdown functions for the modules
    // CALL_ALL_MODULES cannot be used here because it checks for shutdown flag
@@ -938,37 +1088,42 @@ void NXCORE_EXPORTABLE Shutdown()
                        g_pModuleList[i].pfShutdown();
        }
 
-       SaveObjects(g_hCoreDB);
-       DbgPrintf(2, _T("All objects saved to database"));
-       SaveUsers(g_hCoreDB);
-       DbgPrintf(2, _T("All users saved to database"));
+   StopDataCollection();
+   StopObjectMaintenanceThreads();
+
+   DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
+       SaveObjects(hdb, INVALID_INDEX, true);
+       nxlog_debug(2, _T("All objects saved to database"));
+       SaveUsers(hdb, INVALID_INDEX);
+       nxlog_debug(2, _T("All users saved to database"));
+   UpdatePStorageDatabase(hdb, INVALID_INDEX);
+       nxlog_debug(2, _T("All persistent storage values saved"));
+       DBConnectionPoolReleaseConnection(hdb);
+
        StopDBWriter();
-       DbgPrintf(1, _T("Database writer stopped"));
+       nxlog_debug(1, _T("Database writer stopped"));
 
        CleanupUsers();
+       PersistentStorageDestroy();
 
        // Remove database lock
        UnlockDB();
 
        DBConnectionPoolShutdown();
-
-       // Disconnect from database and unload driver
-       if (g_hCoreDB != NULL)
-               DBDisconnect(g_hCoreDB);
-
        DBUnloadDriver(g_dbDriver);
-       DbgPrintf(1, _T("Database driver unloaded"));
+       nxlog_debug(1, _T("Database driver unloaded"));
 
        CleanupActions();
        ShutdownEventSubsystem();
    ShutdownAlarmManager();
-       DbgPrintf(1, _T("Event processing stopped"));
+   nxlog_debug(1, _T("Event processing stopped"));
 
+       ThreadPoolDestroy(g_agentConnectionThreadPool);
    ThreadPoolDestroy(g_mainThreadPool);
    MsgWaitQueue::shutdown();
+   WatchdogShutdown();
 
-       delete g_pScriptLibrary;
-
+       nxlog_debug(1, _T("Server shutdown complete"));
        nxlog_close();
 
        // Remove PID file
@@ -990,973 +1145,32 @@ void NXCORE_EXPORTABLE Shutdown()
  */
 void NXCORE_EXPORTABLE FastShutdown()
 {
+   DbgPrintf(1, _T("Using fast shutdown procedure"));
+
        g_flags |= AF_SHUTDOWN;     // Set shutdown flag
        ConditionSet(m_condShutdown);
 
-       SaveObjects(g_hCoreDB);
+       DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
+       SaveObjects(hdb, INVALID_INDEX, true);
        DbgPrintf(2, _T("All objects saved to database"));
-       SaveUsers(g_hCoreDB);
+       SaveUsers(hdb, INVALID_INDEX);
        DbgPrintf(2, _T("All users saved to database"));
+   UpdatePStorageDatabase(hdb, INVALID_INDEX);
+       DbgPrintf(2, _T("All persistent storage values saved"));
+       DBConnectionPoolReleaseConnection(hdb);
 
-       // Remove database lock first, because we have a chance to loose DB connection
+       // Remove database lock first, because we have a chance to lose DB connection
        UnlockDB();
 
        // Stop database writers
        StopDBWriter();
        DbgPrintf(1, _T("Database writer stopped"));
 
+   DbgPrintf(1, _T("Server shutdown complete"));
        nxlog_close();
 }
 
 /**
- * Compare given string to command template with abbreviation possibility
- */
-static bool IsCommand(const TCHAR *cmdTemplate, TCHAR *pszString, int iMinChars)
-{
-       int i;
-
-       // Convert given string to uppercase
-       _tcsupr(pszString);
-
-       for(i = 0; pszString[i] != 0; i++)
-               if (pszString[i] != cmdTemplate[i])
-                       return false;
-       if (i < iMinChars)
-               return false;
-       return true;
-}
-
-/**
- * Dump index callback (by IP address)
- */
-static void DumpIndexCallbackByInetAddr(const InetAddress& addr, NetObj *object, void *data)
-{
-       TCHAR buffer[64];
-       ConsolePrintf((CONSOLE_CTX)data, _T("%-40s %p %s [%d]\n"), addr.toString(buffer), object, object->getName(), (int)object->getId());
-}
-
-/**
- * Dump index (by IP address)
- */
-static void DumpIndex(CONSOLE_CTX pCtx, InetAddressIndex *index)
-{
-       index->forEach(DumpIndexCallbackByInetAddr, pCtx);
-}
-
-/**
- * Dump index callback (by ID)
- */
-static void DumpIndexCallbackById(NetObj *object, void *data)
-{
-       ConsolePrintf((CONSOLE_CTX)data, _T("%08X %p %s\n"), object->getId(), object, object->getName());
-}
-
-/**
- * Dump index (by ID)
- */
-static void DumpIndex(CONSOLE_CTX pCtx, ObjectIndex *index)
-{
-       index->forEach(DumpIndexCallbackById, pCtx);
-}
-
-/**
- * Process command entered from command line in standalone mode
- * Return TRUE if command was _T("down")
- */
-int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
-{
-       const TCHAR *pArg;
-       TCHAR szBuffer[256], *eptr;
-       int nExitCode = CMD_EXIT_CONTINUE;
-
-       // Get command
-       pArg = ExtractWord(pszCmdLine, szBuffer);
-
-       if (IsCommand(_T("DEBUG"), szBuffer, 2))
-       {
-               // Get argument
-               pArg = ExtractWord(pArg, szBuffer);
-               int level = (int)_tcstol(szBuffer, &eptr, 0);
-               if ((*eptr == 0) && (level >= 0) && (level <= 9))
-               {
-                       g_debugLevel = (UINT32)level;
-                       ConsolePrintf(pCtx, (level == 0) ? _T("Debug mode turned off\n") : _T("Debug level set to %d\n"), level);
-               }
-               else if (IsCommand(_T("OFF"), szBuffer, 2))
-               {
-                       g_debugLevel = 0;
-                       ConsoleWrite(pCtx, _T("Debug mode turned off\n"));
-               }
-               else
-               {
-                       if (szBuffer[0] == 0)
-                               ConsoleWrite(pCtx, _T("ERROR: Missing argument\n\n"));
-                       else
-                               ConsoleWrite(pCtx, _T("ERROR: Invalid debug level\n\n"));
-               }
-       }
-       else if (IsCommand(_T("DOWN"), szBuffer, 4))
-       {
-               ConsoleWrite(pCtx, _T("Proceeding with server shutdown...\n"));
-               nExitCode = CMD_EXIT_SHUTDOWN;
-       }
-       else if (IsCommand(_T("DUMP"), szBuffer, 4))
-       {
-               DumpProcess(pCtx);
-       }
-       else if (IsCommand(_T("GET"), szBuffer, 3))
-       {
-               pArg = ExtractWord(pArg, szBuffer);
-               if (szBuffer[0] != 0)
-               {
-                       TCHAR value[MAX_CONFIG_VALUE];
-                       ConfigReadStr(szBuffer, value, MAX_CONFIG_VALUE, _T(""));
-                       ConsolePrintf(pCtx, _T("%s = %s\n"), szBuffer, value);
-               }
-               else
-               {
-                       ConsoleWrite(pCtx, _T("Variable name missing\n"));
-               }
-       }
-       else if (IsCommand(_T("RAISE"), szBuffer, 5))
-       {
-               // Get argument
-               pArg = ExtractWord(pArg, szBuffer);
-
-               if (IsCommand(_T("ACCESS"), szBuffer, 6))
-               {
-                       ConsoleWrite(pCtx, _T("Raising exception...\n"));
-                       char *p = NULL;
-                       *p = 0;
-               }
-               else if (IsCommand(_T("BREAKPOINT"), szBuffer, 5))
-               {
-#ifdef _WIN32
-                       ConsoleWrite(pCtx, _T("Raising exception...\n"));
-                       RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
-#else
-                       ConsoleWrite(pCtx, _T("ERROR: Not supported on current platform\n"));
-#endif
-               }
-               else
-               {
-                       ConsoleWrite(pCtx, _T("Invalid exception name; possible names are:\nACCESS BREAKPOINT\n"));
-               }
-       }
-       else if (IsCommand(_T("EXIT"), szBuffer, 4))
-       {
-               if ((pCtx->hSocket != -1) || (pCtx->session != NULL))
-               {
-                       ConsoleWrite(pCtx, _T("Closing session...\n"));
-                       nExitCode = CMD_EXIT_CLOSE_SESSION;
-               }
-               else
-               {
-                       ConsoleWrite(pCtx, _T("Cannot exit from local server console\n"));
-               }
-       }
-       else if (IsCommand(_T("KILL"), szBuffer, 4))
-       {
-               pArg = ExtractWord(pArg, szBuffer);
-               if (szBuffer[0] != 0)
-               {
-         int id = _tcstol(szBuffer, &eptr, 10);
-         if (*eptr == 0)
-         {
-            if (KillClientSession(id))
-            {
-                       ConsoleWrite(pCtx, _T("Session killed\n"));
-            }
-            else
-            {
-                       ConsoleWrite(pCtx, _T("Invalid session ID\n"));
-            }
-         }
-         else
-         {
-                       ConsoleWrite(pCtx, _T("Invalid session ID\n"));
-         }
-               }
-               else
-               {
-                       ConsoleWrite(pCtx, _T("Session ID missing\n"));
-               }
-   }
-       else if (IsCommand(_T("PING"), szBuffer, 4))
-       {
-               pArg = ExtractWord(pArg, szBuffer);
-               if (szBuffer[0] != 0)
-               {
-         InetAddress addr = InetAddress::parse(szBuffer);
-         if (addr.isValid())
-         {
-            UINT32 rtt;
-            UINT32 rc = IcmpPing(addr, 1, 2000, &rtt, 128);
-            switch(rc)
-            {
-               case ICMP_SUCCESS:
-                  ConsolePrintf(pCtx, _T("Success, RTT = %d ms\n"), (int)rtt);
-                  break;
-               case ICMP_UNREACHEABLE:
-                  ConsolePrintf(pCtx, _T("Destination unreachable\n"));
-                  break;
-               case ICMP_TIMEOUT:
-                  ConsolePrintf(pCtx, _T("Request timeout\n"));
-                  break;
-               case ICMP_RAW_SOCK_FAILED:
-                  ConsolePrintf(pCtx, _T("Cannot create raw socket\n"));
-                  break;
-               case ICMP_API_ERROR:
-                  ConsolePrintf(pCtx, _T("API error\n"));
-                  break;
-               default:
-                  ConsolePrintf(pCtx, _T("ERROR %d\n"), (int)rc);
-                  break;
-            }
-         }
-         else
-         {
-            ConsoleWrite(pCtx, _T("Invalid IP address\n"));
-         }
-      }
-      else
-      {
-         ConsoleWrite(pCtx, _T("Usage: PING <address>\n"));
-      }
-   }
-       else if (IsCommand(_T("POLL"), szBuffer, 2))
-       {
-               pArg = ExtractWord(pArg, szBuffer);
-               if (szBuffer[0] != 0)
-               {
-         int pollType;
-         if (IsCommand(_T("CONFIGURATION"), szBuffer, 1))
-         {
-            pollType = 1;
-         }
-         else if (IsCommand(_T("STATUS"), szBuffer, 1))
-         {
-            pollType = 2;
-         }
-         else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
-         {
-            pollType = 3;
-         }
-         else
-         {
-            pollType = 0;
-         }
-
-         if (pollType > 0)
-         {
-               pArg = ExtractWord(pArg, szBuffer);
-                          UINT32 id = _tcstoul(szBuffer, NULL, 0);
-                          if (id != 0)
-                          {
-                                  Node *node = (Node *)FindObjectById(id, OBJECT_NODE);
-                                  if (node != NULL)
-                                  {
-                  switch(pollType)
-                  {
-                     case 1:
-                                           node->lockForConfigurationPoll();
-                        ThreadPoolExecute(g_pollerThreadPool, node, &Node::configurationPoll, RegisterPoller(POLLER_TYPE_CONFIGURATION, node));
-                        break;
-                     case 2:
-                                               node->lockForStatusPoll();
-                        ThreadPoolExecute(g_pollerThreadPool, node, &Node::statusPoll, RegisterPoller(POLLER_TYPE_STATUS, node));
-                        break;
-                     case 3:
-                                               node->lockForTopologyPoll();
-                        ThreadPoolExecute(g_pollerThreadPool, node, &Node::topologyPoll, RegisterPoller(POLLER_TYPE_TOPOLOGY, node));
-                        break;
-                  }
-                                  }
-                                  else
-                                  {
-                                          ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), id);
-                                  }
-                          }
-                          else
-                          {
-                                  ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
-                          }
-         }
-         else
-         {
-                       ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|STATUS|TOPOLOGY] <node>\n"));
-         }
-               }
-               else
-               {
-                       ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|STATUS|TOPOLOGY] <node>\n"));
-               }
-       }
-       else if (IsCommand(_T("SET"), szBuffer, 3))
-       {
-               pArg = ExtractWord(pArg, szBuffer);
-               if (szBuffer[0] != 0)
-               {
-                       TCHAR value[256];
-                       pArg = ExtractWord(pArg, value);
-                       if (ConfigWriteStr(szBuffer, value, TRUE, TRUE, TRUE))
-                       {
-                               ConsolePrintf(pCtx, _T("Configuration variable %s updated\n"), szBuffer);
-                       }
-                       else
-                       {
-                               ConsolePrintf(pCtx, _T("ERROR: cannot update configuration variable %s\n"), szBuffer);
-                       }
-               }
-               else
-               {
-                       ConsolePrintf(pCtx, _T("Variable name missing\n"));
-               }
-       }
-       else if (IsCommand(_T("SHOW"), szBuffer, 2))
-       {
-               // Get argument
-               pArg = ExtractWord(pArg, szBuffer);
-
-               if (IsCommand(_T("COMPONENTS"), szBuffer, 1))
-               {
-                       // Get argument
-                       pArg = ExtractWord(pArg, szBuffer);
-                       UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
-                       if (dwNode != 0)
-                       {
-                               NetObj *pObject = FindObjectById(dwNode);
-                               if (pObject != NULL)
-                               {
-                                       if (pObject->getObjectClass() == OBJECT_NODE)
-                                       {
-                                               ComponentTree *components = ((Node *)pObject)->getComponents();
-                                               if (components != NULL)
-                                               {
-                                                       components->print(pCtx);
-                                                       components->decRefCount();
-                                               }
-                                               else
-                                               {
-                                                       ConsoleWrite(pCtx, _T("ERROR: Node does not have physical component information\n\n"));
-                                               }
-                                       }
-                                       else
-                                       {
-                                               ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
-                                       }
-                               }
-                               else
-                               {
-                                       ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
-                               }
-                       }
-                       else
-                       {
-                               ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
-                       }
-               }
-               else if (IsCommand(_T("DBCP"), szBuffer, 4))
-               {
-         ObjectArray<PoolConnectionInfo> *list = DBConnectionPoolGetConnectionList();
-         for(int i = 0; i < list->size(); i++)
-         {
-            PoolConnectionInfo *c = list->get(i);
-            TCHAR accessTime[64];
-            struct tm *ltm = localtime(&c->lastAccessTime);
-            _tcsftime(accessTime, 64, _T("%d.%b.%Y %H:%M:%S"), ltm);
-            ConsolePrintf(pCtx, _T("%p %s %hs:%d\n"), c->handle, accessTime, c->srcFile, c->srcLine);
-         }
-         ConsolePrintf(pCtx, _T("%d database connections in use\n\n"), list->size());
-         delete list;
-      }
-               else if (IsCommand(_T("FDB"), szBuffer, 3))
-               {
-                       // Get argument
-                       pArg = ExtractWord(pArg, szBuffer);
-                       UINT32 dwNode = _tcstoul(szBuffer, NULL, 0);
-                       if (dwNode != 0)
-                       {
-                               NetObj *pObject = FindObjectById(dwNode);
-                               if (pObject != NULL)
-                               {
-                                       if (pObject->getObjectClass() == OBJECT_NODE)
-                                       {
-                  ForwardingDatabase *fdb = ((Node *)pObject)->getSwitchForwardingDatabase();
-                                               if (fdb != NULL)
-                                               {
-                                                       fdb->print(pCtx, (Node *)pObject);
-                                                       fdb->decRefCount();
-                                               }
-                                               else
-                                               {
-                                                       ConsoleWrite(pCtx, _T("ERROR: Node does not have forwarding database information\n\n"));
-                                               }
-                                       }
-                                       else
-                                       {
-                                               ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
-                                       }
-                               }
-                               else
-                               {
-                                       ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
-                               }
-                       }
-                       else
-                       {
-                               ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
-                       }
-               }
-               else if (IsCommand(_T("FLAGS"), szBuffer, 1))
-               {
-         ConsolePrintf(pCtx, _T("Flags: 0x") UINT64X_FMT(_T("016")) _T("\n"), g_flags);
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DAEMON));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSLOG));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NETWORK_DISCOVERY));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ACTIVE_NETWORK_DISCOVERY));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_SQL_ERRORS));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DELETE_EMPTY_SUBNETS));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_SNMP_TRAPD));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_ZONING));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYNC_NODE_NAMES_WITH_DNS));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CHECK_TRUSTED_NODES));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NXSL_CONTAINER_FUNCS));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_FQDN_FOR_NODE_NAMES));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DEBUG_CONSOLE_DISABLED));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_OBJECT_TRANSACTIONS));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_WRITE_FULL_DUMP));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_NODE_NAMES));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CATCH_EXCEPTIONS));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_HELPDESK_LINK_ACTIVE));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_LOCKED));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_MULTIPLE_DB_CONN));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_CONNECTION_LOST));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_NO_NETWORK_CONNECTIVITY));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_EVENT_STORM_DETECTED));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SNMP_TRAP_DISCOVERY));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAPS_FROM_UNMANAGED_NODES));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_IP_FOR_EACH_STATUS_POLL));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_PERFDATA_STORAGE_DRIVER_LOADED));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_BACKGROUND_LOG_WRITER));
-         ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CASE_INSENSITIVE_LOGINS));
-         ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAP_SOURCES_IN_ALL_ZONES));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SERVER_INITIALIZED));
-                       ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SHUTDOWN));
-                       ConsolePrintf(pCtx, _T("\n"));
-               }
-               else if (IsCommand(_T("HEAP"), szBuffer, 1))
-               {
-         TCHAR *text = GetHeapInfo();
-         if (text != NULL)
-         {
-            ConsoleWrite(pCtx, text);
-            ConsoleWrite(pCtx, _T("\n"));
-            free(text);
-         }
-         else
-         {
-            ConsoleWrite(pCtx, _T("Error reading heap information\n"));
-         }
-      }
-               else if (IsCommand(_T("INDEX"), szBuffer, 1))
-               {
-                       // Get argument
-                       pArg = ExtractWord(pArg, szBuffer);
-
-                       if (IsCommand(_T("CONDITION"), szBuffer, 1))
-                       {
-                               DumpIndex(pCtx, &g_idxConditionById);
-                       }
-                       else if (IsCommand(_T("ID"), szBuffer, 2))
-                       {
-                               DumpIndex(pCtx, &g_idxObjectById);
-                       }
-                       else if (IsCommand(_T("INTERFACE"), szBuffer, 2))
-                       {
-                               DumpIndex(pCtx, &g_idxInterfaceByAddr);
-                       }
-                       else if (IsCommand(_T("NODEADDR"), szBuffer, 5))
-                       {
-                               DumpIndex(pCtx, &g_idxNodeByAddr);
-                       }
-                       else if (IsCommand(_T("NODEID"), szBuffer, 5))
-                       {
-                               DumpIndex(pCtx, &g_idxNodeById);
-                       }
-                       else if (IsCommand(_T("SUBNET"), szBuffer, 1))
-                       {
-                               DumpIndex(pCtx, &g_idxSubnetByAddr);
-                       }
-                       else if (IsCommand(_T("ZONE"), szBuffer, 1))
-                       {
-                               DumpIndex(pCtx, &g_idxZoneByGUID);
-                       }
-                       else
-                       {
-                               if (szBuffer[0] == 0)
-                                       ConsoleWrite(pCtx, _T("ERROR: Missing index name\n")
-                                                                    _T("Valid names are: CONDITION, ID, INTERFACE, NODEADDR, NODEID, SUBNET, ZONE\n\n"));
-                               else
-                                       ConsoleWrite(pCtx, _T("ERROR: Invalid index name\n\n"));
-                       }
-               }
-               else if (IsCommand(_T("MODULES"), szBuffer, 3))
-               {
-         ConsoleWrite(pCtx, _T("Loaded server modules:\n"));
-         for(UINT32 i = 0; i < g_dwNumModules; i++)
-         {
-            ConsolePrintf(pCtx, _T("   %s\n"), g_pModuleList[i].szName);
-         }
-         ConsolePrintf(pCtx, _T("%d modules loaded\n"), g_dwNumModules);
-               }
-               else if (IsCommand(_T("MSGWQ"), szBuffer, 2))
-               {
-         String text = MsgWaitQueue::getDiagInfo();
-         ConsoleWrite(pCtx, text);
-         ConsoleWrite(pCtx, _T("\n"));
-      }
-               else if (IsCommand(_T("OBJECTS"), szBuffer, 1))
-               {
-                       // Get filter
-                       pArg = ExtractWord(pArg, szBuffer);
-         StrStrip(szBuffer);
-         DumpObjects(pCtx, (szBuffer[0] != 0) ? szBuffer : NULL);
-               }
-               else if (IsCommand(_T("POLLERS"), szBuffer, 1))
-               {
-                       ShowPollers(pCtx);
-               }
-               else if (IsCommand(_T("QUEUES"), szBuffer, 1))
-               {
-                       ShowQueueStats(pCtx, &g_dataCollectionQueue, _T("Data collector"));
-                       ShowQueueStats(pCtx, &g_dciCacheLoaderQueue, _T("DCI cache loader"));
-                       ShowQueueStats(pCtx, g_dbWriterQueue, _T("Database writer"));
-                       ShowQueueStats(pCtx, g_dciDataWriterQueue, _T("Database writer (IData)"));
-                       ShowQueueStats(pCtx, g_dciRawDataWriterQueue, _T("Database writer (raw DCI values)"));
-                       ShowQueueStats(pCtx, g_pEventQueue, _T("Event processor"));
-                       ShowQueueStats(pCtx, &g_nodePollerQueue, _T("Node poller"));
-                       ShowQueueStats(pCtx, &g_syslogProcessingQueue, _T("Syslog processing"));
-                       ShowQueueStats(pCtx, &g_syslogWriteQueue, _T("Syslog writer"));
-                       ConsolePrintf(pCtx, _T("\n"));
-               }
-               else if (IsCommand(_T("ROUTING-TABLE"), szBuffer, 1))
-               {
-                       UINT32 dwNode;
-                       NetObj *pObject;
-
-                       pArg = ExtractWord(pArg, szBuffer);
-                       dwNode = _tcstoul(szBuffer, NULL, 0);
-                       if (dwNode != 0)
-                       {
-                               pObject = FindObjectById(dwNode);
-                               if (pObject != NULL)
-                               {
-                                       if (pObject->getObjectClass() == OBJECT_NODE)
-                                       {
-                                               ROUTING_TABLE *pRT;
-                                               TCHAR szIpAddr[16];
-                                               int i;
-
-                                               ConsolePrintf(pCtx, _T("Routing table for node %s:\n\n"), pObject->getName());
-                                               pRT = ((Node *)pObject)->getCachedRoutingTable();
-                                               if (pRT != NULL)
-                                               {
-                                                       for(i = 0; i < pRT->iNumEntries; i++)
-                                                       {
-                                                               _sntprintf(szBuffer, 256, _T("%s/%d"), IpToStr(pRT->pRoutes[i].dwDestAddr, szIpAddr),
-                                                                                    BitsInMask(pRT->pRoutes[i].dwDestMask));
-                                                               ConsolePrintf(pCtx, _T("%-18s %-15s %-6d %d\n"), szBuffer,
-                                                                                       IpToStr(pRT->pRoutes[i].dwNextHop, szIpAddr),
-                                                                                       pRT->pRoutes[i].dwIfIndex, pRT->pRoutes[i].dwRouteType);
-                                                       }
-                                                       ConsoleWrite(pCtx, _T("\n"));
-                                               }
-                                               else
-                                               {
-                                                       ConsoleWrite(pCtx, _T("Node doesn't have cached routing table\n\n"));
-                                               }
-                                       }
-                                       else
-                                       {
-                                               ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
-                                       }
-                               }
-                               else
-                               {
-                                       ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
-                               }
-                       }
-                       else
-                       {
-                               ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
-                       }
-               }
-               else if (IsCommand(_T("SESSIONS"), szBuffer, 2))
-               {
-                       ConsoleWrite(pCtx, _T("\x1b[1mCLIENT SESSIONS\x1b[0m\n============================================================\n"));
-                       DumpClientSessions(pCtx);
-                       ConsoleWrite(pCtx, _T("\n\x1b[1mMOBILE DEVICE SESSIONS\x1b[0m\n============================================================\n"));
-                       DumpMobileDeviceSessions(pCtx);
-               }
-               else if (IsCommand(_T("STATS"), szBuffer, 2))
-               {
-                       ShowServerStats(pCtx);
-               }
-               else if (IsCommand(_T("THREADS"), szBuffer, 2))
-               {
-                       ShowThreadPool(pCtx, g_mainThreadPool);
-                       ShowThreadPool(pCtx, g_pollerThreadPool);
-               }
-               else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
-               {
-                       pArg = ExtractWord(pArg, szBuffer);
-                       UINT32 nodeId = _tcstoul(szBuffer, NULL, 0);
-                       if (nodeId != 0)
-                       {
-                               Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
-                               if (node != NULL)
-                               {
-               LinkLayerNeighbors *nbs = BuildLinkLayerNeighborList(node);
-               if (nbs != NULL)
-               {
-                  ConsolePrintf(pCtx, _T("Proto   | PtP | ifLocal | ifRemote | Peer\n")
-                                      _T("--------+-----+---------+----------+------------------------------------\n"));
-                  for(int i = 0; i < nbs->size(); i++)
-                  {
-                               LL_NEIGHBOR_INFO *ni = nbs->getConnection(i);
-                     TCHAR peer[256];
-                     if (ni->objectId != 0)
-                     {
-                        NetObj *object = FindObjectById(ni->objectId);
-                        if (object != NULL)
-                           _sntprintf(peer, 256, _T("%s [%d]"), object->getName(), ni->objectId);
-                        else
-                           _sntprintf(peer, 256, _T("[%d]"), ni->objectId);
-                     }
-                     else
-                     {
-                        peer[0] = 0;
-                     }
-                     ConsolePrintf(pCtx, _T("%-7s | %c   | %7d | %7d | %s\n"),
-                        GetLinkLayerProtocolName(ni->protocol), ni->isPtToPt ? _T('Y') : _T('N'), ni->ifLocal, ni->ifRemote, peer);
-                  }
-                  nbs->decRefCount();
-               }
-               else
-               {
-                                       ConsoleWrite(pCtx, _T("ERROR: call to BuildLinkLayerNeighborList failed\n\n"));
-               }
-                               }
-                               else
-                               {
-                                       ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), nodeId);
-                               }
-                       }
-                       else
-                       {
-                               ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
-                       }
-               }
-               else if (IsCommand(_T("USERS"), szBuffer, 1))
-               {
-                       DumpUsers(pCtx);
-               }
-               else if (IsCommand(_T("VLANS"), szBuffer, 1))
-               {
-                       UINT32 dwNode;
-                       NetObj *pObject;
-
-                       pArg = ExtractWord(pArg, szBuffer);
-                       dwNode = _tcstoul(szBuffer, NULL, 0);
-                       if (dwNode != 0)
-                       {
-                               pObject = FindObjectById(dwNode);
-                               if (pObject != NULL)
-                               {
-                                       if (pObject->getObjectClass() == OBJECT_NODE)
-                                       {
-                                               VlanList *vlans = ((Node *)pObject)->getVlans();
-                                               if (vlans != NULL)
-                                               {
-                                                       ConsoleWrite(pCtx, _T("\x1b[1mVLAN\x1b[0m | \x1b[1mName\x1b[0m             | \x1b[1mPorts\x1b[0m\n")
-                                                                               _T("-----+------------------+-----------------------------------------------------------------\n"));
-                                                       for(int i = 0; i < vlans->size(); i++)
-                                                       {
-                                                               VlanInfo *vlan = vlans->get(i);
-                                                               ConsolePrintf(pCtx, _T("%4d | %-16s |"), vlan->getVlanId(), vlan->getName());
-                                                               for(int j = 0; j < vlan->getNumPorts(); j++)
-                                                                       ConsolePrintf(pCtx, _T(" %d.%d"), (int)(vlan->getPorts()[j] >> 16), (int)(vlan->getPorts()[j] & 0xFFFF));
-                                                               ConsolePrintf(pCtx, _T("\n"));
-                                                       }
-                                                       ConsolePrintf(pCtx, _T("\n"));
-                                                       vlans->decRefCount();
-                                               }
-                                               else
-                                               {
-                                                       ConsoleWrite(pCtx, _T("\x1b[31mNode doesn't have VLAN information\x1b[0m\n\n"));
-                                               }
-                                       }
-                                       else
-                                       {
-                                               ConsoleWrite(pCtx, _T("\x1b[31mERROR: Object is not a node\x1b[0m\n\n"));
-                                       }
-                               }
-                               else
-                               {
-                                       ConsolePrintf(pCtx, _T("\x1b[31mERROR: Object with ID %d does not exist\x1b[0m\n\n"), dwNode);
-                               }
-                       }
-                       else
-                       {
-                               ConsoleWrite(pCtx, _T("\x1b[31mERROR: Invalid or missing node ID\x1b[0m\n\n"));
-                       }
-               }
-               else if (IsCommand(_T("WATCHDOG"), szBuffer, 1))
-               {
-                       WatchdogPrintStatus(pCtx);
-                       ConsoleWrite(pCtx, _T("\n"));
-               }
-               else
-               {
-                       if (szBuffer[0] == 0)
-                               ConsoleWrite(pCtx, _T("ERROR: Missing subcommand\n\n"));
-                       else
-                               ConsoleWrite(pCtx, _T("ERROR: Invalid SHOW subcommand\n\n"));
-               }
-       }
-       else if (IsCommand(_T("EXEC"), szBuffer, 3))
-       {
-               pArg = ExtractWord(pArg, szBuffer);
-
-               bool libraryLocked = true;
-      bool destroyCompiledScript = false;
-               g_pScriptLibrary->lock();
-
-               NXSL_Program *compiledScript = g_pScriptLibrary->findScript(szBuffer);
-               if (compiledScript == NULL)
-               {
-                       g_pScriptLibrary->unlock();
-                       libraryLocked = false;
-         destroyCompiledScript = true;
-                       char *script;
-                       UINT32 fileSize;
-                       if ((script = (char *)LoadFile(szBuffer, &fileSize)) != NULL)
-                       {
-                               const int errorMsgLen = 512;
-                               TCHAR errorMsg[errorMsgLen];
-#ifdef UNICODE
-                               WCHAR *wscript = WideStringFromMBString(script);
-                               compiledScript = NXSLCompile(wscript, errorMsg, errorMsgLen, NULL);
-                               free(wscript);
-#else
-                               compiledScript = NXSLCompile(script, errorMsg, errorMsgLen, NULL);
-#endif
-                               free(script);
-                               if (compiledScript == NULL)
-                               {
-                                       ConsolePrintf(pCtx, _T("ERROR: Script compilation error: %s\n\n"), errorMsg);
-                               }
-                       }
-                       else
-                       {
-                               ConsolePrintf(pCtx, _T("ERROR: Script \"%s\" not found\n\n"), szBuffer);
-                       }
-               }
-
-               if (compiledScript != NULL)
-               {
-                       NXSL_ServerEnv *pEnv = new NXSL_ServerEnv;
-                       pEnv->setConsole(pCtx);
-
-         NXSL_VM *vm = new NXSL_VM(pEnv);
-         if (vm->load(compiledScript))
-         {
-            if (libraryLocked)
-            {
-                       g_pScriptLibrary->unlock();
-               libraryLocked = false;
-            }
-
-                          NXSL_Value *argv[32];
-                          int argc = 0;
-                          while(argc < 32)
-                          {
-                                  pArg = ExtractWord(pArg, szBuffer);
-                                  if (szBuffer[0] == 0)
-                                          break;
-                                  argv[argc++] = new NXSL_Value(szBuffer);
-                          }
-
-                          if (vm->run(argc, argv))
-                          {
-                                  NXSL_Value *pValue = vm->getResult();
-                                  int retCode = pValue->getValueAsInt32();
-                                  ConsolePrintf(pCtx, _T("INFO: Script finished with rc=%d\n\n"), retCode);
-                          }
-                          else
-                          {
-                                  ConsolePrintf(pCtx, _T("ERROR: Script finished with error: %s\n\n"), vm->getErrorText());
-                          }
-         }
-         else
-         {
-                          ConsolePrintf(pCtx, _T("ERROR: VM creation failed: %s\n\n"), vm->getErrorText());
-         }
-         delete vm;
-         if (destroyCompiledScript)
-            delete compiledScript;
-               }
-               if (libraryLocked)
-                       g_pScriptLibrary->unlock();
-       }
-       else if (IsCommand(_T("TRACE"), szBuffer, 1))
-       {
-               UINT32 dwNode1, dwNode2;
-               NetObj *pObject1, *pObject2;
-               NetworkPath *pTrace;
-               TCHAR szNextHop[16];
-               int i;
-
-               // Get arguments
-               pArg = ExtractWord(pArg, szBuffer);
-               dwNode1 = _tcstoul(szBuffer, NULL, 0);
-
-               pArg = ExtractWord(pArg, szBuffer);
-               dwNode2 = _tcstoul(szBuffer, NULL, 0);
-
-               if ((dwNode1 != 0) && (dwNode2 != 0))
-               {
-                       pObject1 = FindObjectById(dwNode1);
-                       if (pObject1 == NULL)
-                       {
-                               ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode1);
-                       }
-                       else
-                       {
-                               pObject2 = FindObjectById(dwNode2);
-                               if (pObject2 == NULL)
-                               {
-                                       ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode2);
-                               }
-                               else
-                               {
-                                       if ((pObject1->getObjectClass() == OBJECT_NODE) && (pObject2->getObjectClass() == OBJECT_NODE))
-                                       {
-                                               pTrace = TraceRoute((Node *)pObject1, (Node *)pObject2);
-                                               if (pTrace != NULL)
-                                               {
-                     TCHAR sourceIp[32];
-                                                       ConsolePrintf(pCtx, _T("Trace from %s to %s (%d hops, %s, source IP %s):\n"),
-                                                                       pObject1->getName(), pObject2->getName(), pTrace->getHopCount(),
-                                                                       pTrace->isComplete() ? _T("complete") : _T("incomplete"),
-                           pTrace->getSourceAddress().toString(sourceIp));
-                                                       for(i = 0; i < pTrace->getHopCount(); i++)
-                                                       {
-                                                               HOP_INFO *hop = pTrace->getHopInfo(i);
-                                                               ConsolePrintf(pCtx, _T("[%d] %s %s %s %d\n"),
-                                                                               hop->object->getId(),
-                                                                               hop->object->getName(),
-                                                                               hop->nextHop.toString(szNextHop),
-                                                                               hop->isVpn ? _T("VPN Connector ID:") : _T("Interface Index: "),
-                                                                               hop->ifIndex);
-                                                       }
-                                                       delete pTrace;
-                                                       ConsolePrintf(pCtx, _T("\n"));
-                                               }
-                                               else
-                                               {
-                                                       ConsoleWrite(pCtx, _T("ERROR: Call to TraceRoute() failed\n\n"));
-                                               }
-                                       }
-                                       else
-                                       {
-                                               ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
-                                       }
-                               }
-                       }
-               }
-               else
-               {
-                       ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node id(s)\n\n"));
-               }
-       }
-   else if (IsCommand(_T("LDAPSYNC"), szBuffer, 4))
-   {
-      LDAPConnection conn;
-      conn.syncUsers();
-   }
-   else if (IsCommand(_T("AT"), szBuffer, 2))
-   {
-      pArg = ExtractWord(pArg, szBuffer);
-      TCHAR *params =_tcsdup(szBuffer);
-      ConsoleWrite(pCtx, pArg);
-      ConsoleWrite(pCtx, _T("\n\n"));
-
-      //skip all space and tab characters
-      while(pArg[0] == _T(' ') || pArg[0] == _T('\t') )
-         pArg++;
-
-      if(pArg[0] == _T('+'))
-      {
-         int tm = _tcstoul(pArg+1, NULL, 0);
-         AddOneTimeAction(_T("Execute.Script"), time(NULL) + tm, params);
-      }
-      else
-      {
-         AddSchedule(_T("Execute.Script"), pArg, params);
-      }
-      safe_free(params);
-   }
-       else if (IsCommand(_T("HELP"), szBuffer, 2) || IsCommand(_T("?"), szBuffer, 1))
-       {
-               ConsoleWrite(pCtx,
-            _T("Valid commands are:\n")
-                               _T("   at <shedule> [+seconds from now|cron shedule]       - Set debug level (valid range is 0..9)\n")
-                               _T("   debug [<level>|off]       - Set debug level (valid range is 0..9)\n")
-                               _T("   down                      - Shutdown NetXMS server\n")
-                               _T("   exec <script> [<params>]  - Executes NXSL script from script library\n")
-                               _T("   exit                      - Exit from remote session\n")
-            _T("   kill <session>            - Kill client session\n")
-                               _T("   get <variable>            - Get value of server configuration variable\n")
-                               _T("   help                      - Display this help\n")
-                               _T("   ldapsync                  - Synchronize ldap users with local user database\n")
-            _T("   ping <address>            - Send ICMP echo request to given IP address\n")
-            _T("   poll <type> <node>        - Initiate node poll\n")
-                               _T("   raise <exception>         - Raise exception\n")
-                               _T("   set <variable> <value>    - Set value of server configuration variable\n")
-                               _T("   show components <node>    - Show physical components of given node\n")
-            _T("   show dbcp                 - Show active sessions in database connection pool\n")
-                               _T("   show fdb <node>           - Show forwarding database for node\n")
-                               _T("   show flags                - Show internal server flags\n")
-            _T("   show heap                 - Show heap information\n")
-                               _T("   show index <index>        - Show internal index\n")
-                               _T("   show modules              - Show loaded server modules\n")
-            _T("   show msgwq                - Show message wait queues information\n")
-                               _T("   show objects [<filter>]   - Dump network objects to screen\n")
-                               _T("   show pollers              - Show poller threads state information\n")
-                               _T("   show queues               - Show internal queues statistics\n")
-                               _T("   show routing-table <node> - Show cached routing table for node\n")
-                               _T("   show sessions             - Show active client sessions\n")
-                               _T("   show stats                - Show server statistics\n")
-                               _T("   show topology <node>      - Collect and show link layer topology for node\n")
-                               _T("   show users                - Show users\n")
-                               _T("   show vlans <node>         - Show cached VLAN information for node\n")
-                               _T("   show watchdog             - Display watchdog information\n")
-                               _T("   trace <node1> <node2>     - Show network path trace between two nodes\n")
-                               _T("\nAlmost all commands can be abbreviated to 2 or 3 characters\n")
-                               _T("\n"));
-       }
-   else
-       {
-               ConsoleWrite(pCtx, _T("UNKNOWN COMMAND\n\n"));
-       }
-
-       return nExitCode;
-}
-
-/**
  * Signal handler for UNIX platforms
  */
 #ifndef _WIN32
@@ -1975,7 +1189,6 @@ THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
 {
        sigset_t signals;
        int nSignal;
-       BOOL bCallShutdown = FALSE;
 
        m_signalHandlerThread = pthread_self();
 
@@ -2004,11 +1217,16 @@ THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
                        {
                                case SIGTERM:
                                case SIGINT:
-                                       m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
-                                       if (IsStandalone())
-                                               bCallShutdown = TRUE;
-                                       ConditionSet(m_condShutdown);
-                                       goto stop_handler;
+                                  // avoid repeat Shutdown() call
+                                  if (!(g_flags & AF_SHUTDOWN))
+                                  {
+                  m_nShutdownReason = SHUTDOWN_BY_SIGNAL;
+                  if (IsStandalone())
+                     Shutdown(); // will never return
+                  else
+                     ConditionSet(m_condShutdown);
+                                  }
+                                  break;
                                case SIGSEGV:
                                        abort();
                                        break;
@@ -2032,8 +1250,6 @@ THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL SignalHandler(void *pArg)
 
 stop_handler:
        sigprocmask(SIG_UNBLOCK, &signals, NULL);
-       if (bCallShutdown)
-               Shutdown();
        return THREAD_OK;
 }
 
@@ -2088,7 +1304,11 @@ THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
                           if (ptr != NULL)
                           {
 #ifdef UNICODE
+#if HAVE_MBSTOWCS
+                             mbstowcs(wcCommand, ptr, 255);
+#else
                                   MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ptr, -1, wcCommand, 256);
+#endif
                                   wcCommand[255] = 0;
                                   StrStrip(wcCommand);
                                   if (wcCommand[0] != 0)
@@ -2118,8 +1338,11 @@ THREAD_RESULT NXCORE_EXPORTABLE THREAD_CALL Main(void *pArg)
 #if USE_READLINE
                free(ptr);
 #endif
-                  m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
-                  Shutdown();
+               if (!(g_flags & AF_SHUTDOWN))
+               {
+            m_nShutdownReason = SHUTDOWN_FROM_CONSOLE;
+            Shutdown();
+               }
       }
       else
       {