"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/server/core/console.cpp" (23 Feb 2021, 66898 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "console.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.7.130_vs_3.7.145.

    1 /*
    2 ** NetXMS - Network Management System
    3 ** Copyright (C) 2003-2021 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: console.cpp
   20 **
   21 **/
   22 
   23 #include "nxcore.h"
   24 #include <entity_mib.h>
   25 
   26 /**
   27  * Externals
   28  */
   29 extern ObjectQueue<DiscoveredAddress> g_nodePollerQueue;
   30 extern ObjectQueue<SyslogMessage> g_syslogProcessingQueue;
   31 extern ObjectQueue<SyslogMessage> g_syslogWriteQueue;
   32 extern ObjectQueue<WindowsEvent> g_windowsEventProcessingQueue;
   33 extern ObjectQueue<WindowsEvent> g_windowsEventWriterQueue;
   34 extern ThreadPool *g_pollerThreadPool;
   35 extern ThreadPool *g_schedulerThreadPool;
   36 extern ThreadPool *g_dataCollectorThreadPool;
   37 
   38 void ShowPredictionEngines(CONSOLE_CTX console);
   39 void ShowAgentTunnels(CONSOLE_CTX console);
   40 uint32_t BindAgentTunnel(uint32_t tunnelId, uint32_t nodeId, uint32_t userId);
   41 uint32_t UnbindAgentTunnel(uint32_t nodeId, uint32_t userId);
   42 int64_t GetEventLogWriterQueueSize();
   43 int64_t GetEventProcessorQueueSize();
   44 void DiscoveryPoller(PollerInfo *poller);
   45 void RangeScanCallback(const InetAddress& addr, int32_t zoneUIN, const Node *proxy, uint32_t rtt, ServerConsole *console, void *context);
   46 void CheckRange(const InetAddressListElement& range, void(*callback)(const InetAddress&, int32_t, const Node *, uint32_t, ServerConsole *, void *), ServerConsole *console, void *context);
   47 void ShowSyncerStats(ServerConsole *console);
   48 
   49 /**
   50  * Format string to show value of global flag
   51  */
   52 #define SHOW_FLAG_VALUE(x) _T("  %-38s = %d\n"), _T(#x), (g_flags & x) ? 1 : 0
   53 
   54 /**
   55  * Compare given string to command template with abbreviation possibility
   56  */
   57 bool NXCORE_EXPORTABLE IsCommand(const TCHAR *cmdTemplate, const TCHAR *str, int minChars)
   58 {
   59    TCHAR temp[256];
   60    _tcslcpy(temp, str, 256);
   61    _tcsupr(temp);
   62 
   63    int i;
   64    for(i = 0; temp[i] != 0; i++)
   65       if (temp[i] != cmdTemplate[i])
   66          return false;
   67    return i >= minChars;
   68 }
   69 
   70 /**
   71  * Show memory usage
   72  */
   73 static void ShowMemoryUsage(ServerConsole *console)
   74 {
   75    console->printf(_T("Alarms ...................: %.02f MB\n"), static_cast<double>(GetAlarmMemoryUsage()) / 1048576);
   76    console->printf(_T("Data collection cache ....: %.02f MB\n"), static_cast<double>(GetDCICacheMemoryUsage()) / 1048576);
   77    console->printf(_T("Raw DCI data write cache .: %.02f MB\n"), static_cast<double>(GetRawDataWriterMemoryUsage()) / 1048576);
   78    console->print(_T("\n"));
   79 }
   80 
   81 /**
   82  * Print ARP cache
   83  */
   84 static void PrintArpCache(CONSOLE_CTX ctx, Node *node, ArpCache *arpCache)
   85 {
   86    ConsolePrintf(ctx, _T("\x1b[1mIP address\x1b[0m      | \x1b[1mMAC address\x1b[0m       | \x1b[1mIfIndex\x1b[0m | \x1b[1mInterface\x1b[0m\n"));
   87    ConsolePrintf(ctx, _T("----------------+-------------------+---------+----------------------\n"));
   88 
   89    TCHAR ipAddrStr[64], macAddrStr[64];
   90    for(int i = 0; i < arpCache->size(); i++)
   91    {
   92       const ArpEntry *e = arpCache->get(i);
   93       shared_ptr<Interface> iface = node->findInterfaceByIndex(e->ifIndex);
   94       ConsolePrintf(ctx, _T("%-15s | %s | %7d | %-20s\n"), e->ipAddr.toString(ipAddrStr), e->macAddr.toString(macAddrStr),
   95          e->ifIndex, (iface != nullptr) ? iface->getName() : _T("\x1b[31;1mUNKNOWN\x1b[0m"));
   96    }
   97    ConsolePrintf(ctx, _T("\n%d entries\n\n"), arpCache->size());
   98 }
   99 
  100 /**
  101  * Dump index callback (by IP address)
  102  */
  103 static void DumpIndexCallbackByInetAddr(const InetAddress& addr, NetObj *object, void *context)
  104 {
  105    TCHAR buffer[64];
  106    static_cast<ServerConsole*>(context)->printf(_T("%-40s [%7u] %s [%d]\n"),
  107             addr.toString(buffer), object->getId(), object->getName(), (int)object->getId());
  108 }
  109 
  110 /**
  111  * Dump index (by IP address)
  112  */
  113 void DumpIndex(CONSOLE_CTX pCtx, InetAddressIndex *index)
  114 {
  115    index->forEach(DumpIndexCallbackByInetAddr, pCtx);
  116 }
  117 
  118 /**
  119  * Dump index callback (by GUID)
  120  */
  121 static void DumpIndexCallbackByGUID(const uuid *guid, NetObj *object, void *context)
  122 {
  123    TCHAR buffer[64];
  124    static_cast<ServerConsole*>(context)->printf(_T("%s [%7u] %s\n"), guid->toString(buffer), object->getId(), object->getName());
  125 }
  126 
  127 /**
  128  * Dump index (by ID)
  129  */
  130 static void DumpIndex(ServerConsole *console, HashIndex<uuid> *index)
  131 {
  132    index->forEach(DumpIndexCallbackByGUID, console);
  133 }
  134 
  135 /**
  136  * Dump index callback (by ID)
  137  */
  138 static void DumpIndexCallbackById(NetObj *object, void *context)
  139 {
  140    static_cast<ServerConsole*>(context)->printf(_T("%08X %p %s\n"), object->getId(), object, object->getName());
  141 }
  142 
  143 /**
  144  * Dump index (by ID)
  145  */
  146 static void DumpIndex(ServerConsole *console, ObjectIndex *index)
  147 {
  148    index->forEach(DumpIndexCallbackById, console);
  149 }
  150 
  151 /**
  152  * Compare debug tags for alphabetical sorting
  153  */
  154 static int CompareDebugTags(const DebugTagInfo **t1, const DebugTagInfo **t2)
  155 {
  156    return _tcsicmp((*t1)->tag, (*t2)->tag);
  157 }
  158 
  159 /**
  160  * Callback for address scan
  161  */
  162 static void PrintScanCallback(const InetAddress& addr, int32_t zoneUIN, const Node *proxy, UINT32 rtt, ServerConsole *console, void *context)
  163 {
  164    TCHAR ipAddrText[64];
  165    if (proxy != nullptr)
  166    {
  167       ConsolePrintf(console, _T("   Reply from %s to ICMP ping via proxy %s [%u]\n"),
  168             addr.toString(ipAddrText), proxy->getName(), proxy->getId());
  169    }
  170    else
  171    {
  172       ConsolePrintf(console, _T("   Reply from %s in %dms\n"), addr.toString(ipAddrText), rtt);
  173    }
  174 
  175 }
  176 
  177 /**
  178  * Callback for enumerating discovery queue
  179  */
  180 static EnumerationCallbackResult ShowDiscoveryQueueElement(const DiscoveredAddress *address, CONSOLE_CTX console)
  181 {
  182    static const TCHAR *sourceTypes[] = { _T("arp"), _T("route"), _T("agent reg"), _T("snmp trap"), _T("syslog"), _T("active") };
  183    TCHAR ipAddrText[48], nodeInfo[256];
  184    if (address->sourceNodeId != 0)
  185    {
  186       shared_ptr<NetObj> node = FindObjectById(address->sourceNodeId, OBJECT_NODE);
  187       _sntprintf(nodeInfo, 256, _T("%s [%u]"), (node != nullptr) ? node->getName() : _T("<unknown>"), address->sourceNodeId);
  188    }
  189    else
  190    {
  191       nodeInfo[0] = 0;
  192    }
  193    ConsolePrintf(console, _T("%-40s %-10s %s\n"),
  194             address->ipAddr.toString(ipAddrText), sourceTypes[address->sourceType], nodeInfo);
  195    return _CONTINUE;
  196 }
  197 
  198 /**
  199  * Process command entered from command line in standalone mode
  200  * Return TRUE if command was _T("down")
  201  */
  202 int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
  203 {
  204    TCHAR szBuffer[256], *eptr;
  205    int nExitCode = CMD_EXIT_CONTINUE;
  206 
  207    // Get command
  208    const TCHAR *pArg = ExtractWord(pszCmdLine, szBuffer);
  209 
  210    if (IsCommand(_T("AT"), szBuffer, 2))
  211    {
  212       pArg = ExtractWord(pArg, szBuffer);
  213       if (szBuffer[0] == _T('+'))
  214       {
  215          int offset = _tcstoul(&szBuffer[1], nullptr, 0);
  216          AddOneTimeScheduledTask(_T("Execute.Script"), time(nullptr) + offset, pArg, nullptr, 0, 0, SYSTEM_ACCESS_FULL);//TODO: change to correct user
  217       }
  218       else
  219       {
  220          AddRecurrentScheduledTask(_T("Execute.Script"), szBuffer, pArg, nullptr, 0, 0, SYSTEM_ACCESS_FULL); //TODO: change to correct user
  221       }
  222    }
  223    else if (IsCommand(_T("CLEAR"), szBuffer, 5))
  224    {
  225       pArg = ExtractWord(pArg, szBuffer);
  226       if (IsCommand(_T("DBWRITER"), szBuffer, 8))
  227       {
  228          ExtractWord(pArg, szBuffer);
  229          ClearDBWriterData(pCtx, szBuffer);
  230       }
  231       else if (szBuffer[0] == 0)
  232       {
  233          ConsoleWrite(pCtx,
  234                   _T("Valid components:\n")
  235                   _T("   DBWriter Counters\n")
  236                   _T("   DBWriter DataQueue\n")
  237                   _T("\n"));
  238       }
  239       else
  240       {
  241          ConsoleWrite(pCtx, _T("Invalid component name\n"));
  242       }
  243    }
  244    else if (IsCommand(_T("DBCP"), szBuffer, 3))
  245    {
  246       ExtractWord(pArg, szBuffer);
  247       if (IsCommand(_T("RESET"), szBuffer, 5))
  248       {
  249          ConsoleWrite(pCtx, _T("Resetting database connection pool\n"));
  250          DBConnectionPoolReset();
  251          ConsoleWrite(pCtx, _T("Database connection pool reset completed\n"));
  252       }
  253       else
  254       {
  255          ConsoleWrite(pCtx, _T("Invalid subcommand\n"));
  256       }
  257    }
  258    else if (IsCommand(_T("DEBUG"), szBuffer, 2))
  259    {
  260       StringList *list = ParseCommandLine(pArg);
  261       if (list->size() == 0)
  262       {
  263          ConsolePrintf(pCtx, _T("Current debug levels:\n"));
  264          ConsolePrintf(pCtx, _T("   DEFAULT              = %d\n"), nxlog_get_debug_level());
  265 
  266          ObjectArray<DebugTagInfo> *tags = nxlog_get_all_debug_tags();
  267          tags->sort(CompareDebugTags);
  268          for(int i = 0; i < tags->size(); i++)
  269          {
  270             const DebugTagInfo *t = tags->get(i);
  271             ConsolePrintf(pCtx, _T("   %-20s = %d\n"), t->tag, t->level);
  272          }
  273          delete tags;
  274 
  275          ConsolePrintf(pCtx, _T("   SQL query trace      = %s\n"), DBIsQueryTraceEnabled() ? _T("ON") : _T("OFF"));
  276       }
  277       else if (!_tcsicmp(list->get(0), _T("SQL")))
  278       {
  279          if (list->size() > 1)
  280          {
  281             if (!_tcsicmp(list->get(1), _T("ON")))
  282             {
  283                DBEnableQueryTrace(true);
  284                nxlog_set_debug_level_tag(_T("db.query"), 9);
  285             }
  286             else if (!_tcsicmp(list->get(1), _T("OFF")))
  287             {
  288                DBEnableQueryTrace(false);
  289                nxlog_set_debug_level_tag(_T("db.query"), -1);
  290             }
  291             else
  292             {
  293                ConsoleWrite(pCtx, _T("ERROR: Invalid SQL query trace mode (valid modes are ON and OFF)\n\n"));
  294             }
  295          }
  296          else
  297          {
  298             ConsolePrintf(pCtx, _T("SQL query trace is %s\n"), DBIsQueryTraceEnabled() ? _T("ON") : _T("OFF"));
  299          }
  300       }
  301       else
  302       {
  303          int index = (list->size() == 1) ? 0 : 1;
  304          int level;
  305          if (!_tcsicmp(list->get(index), _T("OFF")))
  306          {
  307             level = 0;
  308          }
  309          else if (IsCommand(_T("DEFAULT"), list->get(index), 3))
  310          {
  311             level = -1;
  312          }
  313          else
  314          {
  315             level = (int)_tcstol(list->get(index), &eptr, 0);
  316             if (*eptr != 0)
  317                level = -99;   // mark as invalid
  318          }
  319          if ((level >= -1) && (level <= 9))
  320          {
  321             if (list->size() == 1)
  322             {
  323                if (level < 0)
  324                   level = 0;
  325                nxlog_set_debug_level(level);
  326                ConsolePrintf(pCtx, (level == 0) ? _T("Debug mode turned off\n") : _T("Debug level set to %d\n"), level);
  327             }
  328             else if (list->size() == 2)
  329             {
  330                nxlog_set_debug_level_tag(list->get(0), level);
  331                if (level == -1)
  332                   ConsolePrintf(pCtx,  _T("Debug level for tag \"%s\" set to default\n"), list->get(0));
  333                else
  334                   ConsolePrintf(pCtx,  _T("Debug level for tag \"%s\" set to %d\n"), list->get(0), level);
  335             }
  336          }
  337          else
  338          {
  339             ConsoleWrite(pCtx, _T("ERROR: Invalid debug level\n\n"));
  340          }
  341       }
  342       delete list;
  343    }
  344    else if (IsCommand(_T("DOWN"), szBuffer, 4))
  345    {
  346       ConsoleWrite(pCtx, _T("Proceeding with server shutdown...\n"));
  347       nExitCode = CMD_EXIT_SHUTDOWN;
  348    }
  349    else if (IsCommand(_T("DUMP"), szBuffer, 4))
  350    {
  351       DumpProcess(pCtx);
  352    }
  353    else if (IsCommand(_T("GET"), szBuffer, 3))
  354    {
  355       ExtractWord(pArg, szBuffer);
  356       if (szBuffer[0] != 0)
  357       {
  358          TCHAR value[MAX_CONFIG_VALUE];
  359          ConfigReadStr(szBuffer, value, MAX_CONFIG_VALUE, _T(""));
  360          ConsolePrintf(pCtx, _T("%s = %s\n"), szBuffer, value);
  361       }
  362       else
  363       {
  364          ConsoleWrite(pCtx, _T("Variable name missing\n"));
  365       }
  366    }
  367    else if (IsCommand(_T("HKRUN"), szBuffer, 2))
  368    {
  369       ConsoleWrite(pCtx, _T("Starting housekeeper\n"));
  370       RunHouseKeeper();
  371    }
  372    else if (IsCommand(_T("LDAPSYNC"), szBuffer, 4))
  373    {
  374       LDAPConnection conn;
  375       conn.syncUsers();
  376    }
  377    else if (IsCommand(_T("LOG"), szBuffer, 3))
  378    {
  379       while(_istspace(*pArg))
  380          pArg++;
  381       if (*pArg != 0)
  382          DbgPrintf(0, _T("%s"), pArg);
  383    }
  384    else if (IsCommand(_T("LOGMARK"), szBuffer, 4))
  385    {
  386       DbgPrintf(0, _T("******* MARK *******"));
  387    }
  388    else if (IsCommand(_T("RAISE"), szBuffer, 5))
  389    {
  390       // Get argument
  391       ExtractWord(pArg, szBuffer);
  392 
  393       if (IsCommand(_T("ACCESS"), szBuffer, 6))
  394       {
  395          ConsoleWrite(pCtx, _T("Raising exception...\n"));
  396          char *p = nullptr;
  397          *p = 0;
  398       }
  399       else if (IsCommand(_T("BREAKPOINT"), szBuffer, 5))
  400       {
  401 #ifdef _WIN32
  402          ConsoleWrite(pCtx, _T("Raising exception...\n"));
  403          RaiseException(EXCEPTION_BREAKPOINT, 0, 0, nullptr);
  404 #else
  405          ConsoleWrite(pCtx, _T("ERROR: Not supported on current platform\n"));
  406 #endif
  407       }
  408       else
  409       {
  410          ConsoleWrite(pCtx, _T("Invalid exception name; possible names are:\nACCESS BREAKPOINT\n"));
  411       }
  412    }
  413    else if (IsCommand(_T("EXIT"), szBuffer, 4))
  414    {
  415       if (pCtx->isRemote())
  416       {
  417          ConsoleWrite(pCtx, _T("Closing session...\n"));
  418          nExitCode = CMD_EXIT_CLOSE_SESSION;
  419       }
  420       else
  421       {
  422          ConsoleWrite(pCtx, _T("Cannot exit from local server console\n"));
  423       }
  424    }
  425    else if (IsCommand(_T("KILL"), szBuffer, 4))
  426    {
  427       ExtractWord(pArg, szBuffer);
  428       if (szBuffer[0] != 0)
  429       {
  430          int id = _tcstol(szBuffer, &eptr, 10);
  431          if (*eptr == 0)
  432          {
  433             if (KillClientSession(id))
  434             {
  435                ConsoleWrite(pCtx, _T("Session killed\n"));
  436             }
  437             else
  438             {
  439                ConsoleWrite(pCtx, _T("Invalid session ID\n"));
  440             }
  441          }
  442          else
  443          {
  444             ConsoleWrite(pCtx, _T("Invalid session ID\n"));
  445          }
  446       }
  447       else
  448       {
  449          ConsoleWrite(pCtx, _T("Session ID missing\n"));
  450       }
  451    }
  452    else if (IsCommand(_T("PING"), szBuffer, 4))
  453    {
  454       ExtractWord(pArg, szBuffer);
  455       if (szBuffer[0] != 0)
  456       {
  457          InetAddress addr = InetAddress::parse(szBuffer);
  458          if (addr.isValid())
  459          {
  460             UINT32 rtt;
  461             UINT32 rc = IcmpPing(addr, 1, 2000, &rtt, 128, false);
  462             switch(rc)
  463             {
  464                case ICMP_SUCCESS:
  465                   ConsolePrintf(pCtx, _T("Success, RTT = %d ms\n"), (int)rtt);
  466                   break;
  467                case ICMP_UNREACHABLE:
  468                   ConsolePrintf(pCtx, _T("Destination unreachable\n"));
  469                   break;
  470                case ICMP_TIMEOUT:
  471                   ConsolePrintf(pCtx, _T("Request timeout\n"));
  472                   break;
  473                case ICMP_RAW_SOCK_FAILED:
  474                   ConsolePrintf(pCtx, _T("Cannot create raw socket\n"));
  475                   break;
  476                case ICMP_API_ERROR:
  477                   ConsolePrintf(pCtx, _T("API error\n"));
  478                   break;
  479                default:
  480                   ConsolePrintf(pCtx, _T("ERROR %d\n"), (int)rc);
  481                   break;
  482             }
  483          }
  484          else
  485          {
  486             ConsoleWrite(pCtx, _T("Invalid IP address\n"));
  487          }
  488       }
  489       else
  490       {
  491          ConsoleWrite(pCtx, _T("Usage: PING <address>\n"));
  492       }
  493    }
  494    else if (IsCommand(_T("POLL"), szBuffer, 2))
  495    {
  496       pArg = ExtractWord(pArg, szBuffer);
  497       if (szBuffer[0] != 0)
  498       {
  499          int pollType;
  500          if (IsCommand(_T("CONFIGURATION"), szBuffer, 1))
  501          {
  502             pollType = 1;
  503          }
  504          else if (IsCommand(_T("DISCOVERY"), szBuffer, 1))
  505          {
  506             pollType = 6;
  507          }
  508          else if (IsCommand(_T("INSTANCE"), szBuffer, 1))
  509          {
  510             pollType = 5;
  511          }
  512          else if (IsCommand(_T("ROUTING-TABLE"), szBuffer, 1))
  513          {
  514             pollType = 4;
  515          }
  516          else if (IsCommand(_T("STATUS"), szBuffer, 1))
  517          {
  518             pollType = 2;
  519          }
  520          else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
  521          {
  522             pollType = 3;
  523          }
  524          else
  525          {
  526             pollType = 0;
  527          }
  528 
  529          if (pollType > 0)
  530          {
  531             ExtractWord(pArg, szBuffer);
  532             UINT32 id = _tcstoul(szBuffer, nullptr, 0);
  533             if (id != 0)
  534             {
  535                shared_ptr<NetObj> object = FindObjectById(id);
  536                if ((object != nullptr) && object->isDataCollectionTarget())
  537                {
  538                   switch(pollType)
  539                   {
  540                      case 1:
  541                         static_cast<DataCollectionTarget*>(object.get())->startForcedConfigurationPoll();
  542                         ThreadPoolExecute(g_pollerThreadPool, static_pointer_cast<DataCollectionTarget>(object),
  543                                  &DataCollectionTarget::configurationPollWorkerEntry,
  544                                  RegisterPoller(PollerType::CONFIGURATION, object));
  545                         break;
  546                      case 2:
  547                         static_cast<DataCollectionTarget*>(object.get())->startForcedStatusPoll();
  548                         ThreadPoolExecute(g_pollerThreadPool, static_pointer_cast<DataCollectionTarget>(object),
  549                                  &DataCollectionTarget::statusPollWorkerEntry,
  550                                  RegisterPoller(PollerType::STATUS, object));
  551                         break;
  552                      case 3:
  553                         if (object->getObjectClass() == OBJECT_NODE)
  554                         {
  555                            static_cast<Node*>(object.get())->startForcedTopologyPoll();
  556                            ThreadPoolExecute(g_pollerThreadPool, static_pointer_cast<Node>(object),
  557                                     &Node::topologyPollWorkerEntry,
  558                                     RegisterPoller(PollerType::TOPOLOGY, object));
  559                         }
  560                         else
  561                         {
  562                            ConsolePrintf(pCtx, _T("ERROR: this poll type can only be initiated for node objects\n\n"));
  563                         }
  564                         break;
  565                      case 4:
  566                         if (object->getObjectClass() == OBJECT_NODE)
  567                         {
  568                            static_cast<Node*>(object.get())->startForcedRoutePoll();
  569                            ThreadPoolExecute(g_pollerThreadPool, static_pointer_cast<Node>(object),
  570                                     &Node::routingTablePollWorkerEntry,
  571                                     RegisterPoller(PollerType::ROUTING_TABLE, object));
  572                         }
  573                         else
  574                         {
  575                            ConsolePrintf(pCtx, _T("ERROR: this poll type can only be initiated for node objects\n\n"));
  576                         }
  577                         break;
  578                      case 5:
  579                         static_cast<DataCollectionTarget*>(object.get())->startForcedInstancePoll();
  580                         ThreadPoolExecute(g_pollerThreadPool, static_pointer_cast<DataCollectionTarget>(object),
  581                                  &DataCollectionTarget::instanceDiscoveryPollWorkerEntry,
  582                                  RegisterPoller(PollerType::INSTANCE_DISCOVERY, object));
  583                         break;
  584                      case 6:
  585                         if (object->getObjectClass() == OBJECT_NODE)
  586                         {
  587                            static_cast<Node*>(object.get())->startForcedDiscoveryPoll();
  588                            ThreadPoolExecute(g_pollerThreadPool, DiscoveryPoller, RegisterPoller(PollerType::DISCOVERY, object));
  589                         }
  590                         else
  591                         {
  592                            ConsolePrintf(pCtx, _T("ERROR: this poll type can only be initiated for node objects\n\n"));
  593                         }
  594                         break;
  595                   }
  596                }
  597                else
  598                {
  599                   ConsolePrintf(pCtx, _T("ERROR: data collection target with ID %d does not exist\n\n"), id);
  600                }
  601             }
  602             else
  603             {
  604                ConsoleWrite(pCtx, _T("ERROR: Invalid or missing object ID\n\n"));
  605             }
  606          }
  607          else
  608          {
  609             ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|DISCOVERY|STATUS|TOPOLOGY|INSTANCE|ROUTING-TABLE] <object>\n"));
  610          }
  611       }
  612       else
  613       {
  614          ConsoleWrite(pCtx, _T("Usage POLL [CONFIGURATION|DISCOVERY|STATUS|TOPOLOGY|INSTANCE|ROUTING-TABLE] <node>\n"));
  615       }
  616    }
  617    else if (IsCommand(_T("SCAN"), szBuffer, 4))
  618    {
  619       pArg = ExtractWord(pArg, szBuffer);
  620       if (szBuffer[0] != 0)
  621       {
  622          TCHAR addr2[256];
  623          pArg = ExtractWord(pArg, addr2);
  624          if (addr2[0] != 0)
  625          {
  626             InetAddress start = InetAddress::parse(szBuffer);
  627             InetAddress end = InetAddress::parse(addr2);
  628             pArg = ExtractWord(pArg, szBuffer);
  629             int32_t zoneUIN = 0;
  630             UINT32 proxyId = 0;
  631             bool doDiscovery = false;
  632             bool syntaxError = false;
  633             if (szBuffer[0] != 0)
  634             {
  635                if (IsCommand(_T("ZONE"), szBuffer, 1))
  636                {
  637                   pArg = ExtractWord(pArg, szBuffer);
  638                   proxyId = _tcstoul(szBuffer, nullptr, 0);
  639                   ExtractWord(pArg, szBuffer); // Extract next word if it is discovery
  640                }
  641                else if (IsCommand(_T("PROXY"), szBuffer, 1))
  642                {
  643                   pArg = ExtractWord(pArg, szBuffer);
  644                   zoneUIN = _tcstol(szBuffer, nullptr, 0);
  645                   ExtractWord(pArg, szBuffer);  // Extract next word if it is discovery
  646                }
  647                else if (IsCommand(_T("DISCOVERY"), szBuffer, 1))
  648                {
  649                   doDiscovery = true;
  650                }
  651                else
  652                {
  653                   syntaxError = true;
  654                }
  655 
  656                if (!doDiscovery && (szBuffer[0] != 0))
  657                {
  658                   if (IsCommand(_T("DISCOVERY"), szBuffer, 4)) // if "discovery" is after proxy/zone
  659                   {
  660                      doDiscovery = true;
  661                   }
  662                   else
  663                   {
  664                      syntaxError = true;
  665                   }
  666                }
  667 
  668             }
  669             if (!syntaxError)
  670             {
  671                if (start.isValid() && end.isValid())
  672                {
  673                   InetAddressListElement range(start, end, proxyId, zoneUIN);
  674                   ConsolePrintf(pCtx, _T("Scanning address range %s - %s\n"), start.toString(szBuffer), end.toString(addr2));
  675                   CheckRange(range, doDiscovery ? RangeScanCallback : PrintScanCallback, pCtx, nullptr);
  676                   ConsolePrintf(pCtx, _T("Address range %s - %s scan completed\n"), start.toString(szBuffer), end.toString(addr2));
  677                }
  678                else
  679                {
  680                   ConsolePrintf(pCtx, _T("Invalid address\n"));
  681                }
  682             }
  683             else
  684             {
  685                ConsolePrintf(pCtx, _T("Invalid parameter\n"));
  686             }
  687          }
  688          else
  689          {
  690             ConsolePrintf(pCtx, _T("End address missing\n"));
  691          }
  692       }
  693       else
  694       {
  695          ConsolePrintf(pCtx, _T("Start address missing\n"));
  696       }
  697    }
  698    else if (IsCommand(_T("SET"), szBuffer, 3))
  699    {
  700       pArg = ExtractWord(pArg, szBuffer);
  701       if (szBuffer[0] != 0)
  702       {
  703          TCHAR value[256];
  704          ExtractWord(pArg, value);
  705          if (ConfigWriteStr(szBuffer, value, TRUE, TRUE, TRUE))
  706          {
  707             ConsolePrintf(pCtx, _T("Configuration variable %s updated\n"), szBuffer);
  708          }
  709          else
  710          {
  711             ConsolePrintf(pCtx, _T("ERROR: cannot update configuration variable %s\n"), szBuffer);
  712          }
  713       }
  714       else
  715       {
  716          ConsolePrintf(pCtx, _T("Variable name missing\n"));
  717       }
  718    }
  719    else if (IsCommand(_T("SHOW"), szBuffer, 2))
  720    {
  721       // Get argument
  722       pArg = ExtractWord(pArg, szBuffer);
  723 
  724       if (IsCommand(_T("ARP"), szBuffer, 2))
  725       {
  726          // Get argument
  727          ExtractWord(pArg, szBuffer);
  728          UINT32 dwNode = _tcstoul(szBuffer, nullptr, 0);
  729          if (dwNode != 0)
  730          {
  731             shared_ptr<NetObj> pObject = FindObjectById(dwNode);
  732             if (pObject != nullptr)
  733             {
  734                if (pObject->getObjectClass() == OBJECT_NODE)
  735                {
  736                   ArpCache *arpCache = static_cast<Node*>(pObject.get())->getArpCache();
  737                   if (arpCache != nullptr)
  738                   {
  739                      PrintArpCache(pCtx, static_cast<Node*>(pObject.get()), arpCache);
  740                      arpCache->decRefCount();
  741                   }
  742                   else
  743                   {
  744                      ConsoleWrite(pCtx, _T("ERROR: Node does not have forwarding database information\n\n"));
  745                   }
  746                }
  747                else
  748                {
  749                   ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
  750                }
  751             }
  752             else
  753             {
  754                ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
  755             }
  756          }
  757          else
  758          {
  759             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
  760          }
  761       }
  762       else if (IsCommand(_T("COMPONENTS"), szBuffer, 1))
  763       {
  764          // Get argument
  765          ExtractWord(pArg, szBuffer);
  766          UINT32 dwNode = _tcstoul(szBuffer, nullptr, 0);
  767          if (dwNode != 0)
  768          {
  769             shared_ptr<NetObj> pObject = FindObjectById(dwNode);
  770             if (pObject != nullptr)
  771             {
  772                if (pObject->getObjectClass() == OBJECT_NODE)
  773                {
  774                   shared_ptr<ComponentTree> components = static_cast<Node*>(pObject.get())->getComponents();
  775                   if (components != nullptr)
  776                   {
  777                      components->print(pCtx);
  778                   }
  779                   else
  780                   {
  781                      ConsoleWrite(pCtx, _T("ERROR: Node does not have physical component information\n\n"));
  782                   }
  783                }
  784                else
  785                {
  786                   ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
  787                }
  788             }
  789             else
  790             {
  791                ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
  792             }
  793          }
  794          else
  795          {
  796             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
  797          }
  798       }
  799       else if (IsCommand(_T("DBCP"), szBuffer, 4))
  800       {
  801          ObjectArray<PoolConnectionInfo> *list = DBConnectionPoolGetConnectionList();
  802          for(int i = 0; i < list->size(); i++)
  803          {
  804             PoolConnectionInfo *c = list->get(i);
  805             TCHAR accessTime[64];
  806             ConsolePrintf(pCtx, _T("%p %s %hs:%d\n"), c->handle, FormatTimestamp(c->lastAccessTime, accessTime), c->srcFile, c->srcLine);
  807          }
  808          ConsolePrintf(pCtx, _T("%d database connections in use\n\n"), list->size());
  809          delete list;
  810       }
  811       else if (IsCommand(_T("DBSTATS"), szBuffer, 3))
  812       {
  813          LIBNXDB_PERF_COUNTERS counters;
  814          DBGetPerfCounters(&counters);
  815          ConsolePrintf(pCtx, _T("SQL query counters:\n"));
  816          ConsolePrintf(pCtx, _T("   Total .......... ") INT64_FMT _T("\n"), counters.totalQueries);
  817          ConsolePrintf(pCtx, _T("   SELECT ......... ") INT64_FMT _T("\n"), counters.selectQueries);
  818          ConsolePrintf(pCtx, _T("   Non-SELECT ..... ") INT64_FMT _T("\n"), counters.nonSelectQueries);
  819          ConsolePrintf(pCtx, _T("   Long running ... ") INT64_FMT _T("\n"), counters.longRunningQueries);
  820          ConsolePrintf(pCtx, _T("   Failed ......... ") INT64_FMT _T("\n"), counters.failedQueries);
  821 
  822          ConsolePrintf(pCtx, _T("Background writer requests:\n"));
  823          ConsolePrintf(pCtx, _T("   DCI data ....... ") INT64_FMT _T("\n"), g_idataWriteRequests);
  824          ConsolePrintf(pCtx, _T("   DCI raw data ... ") INT64_FMT _T("\n"), g_rawDataWriteRequests);
  825          ConsolePrintf(pCtx, _T("   Others ......... ") INT64_FMT _T("\n"), g_otherWriteRequests);
  826       }
  827       else if (IsCommand(_T("DISCOVERY"), szBuffer, 2))
  828       {
  829          ExtractWord(pArg, szBuffer);
  830          if (IsCommand(_T("QUEUE"), szBuffer, 1))
  831          {
  832             g_nodePollerQueue.forEach(ShowDiscoveryQueueElement, pCtx);
  833          }
  834          else
  835          {
  836             ConsoleWrite(pCtx, _T("Invalid subcommand\n"));
  837          }
  838       }
  839       else if (IsCommand(_T("EP"), szBuffer, 2))
  840       {
  841          StructArray<EventProcessingThreadStats> *stats = GetEventProcessingThreadStats();
  842          if (stats->size() > 0)
  843          {
  844             ConsoleWrite(pCtx,
  845                      _T(" \x1b[1mID\x1b[0m  | \x1b[1mQueue\x1b[0m | \x1b[1mBindings\x1b[0m | \x1b[1mWait time\x1b[0m | \x1b[1mProcessed\x1b[0m\n")
  846                      _T("-----+-------+----------+-----------+-----------\n"));
  847             for(int i = 0; i < stats->size(); i++)
  848             {
  849                EventProcessingThreadStats *s = stats->get(i);
  850                ConsolePrintf(pCtx, _T(" %-3d | %-5u | %-8u | %-9u | ") UINT64_FMT _T("\n"),
  851                         i + 1, s->queueSize, s->bindings, s->averageWaitTime, s->processedEvents);
  852             }
  853          }
  854          else
  855          {
  856             ConsoleWrite(pCtx, _T("Parallel event processing is disabled\n"));
  857          }
  858          delete stats;
  859       }
  860       else if (IsCommand(_T("FDB"), szBuffer, 3))
  861       {
  862          // Get argument
  863          ExtractWord(pArg, szBuffer);
  864          UINT32 dwNode = _tcstoul(szBuffer, nullptr, 0);
  865          if (dwNode != 0)
  866          {
  867             shared_ptr<NetObj> pObject = FindObjectById(dwNode);
  868             if (pObject != nullptr)
  869             {
  870                if (pObject->getObjectClass() == OBJECT_NODE)
  871                {
  872                   ForwardingDatabase *fdb = static_cast<Node*>(pObject.get())->getSwitchForwardingDatabase();
  873                   if (fdb != nullptr)
  874                   {
  875                      fdb->print(pCtx, static_cast<Node*>(pObject.get()));
  876                      fdb->decRefCount();
  877                   }
  878                   else
  879                   {
  880                      ConsoleWrite(pCtx, _T("ERROR: Node does not have forwarding database information\n\n"));
  881                   }
  882                }
  883                else
  884                {
  885                   ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
  886                }
  887             }
  888             else
  889             {
  890                ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
  891             }
  892          }
  893          else
  894          {
  895             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
  896          }
  897       }
  898       else if (IsCommand(_T("FLAGS"), szBuffer, 1))
  899       {
  900          ConsolePrintf(pCtx, _T("Flags: 0x") UINT64X_FMT(_T("016")) _T("\n"), g_flags);
  901          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DAEMON));
  902          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSLOG));
  903          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_PASSIVE_NETWORK_DISCOVERY));
  904          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ACTIVE_NETWORK_DISCOVERY));
  905          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_8021X_STATUS_POLL));
  906          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DELETE_EMPTY_SUBNETS));
  907          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_SNMP_TRAPD));
  908          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_ZONING));
  909          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYNC_NODE_NAMES_WITH_DNS));
  910          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CHECK_TRUSTED_NODES));
  911          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NXSL_CONTAINER_FUNCTIONS));
  912          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_FQDN_FOR_NODE_NAMES));
  913          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE));
  914          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DEBUG_CONSOLE_DISABLED));
  915          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_OBJECT_TRANSACTIONS));
  916          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_WRITE_FULL_DUMP));
  917          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_NODE_NAMES));
  918          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CATCH_EXCEPTIONS));
  919          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_HELPDESK_LINK_ACTIVE));
  920          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_LOCKED));
  921          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_CONNECTION_LOST));
  922          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_NO_NETWORK_CONNECTIVITY));
  923          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_EVENT_STORM_DETECTED));
  924          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SNMP_TRAP_DISCOVERY));
  925          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAPS_FROM_UNMANAGED_NODES));
  926          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_RESOLVE_IP_FOR_EACH_STATUS_POLL));
  927          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_PERFDATA_STORAGE_DRIVER_LOADED));
  928          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_BACKGROUND_LOG_WRITER));
  929          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CASE_INSENSITIVE_LOGINS));
  930          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_TRAP_SOURCES_IN_ALL_ZONES));
  931          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYSLOG_DISCOVERY));
  932          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_LOCAL_CONSOLE));
  933          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_CACHE_DB_ON_STARTUP));
  934          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_NXSL_FILE_IO_FUNCTIONS));
  935          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ENABLE_EMBEDDED_PYTHON));
  936          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DB_SUPPORTS_MERGE));
  937          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_PARALLEL_NETWORK_DISCOVERY));
  938          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SINGLE_TABLE_PERF_DATA));
  939          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_MERGE_DUPLICATE_NODES));
  940          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SYSTEMD_DAEMON));
  941          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_USE_SYSTEMD_JOURNAL));
  942          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_COLLECT_ICMP_STATISTICS));
  943          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_IN_JSON_FORMAT));
  944          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_TO_STDOUT));
  945          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_DBWRITER_HK_INTERLOCK));
  946          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_LOG_ALL_SNMP_TRAPS));
  947          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_ALLOW_TRAP_VARBIND_CONVERSION));
  948          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SERVER_INITIALIZED));
  949          ConsolePrintf(pCtx, SHOW_FLAG_VALUE(AF_SHUTDOWN));
  950          ConsolePrintf(pCtx, _T("\n"));
  951       }
  952       else if (IsCommand(_T("HEAP"), szBuffer, 1))
  953       {
  954          ExtractWord(pArg, szBuffer);
  955          if (IsCommand(_T("DETAILS"), szBuffer, 1))
  956          {
  957             TCHAR *text = GetHeapInfo();
  958             if (text != nullptr)
  959             {
  960                ConsoleWrite(pCtx, text);
  961                ConsoleWrite(pCtx, _T("\n"));
  962                free(text);
  963             }
  964             else
  965             {
  966                ConsoleWrite(pCtx, _T("Error reading heap information\n"));
  967             }
  968          }
  969          else if (IsCommand(_T("SUMMARY"), szBuffer, 1))
  970          {
  971             INT64 allocated = GetAllocatedHeapMemory();
  972             INT64 active = GetActiveHeapMemory();
  973             INT64 mapped = GetMappedHeapMemory();
  974             if ((allocated != -1) && (active != -1) && (mapped != -1))
  975             {
  976                ConsolePrintf(pCtx, _T("Allocated ... : %0.1f MB\n"), (double)allocated / 1024.0 / 1024.0);
  977                ConsolePrintf(pCtx, _T("Active ...... : %0.1f MB\n"), (double)active / 1024.0 / 1024.0);
  978                ConsolePrintf(pCtx, _T("Mapped ...... : %0.1f MB\n"), (double)mapped / 1024.0 / 1024.0);
  979             }
  980             else
  981             {
  982                ConsoleWrite(pCtx, _T("Heap summary information unavailable\n"));
  983             }
  984          }
  985          else
  986          {
  987             ConsoleWrite(pCtx, _T("Invalid subcommand\n"));
  988          }
  989       }
  990       else if (IsCommand(_T("INDEX"), szBuffer, 1))
  991       {
  992          // Get argument
  993          pArg = ExtractWord(pArg, szBuffer);
  994 
  995          if (IsCommand(_T("CONDITION"), szBuffer, 1))
  996          {
  997             DumpIndex(pCtx, &g_idxConditionById);
  998          }
  999          else if (IsCommand(_T("GUID"), szBuffer, 1))
 1000          {
 1001             DumpIndex(pCtx, &g_idxObjectByGUID);
 1002          }
 1003          else if (IsCommand(_T("ID"), szBuffer, 2))
 1004          {
 1005             DumpIndex(pCtx, &g_idxObjectById);
 1006          }
 1007          else if (IsCommand(_T("INTERFACE"), szBuffer, 2))
 1008          {
 1009             pArg = ExtractWord(pArg, szBuffer);
 1010             if (IsCommand(_T("ZONE"), szBuffer, 1))
 1011             {
 1012                ExtractWord(pArg, szBuffer);
 1013                shared_ptr<Zone> zone = FindZoneByUIN(_tcstoul(szBuffer, nullptr, 0));
 1014                if (zone != nullptr)
 1015                {
 1016                   zone->dumpInterfaceIndex(pCtx);
 1017                }
 1018                else
 1019                {
 1020                   ConsoleWrite(pCtx, _T("ERROR: Invalid zone UIN\n\n"));
 1021                }
 1022             }
 1023             else if (szBuffer[0] == 0)
 1024             {
 1025                DumpIndex(pCtx, &g_idxInterfaceByAddr);
 1026             }
 1027             else
 1028             {
 1029                ConsoleWrite(pCtx, _T("ERROR: Invalid index modifier\n\n"));
 1030             }
 1031          }
 1032          else if (IsCommand(_T("NETMAP"), szBuffer, 4))
 1033          {
 1034             DumpIndex(pCtx, &g_idxNetMapById);
 1035          }
 1036          else if (IsCommand(_T("NODEADDR"), szBuffer, 5))
 1037          {
 1038             pArg = ExtractWord(pArg, szBuffer);
 1039             if (IsCommand(_T("ZONE"), szBuffer, 1))
 1040             {
 1041                ExtractWord(pArg, szBuffer);
 1042                shared_ptr<Zone> zone = FindZoneByUIN(_tcstoul(szBuffer, nullptr, 0));
 1043                if (zone != nullptr)
 1044                {
 1045                   zone->dumpNodeIndex(pCtx);
 1046                }
 1047                else
 1048                {
 1049                   ConsoleWrite(pCtx, _T("ERROR: Invalid zone UIN\n\n"));
 1050                }
 1051             }
 1052             else if (szBuffer[0] == 0)
 1053             {
 1054                DumpIndex(pCtx, &g_idxNodeByAddr);
 1055             }
 1056             else
 1057             {
 1058                ConsoleWrite(pCtx, _T("ERROR: Invalid index modifier\n\n"));
 1059             }
 1060          }
 1061          else if (IsCommand(_T("NODEID"), szBuffer, 5))
 1062          {
 1063             DumpIndex(pCtx, &g_idxNodeById);
 1064          }
 1065          else if (IsCommand(_T("SENSOR"), szBuffer, 2))
 1066          {
 1067             DumpIndex(pCtx, &g_idxSensorById);
 1068          }
 1069          else if (IsCommand(_T("SUBNET"), szBuffer, 2))
 1070          {
 1071             pArg = ExtractWord(pArg, szBuffer);
 1072             if (IsCommand(_T("ZONE"), szBuffer, 1))
 1073             {
 1074                ExtractWord(pArg, szBuffer);
 1075                shared_ptr<Zone> zone = FindZoneByUIN(_tcstoul(szBuffer, nullptr, 0));
 1076                if (zone != nullptr)
 1077                {
 1078                   zone->dumpSubnetIndex(pCtx);
 1079                }
 1080                else
 1081                {
 1082                   ConsoleWrite(pCtx, _T("ERROR: Invalid zone UIN\n\n"));
 1083                }
 1084             }
 1085             else if (szBuffer[0] == 0)
 1086             {
 1087                DumpIndex(pCtx, &g_idxSubnetByAddr);
 1088             }
 1089             else
 1090             {
 1091                ConsoleWrite(pCtx, _T("ERROR: Invalid index modifier\n\n"));
 1092             }
 1093          }
 1094          else if (IsCommand(_T("ZONE"), szBuffer, 1))
 1095          {
 1096             DumpIndex(pCtx, &g_idxZoneByUIN);
 1097          }
 1098          else
 1099          {
 1100             if (szBuffer[0] == 0)
 1101                ConsoleWrite(pCtx, _T("ERROR: Missing parameters\n")
 1102                                   _T("Syntax:\n   SHOW INDEX name [ZONE uin]\n")
 1103                                   _T("Valid names are: CONDITION, ID, INTERFACE, NODEADDR, NODEID, SUBNET, ZONE\n\n"));
 1104             else
 1105                ConsoleWrite(pCtx, _T("ERROR: Invalid index name\n\n"));
 1106          }
 1107       }
 1108       else if (IsCommand(_T("LLDP"), szBuffer, 4))
 1109       {
 1110          // Get argument
 1111          ExtractWord(pArg, szBuffer);
 1112          UINT32 dwNode = _tcstoul(szBuffer, nullptr, 0);
 1113          if (dwNode != 0)
 1114          {
 1115             shared_ptr<NetObj> pObject = FindObjectById(dwNode);
 1116             if (pObject != nullptr)
 1117             {
 1118                if (pObject->getObjectClass() == OBJECT_NODE)
 1119                {
 1120                   ((Node *)pObject.get())->showLLDPInfo(pCtx);
 1121                }
 1122                else
 1123                {
 1124                   ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
 1125                }
 1126             }
 1127             else
 1128             {
 1129                ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
 1130             }
 1131          }
 1132          else
 1133          {
 1134             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
 1135          }
 1136       }
 1137       else if (IsCommand(_T("MEMUSAGE"), szBuffer, 3))
 1138       {
 1139          ShowMemoryUsage(pCtx);
 1140       }
 1141       else if (IsCommand(_T("MODULES"), szBuffer, 3))
 1142       {
 1143          ConsoleWrite(pCtx, _T("Loaded server modules:\n"));
 1144          ENUMERATE_MODULES(szName)
 1145          {
 1146             NXMODULE_METADATA *m = CURRENT_MODULE.metadata;
 1147             if (m != nullptr)
 1148                ConsolePrintf(pCtx, _T("   %-24s %-12hs %hs\n"), CURRENT_MODULE.szName, m->moduleVersion, m->vendor);
 1149             else
 1150                ConsolePrintf(pCtx, _T("   %-24s (module metadata unavailable)\n"), CURRENT_MODULE.szName);
 1151          }
 1152          ConsolePrintf(pCtx, _T("%d modules loaded\n"), g_moduleList.size());
 1153       }
 1154       else if (IsCommand(_T("MSGWQ"), szBuffer, 2))
 1155       {
 1156          String text = MsgWaitQueue::getDiagInfo();
 1157          ConsoleWrite(pCtx, text);
 1158          ConsoleWrite(pCtx, _T("\n"));
 1159       }
 1160       else if (IsCommand(_T("NDD"), szBuffer, 3))
 1161       {
 1162          PrintNetworkDeviceDriverList(pCtx);
 1163       }
 1164       else if (IsCommand(_T("OBJECTS"), szBuffer, 1))
 1165       {
 1166          // Get filter
 1167          ExtractWord(pArg, szBuffer);
 1168          StrStrip(szBuffer);
 1169          DumpObjects(pCtx, (szBuffer[0] != 0) ? szBuffer : nullptr);
 1170       }
 1171       else if (IsCommand(_T("PE"), szBuffer, 2))
 1172       {
 1173          ShowPredictionEngines(pCtx);
 1174       }
 1175       else if (IsCommand(_T("POLLERS"), szBuffer, 2))
 1176       {
 1177          ShowPollers(pCtx);
 1178       }
 1179       else if (IsCommand(_T("QUEUES"), szBuffer, 1))
 1180       {
 1181          ShowThreadPoolPendingQueue(pCtx, g_dataCollectorThreadPool, _T("Data collector"));
 1182          ShowQueueStats(pCtx, &g_dciCacheLoaderQueue, _T("DCI cache loader"));
 1183          ShowQueueStats(pCtx, &g_templateUpdateQueue, _T("Template updater"));
 1184          ShowQueueStats(pCtx, &g_dbWriterQueue, _T("Database writer"));
 1185          ShowQueueStats(pCtx, GetIDataWriterQueueSize(), _T("Database writer (IData)"));
 1186          ShowQueueStats(pCtx, GetRawDataWriterQueueSize(), _T("Database writer (raw DCI values)"));
 1187          ShowQueueStats(pCtx, GetEventProcessorQueueSize(), _T("Event processor"));
 1188          ShowQueueStats(pCtx, GetEventLogWriterQueueSize(), _T("Event log writer"));
 1189          ShowThreadPoolPendingQueue(pCtx, g_pollerThreadPool, _T("Poller"));
 1190          ShowQueueStats(pCtx, GetDiscoveryPollerQueueSize(), _T("Node discovery poller"));
 1191          ShowQueueStats(pCtx, &g_syslogProcessingQueue, _T("Syslog processor"));
 1192          ShowQueueStats(pCtx, &g_syslogWriteQueue, _T("Syslog writer"));
 1193          ShowThreadPoolPendingQueue(pCtx, g_schedulerThreadPool, _T("Scheduler"));
 1194          ShowQueueStats(pCtx, &g_windowsEventProcessingQueue, _T("Windows event processor"));
 1195          ShowQueueStats(pCtx, &g_windowsEventWriterQueue, _T("Windows event writer"));
 1196          ConsolePrintf(pCtx, _T("\n"));
 1197       }
 1198       else if (IsCommand(_T("ROUTING-TABLE"), szBuffer, 1))
 1199       {
 1200          ExtractWord(pArg, szBuffer);
 1201          uint32_t dwNode = _tcstoul(szBuffer, nullptr, 0);
 1202          if (dwNode != 0)
 1203          {
 1204             shared_ptr<NetObj> pObject = FindObjectById(dwNode);
 1205             if (pObject != nullptr)
 1206             {
 1207                if (pObject->getObjectClass() == OBJECT_NODE)
 1208                {
 1209                   ConsolePrintf(pCtx, _T("Routing table for node %s:\n\n"), pObject->getName());
 1210                   auto routingTable = static_cast<Node&>(*pObject).getCachedRoutingTable();
 1211                   if (routingTable != nullptr)
 1212                   {
 1213                      for(int i = 0; i < routingTable->size(); i++)
 1214                      {
 1215                         ROUTE *r = routingTable->get(i);
 1216                         TCHAR szIpAddr[16];
 1217                         _sntprintf(szBuffer, 256, _T("%s/%d"), IpToStr(r->dwDestAddr, szIpAddr), BitsInMask(r->dwDestMask));
 1218                         ConsolePrintf(pCtx, _T("%-18s %-15s %-6d %d\n"), szBuffer, IpToStr(r->dwNextHop, szIpAddr), r->dwIfIndex, r->dwRouteType);
 1219                      }
 1220                      ConsoleWrite(pCtx, _T("\n"));
 1221                   }
 1222                   else
 1223                   {
 1224                      ConsoleWrite(pCtx, _T("Node doesn't have cached routing table\n\n"));
 1225                   }
 1226                }
 1227                else
 1228                {
 1229                   ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
 1230                }
 1231             }
 1232             else
 1233             {
 1234                ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), dwNode);
 1235             }
 1236          }
 1237          else
 1238          {
 1239             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
 1240          }
 1241       }
 1242       else if (IsCommand(_T("SESSIONS"), szBuffer, 2))
 1243       {
 1244          ConsoleWrite(pCtx, _T("\x1b[1mCLIENT SESSIONS\x1b[0m\n============================================================\n"));
 1245          DumpClientSessions(pCtx);
 1246          ConsoleWrite(pCtx, _T("\n\x1b[1mMOBILE DEVICE SESSIONS\x1b[0m\n============================================================\n"));
 1247          DumpMobileDeviceSessions(pCtx);
 1248       }
 1249       else if (IsCommand(_T("SIZEOF"), szBuffer, 4))
 1250       {
 1251          pCtx->printf(_T("NetObj .............: %d\n"), static_cast<int>(sizeof(NetObj)));
 1252          pCtx->printf(_T("   AccessPoint .....: %d\n"), static_cast<int>(sizeof(AccessPoint)));
 1253          pCtx->printf(_T("   Cluster .........: %d\n"), static_cast<int>(sizeof(Cluster)));
 1254          pCtx->printf(_T("   Container .......: %d\n"), static_cast<int>(sizeof(Container)));
 1255          pCtx->printf(_T("   Interface .......: %d\n"), static_cast<int>(sizeof(Interface)));
 1256          pCtx->printf(_T("   Node ............: %d\n"), static_cast<int>(sizeof(Node)));
 1257          pCtx->printf(_T("   Sensor ..........: %d\n"), static_cast<int>(sizeof(Sensor)));
 1258          pCtx->printf(_T("   Template ........: %d\n"), static_cast<int>(sizeof(Template)));
 1259          pCtx->printf(_T("ComponentTree ......: %d\n"), static_cast<int>(sizeof(ComponentTree)));
 1260          pCtx->printf(_T("Component ..........: %d\n"), static_cast<int>(sizeof(Component)));
 1261          pCtx->printf(_T("HardwareComponent ..: %d\n"), static_cast<int>(sizeof(HardwareComponent)));
 1262          pCtx->printf(_T("SoftwarePackage ....: %d\n"), static_cast<int>(sizeof(SoftwarePackage)));
 1263          pCtx->printf(_T("WinPerfObject ......: %d\n"), static_cast<int>(sizeof(WinPerfObject)));
 1264          pCtx->printf(_T("WirelessStationInfo : %d\n"), static_cast<int>(sizeof(WirelessStationInfo)));
 1265          pCtx->printf(_T("Alarm ..............: %d\n"), static_cast<int>(sizeof(Alarm)));
 1266          pCtx->printf(_T("DCItem .............: %d\n"), static_cast<int>(sizeof(DCItem)));
 1267          pCtx->printf(_T("DCTable ............: %d\n"), static_cast<int>(sizeof(DCTable)));
 1268          pCtx->printf(_T("ItemValue ..........: %d\n"), static_cast<int>(sizeof(ItemValue)));
 1269          pCtx->printf(_T("Threshold ..........: %d\n"), static_cast<int>(sizeof(Threshold)));
 1270       }
 1271       else if (IsCommand(_T("STATS"), szBuffer, 2))
 1272       {
 1273          ShowServerStats(pCtx);
 1274       }
 1275       else if (IsCommand(_T("SYNCER"), szBuffer, 2))
 1276       {
 1277          ShowSyncerStats(pCtx);
 1278       }
 1279       else if (IsCommand(_T("THREADS"), szBuffer, 2))
 1280       {
 1281          StringList *pools = ThreadPoolGetAllPools();
 1282          for(int i = 0; i < pools->size(); i++)
 1283             ShowThreadPool(pCtx, pools->get(i));
 1284          delete pools;
 1285       }
 1286       else if (IsCommand(_T("TOPOLOGY"), szBuffer, 1))
 1287       {
 1288          ExtractWord(pArg, szBuffer);
 1289          UINT32 nodeId = _tcstoul(szBuffer, nullptr, 0);
 1290          if (nodeId != 0)
 1291          {
 1292             shared_ptr<Node> node = static_pointer_cast<Node>(FindObjectById(nodeId, OBJECT_NODE));
 1293             if (node != nullptr)
 1294             {
 1295                LinkLayerNeighbors *nbs = BuildLinkLayerNeighborList(node.get());
 1296                if (nbs != nullptr)
 1297                {
 1298                   ConsolePrintf(pCtx, _T("Proto   | PtP | ifLocal | ifRemote | Peer\n")
 1299                                       _T("--------+-----+---------+----------+------------------------------------\n"));
 1300                   for(int i = 0; i < nbs->size(); i++)
 1301                   {
 1302                      LL_NEIGHBOR_INFO *ni = nbs->getConnection(i);
 1303                      TCHAR peer[256];
 1304                      if (ni->objectId != 0)
 1305                      {
 1306                         shared_ptr<NetObj> object = FindObjectById(ni->objectId);
 1307                         if (object != nullptr)
 1308                            _sntprintf(peer, 256, _T("%s [%d]"), object->getName(), ni->objectId);
 1309                         else
 1310                            _sntprintf(peer, 256, _T("[%d]"), ni->objectId);
 1311                      }
 1312                      else
 1313                      {
 1314                         peer[0] = 0;
 1315                      }
 1316                      ConsolePrintf(pCtx, _T("%-7s | %c   | %7d | %7d | %s\n"),
 1317                         GetLinkLayerProtocolName(ni->protocol), ni->isPtToPt ? _T('Y') : _T('N'), ni->ifLocal, ni->ifRemote, peer);
 1318                   }
 1319                   nbs->decRefCount();
 1320                }
 1321                else
 1322                {
 1323                   ConsoleWrite(pCtx, _T("ERROR: call to BuildLinkLayerNeighborList failed\n\n"));
 1324                }
 1325             }
 1326             else
 1327             {
 1328                ConsolePrintf(pCtx, _T("ERROR: Node with ID %d does not exist\n\n"), nodeId);
 1329             }
 1330          }
 1331          else
 1332          {
 1333             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node ID\n\n"));
 1334          }
 1335       }
 1336       else if (IsCommand(_T("TUNNELS"), szBuffer, 2))
 1337       {
 1338          ShowAgentTunnels(pCtx);
 1339       }
 1340       else if (IsCommand(_T("USERS"), szBuffer, 1))
 1341       {
 1342          DumpUsers(pCtx);
 1343       }
 1344       else if (IsCommand(_T("VLANS"), szBuffer, 1))
 1345       {
 1346          ExtractWord(pArg, szBuffer);
 1347          uint32_t nodeId = _tcstoul(szBuffer, nullptr, 0);
 1348          if (nodeId != 0)
 1349          {
 1350             shared_ptr<NetObj> object = FindObjectById(nodeId);
 1351             if (object != nullptr)
 1352             {
 1353                if (object->getObjectClass() == OBJECT_NODE)
 1354                {
 1355                   shared_ptr<VlanList> vlans = static_cast<Node*>(object.get())->getVlans();
 1356                   if (vlans != nullptr)
 1357                   {
 1358                      ConsoleWrite(pCtx, _T("\x1b[1mVLAN\x1b[0m | \x1b[1mName\x1b[0m             | \x1b[1mPorts\x1b[0m\n")
 1359                                         _T("-----+------------------+-----------------------------------------------------------------\n"));
 1360                      for(int i = 0; i < vlans->size(); i++)
 1361                      {
 1362                         VlanInfo *vlan = vlans->get(i);
 1363                         ConsolePrintf(pCtx, _T("%4d | %-16s |"), vlan->getVlanId(), vlan->getName());
 1364                         for(int j = 0; j < vlan->getNumPorts(); j++)
 1365                         {
 1366                            TCHAR buffer[128];
 1367                            ConsolePrintf(pCtx, _T(" %s"), vlan->getPorts()[j].location.toString(buffer, 128));
 1368                         }
 1369                         ConsolePrintf(pCtx, _T("\n"));
 1370                      }
 1371                      ConsolePrintf(pCtx, _T("\n"));
 1372                   }
 1373                   else
 1374                   {
 1375                      ConsoleWrite(pCtx, _T("\x1b[31mNode doesn't have VLAN information\x1b[0m\n\n"));
 1376                   }
 1377                }
 1378                else
 1379                {
 1380                   ConsoleWrite(pCtx, _T("\x1b[31mERROR: Object is not a node\x1b[0m\n\n"));
 1381                }
 1382             }
 1383             else
 1384             {
 1385                ConsolePrintf(pCtx, _T("\x1b[31mERROR: Object with ID %d does not exist\x1b[0m\n\n"), nodeId);
 1386             }
 1387          }
 1388          else
 1389          {
 1390             ConsoleWrite(pCtx, _T("\x1b[31mERROR: Invalid or missing node ID\x1b[0m\n\n"));
 1391          }
 1392       }
 1393       else if (IsCommand(_T("WATCHDOG"), szBuffer, 1))
 1394       {
 1395          WatchdogPrintStatus(pCtx);
 1396          ConsoleWrite(pCtx, _T("\n"));
 1397       }
 1398       else
 1399       {
 1400          if (szBuffer[0] == 0)
 1401             ConsoleWrite(pCtx, _T("ERROR: Missing subcommand\n\n"));
 1402          else
 1403             ConsoleWrite(pCtx, _T("ERROR: Invalid SHOW subcommand\n\n"));
 1404       }
 1405    }
 1406    else if (IsCommand(_T("SNAPSHOT"), szBuffer, 4))
 1407    {
 1408       // create access snapshot
 1409       ExtractWord(pArg, szBuffer);
 1410       UINT32 userId = _tcstoul(szBuffer, nullptr, 0);
 1411       bool success = CreateObjectAccessSnapshot(userId, OBJECT_NODE);
 1412       ConsolePrintf(pCtx, _T("Object access snapshot creation for user %d %s\n\n"), userId, success ? _T("successful") : _T("failed"));
 1413    }
 1414    else if (IsCommand(_T("EXEC"), szBuffer, 3))
 1415    {
 1416       pArg = ExtractWord(pArg, szBuffer);
 1417 
 1418       bool libraryLocked = true;
 1419       bool destroyCompiledScript = false;
 1420       NXSL_Library *scriptLibrary = GetServerScriptLibrary();
 1421       scriptLibrary->lock();
 1422 
 1423       NXSL_Program *compiledScript = scriptLibrary->findNxslProgram(szBuffer);
 1424       if (compiledScript == nullptr)
 1425       {
 1426          scriptLibrary->unlock();
 1427          libraryLocked = false;
 1428          destroyCompiledScript = true;
 1429          char *script;
 1430          if ((script = LoadFileAsUTF8String(szBuffer)) != nullptr)
 1431          {
 1432             const int errorMsgLen = 512;
 1433             TCHAR errorMsg[errorMsgLen];
 1434 #ifdef UNICODE
 1435             WCHAR *wscript = WideStringFromUTF8String(script);
 1436             compiledScript = NXSLCompile(wscript, errorMsg, errorMsgLen, nullptr);
 1437             MemFree(wscript);
 1438 #else
 1439             compiledScript = NXSLCompile(script, errorMsg, errorMsgLen, nullptr);
 1440 #endif
 1441             MemFree(script);
 1442             if (compiledScript == nullptr)
 1443             {
 1444                ConsolePrintf(pCtx, _T("ERROR: Script compilation error: %s\n\n"), errorMsg);
 1445             }
 1446          }
 1447          else
 1448          {
 1449             ConsolePrintf(pCtx, _T("ERROR: Script \"%s\" not found\n\n"), szBuffer);
 1450          }
 1451       }
 1452 
 1453       if (compiledScript != nullptr)
 1454       {
 1455          NXSL_ServerEnv *pEnv = new NXSL_ServerEnv;
 1456          pEnv->setConsole(pCtx);
 1457 
 1458          NXSL_VM *vm = new NXSL_VM(pEnv);
 1459          if (vm->load(compiledScript))
 1460          {
 1461             if (libraryLocked)
 1462             {
 1463                scriptLibrary->unlock();
 1464                libraryLocked = false;
 1465             }
 1466 
 1467             NXSL_Value *argv[32];
 1468             int argc = 0;
 1469             while(argc < 32)
 1470             {
 1471                pArg = ExtractWord(pArg, szBuffer);
 1472                if (szBuffer[0] == 0)
 1473                   break;
 1474                argv[argc++] = vm->createValue(szBuffer);
 1475             }
 1476 
 1477             if (vm->run(argc, argv))
 1478             {
 1479                ConsolePrintf(pCtx, _T("INFO: Script finished with return value %s\n\n"), vm->getResult()->getValueAsCString());
 1480             }
 1481             else
 1482             {
 1483                ConsolePrintf(pCtx, _T("ERROR: Script finished with error: %s\n\n"), vm->getErrorText());
 1484             }
 1485          }
 1486          else
 1487          {
 1488             ConsolePrintf(pCtx, _T("ERROR: VM creation failed: %s\n\n"), vm->getErrorText());
 1489          }
 1490          delete vm;
 1491          if (destroyCompiledScript)
 1492             delete compiledScript;
 1493       }
 1494       if (libraryLocked)
 1495          scriptLibrary->unlock();
 1496    }
 1497    else if (IsCommand(_T("TCPPING"), szBuffer, 4))
 1498    {
 1499       pArg = ExtractWord(pArg, szBuffer);
 1500       if (szBuffer[0] != 0)
 1501       {
 1502          InetAddress addr = InetAddress::parse(szBuffer);
 1503          if (addr.isValid())
 1504          {
 1505             ExtractWord(pArg, szBuffer);
 1506             if (szBuffer[0] != 0)
 1507             {
 1508                UINT16 port = static_cast<UINT16>(_tcstoul(szBuffer, nullptr, 0));
 1509                UINT32 rc = TcpPing(addr, port, 1000);
 1510                switch(rc)
 1511                {
 1512                   case TCP_PING_SUCCESS:
 1513                      ConsolePrintf(pCtx, _T("Success\n"));
 1514                      break;
 1515                   case TCP_PING_REJECT:
 1516                      ConsolePrintf(pCtx, _T("Connection rejected\n"));
 1517                      break;
 1518                   case TCP_PING_SOCKET_ERROR:
 1519                      ConsolePrintf(pCtx, _T("Socket error\n"));
 1520                      break;
 1521                   case TCP_PING_TIMEOUT:
 1522                      ConsolePrintf(pCtx, _T("Timeout\n"));
 1523                      break;
 1524                }
 1525             }
 1526             else
 1527             {
 1528                ConsoleWrite(pCtx, _T("Usage: TCPPING <address> <port>\n"));
 1529             }
 1530          }
 1531          else
 1532          {
 1533             ConsoleWrite(pCtx, _T("Invalid IP address\n"));
 1534          }
 1535       }
 1536       else
 1537       {
 1538          ConsoleWrite(pCtx, _T("Usage: TCPPING <address> <port>\n"));
 1539       }
 1540    }
 1541    else if (IsCommand(_T("TRACE"), szBuffer, 1))
 1542    {
 1543       // Get arguments
 1544       pArg = ExtractWord(pArg, szBuffer);
 1545       uint32_t sourceNodeId = _tcstoul(szBuffer, nullptr, 0);
 1546 
 1547       ExtractWord(pArg, szBuffer);
 1548       uint32_t destNodeId = _tcstoul(szBuffer, nullptr, 0);
 1549 
 1550       if ((sourceNodeId != 0) && (destNodeId != 0))
 1551       {
 1552          shared_ptr<NetObj> sourceNode = FindObjectById(sourceNodeId);
 1553          if (sourceNode == nullptr)
 1554          {
 1555             ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), sourceNodeId);
 1556          }
 1557          else
 1558          {
 1559             shared_ptr<NetObj> destNode = FindObjectById(destNodeId);
 1560             if (destNode == nullptr)
 1561             {
 1562                ConsolePrintf(pCtx, _T("ERROR: Object with ID %d does not exist\n\n"), destNodeId);
 1563             }
 1564             else
 1565             {
 1566                if ((sourceNode->getObjectClass() == OBJECT_NODE) && (destNode->getObjectClass() == OBJECT_NODE))
 1567                {
 1568                   shared_ptr<NetworkPath> trace = TraceRoute(static_pointer_cast<Node>(sourceNode), static_pointer_cast<Node>(destNode));
 1569                   if (trace != nullptr)
 1570                   {
 1571                      TCHAR sourceIp[32];
 1572                      ConsolePrintf(pCtx, _T("Trace from %s to %s (%d hops, %s, source IP %s):\n"),
 1573                            sourceNode->getName(), destNode->getName(), trace->getHopCount(),
 1574                            trace->isComplete() ? _T("complete") : _T("incomplete"),
 1575                            trace->getSourceAddress().toString(sourceIp));
 1576                      trace->print(pCtx, 3);
 1577                      ConsolePrintf(pCtx, _T("\n"));
 1578                   }
 1579                   else
 1580                   {
 1581                      ConsoleWrite(pCtx, _T("ERROR: Call to TraceRoute() failed\n\n"));
 1582                   }
 1583                }
 1584                else
 1585                {
 1586                   ConsoleWrite(pCtx, _T("ERROR: Object is not a node\n\n"));
 1587                }
 1588             }
 1589          }
 1590       }
 1591       else
 1592       {
 1593          ConsoleWrite(pCtx, _T("ERROR: Invalid or missing node id(s)\n\n"));
 1594       }
 1595    }
 1596    else if (IsCommand(_T("TUNNEL"), szBuffer, 2))
 1597    {
 1598       pArg = ExtractWord(pArg, szBuffer);
 1599       if (IsCommand(_T("BIND"), szBuffer, 1))
 1600       {
 1601          pArg = ExtractWord(pArg, szBuffer);
 1602          uint32_t tunnelId = _tcstoul(szBuffer, nullptr, 0);
 1603 
 1604          ExtractWord(pArg, szBuffer);
 1605          uint32_t nodeId = _tcstoul(szBuffer, nullptr, 0);
 1606 
 1607          if ((tunnelId != 0) && (nodeId != 0))
 1608          {
 1609             UINT32 rcc = BindAgentTunnel(tunnelId, nodeId, 0);
 1610             ConsolePrintf(pCtx, _T("Bind tunnel %d to node %d: RCC = %d\n\n"), tunnelId, nodeId, rcc);
 1611          }
 1612          else
 1613          {
 1614             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing argument(s)\n\n"));
 1615          }
 1616       }
 1617       else if (IsCommand(_T("UNBIND"), szBuffer, 1))
 1618       {
 1619          ExtractWord(pArg, szBuffer);
 1620          UINT32 nodeId = _tcstoul(szBuffer, nullptr, 0);
 1621 
 1622          if (nodeId != 0)
 1623          {
 1624             UINT32 rcc = UnbindAgentTunnel(nodeId, 0);
 1625             ConsolePrintf(pCtx, _T("Unbind tunnel from node %d: RCC = %d\n\n"), nodeId, rcc);
 1626          }
 1627          else
 1628          {
 1629             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing argument(s)\n\n"));
 1630          }
 1631       }
 1632       else
 1633       {
 1634          ConsoleWrite(pCtx, _T("ERROR: Invalid TUNNEL subcommand\n\n"));
 1635       }
 1636    }
 1637    else if (IsCommand(_T("HELP"), szBuffer, 2) || IsCommand(_T("?"), szBuffer, 1))
 1638    {
 1639       ConsoleWrite(pCtx,
 1640             _T("Valid commands are:\n")
 1641             _T("   at +<sec> <script> [<params>]     - Schedule one time script execution task\n")
 1642             _T("   at <schedule> <script> [<params>] - Schedule repeated script execution task\n")
 1643             _T("   clear                             - Show list of valid component names for clearing\n")
 1644             _T("   clear <component>                 - Clear internal data or queue for given component\n")
 1645             _T("   dbcp reset                        - Reset database connection pool\n")
 1646             _T("   debug [<level>|off]               - Set debug level (valid range is 0..9)\n")
 1647             _T("   debug [<debug tag> <level>|off|default]\n")
 1648             _T("                                     - Set debug level for a particular debug tag\n")
 1649             _T("   debug sql [on|off]                - Turn SQL query trace on or off\n")
 1650             _T("   down                              - Shutdown NetXMS server\n")
 1651             _T("   exec <script> [<params>]          - Executes NXSL script from script library\n")
 1652             _T("   exit                              - Exit from remote session\n")
 1653             _T("   kill <session>                    - Kill client session\n")
 1654             _T("   get <variable>                    - Get value of server configuration variable\n")
 1655             _T("   help                              - Display this help\n")
 1656             _T("   hkrun                             - Run housekeeper immediately\n")
 1657             _T("   ldapsync                          - Synchronize ldap users with local user database\n")
 1658             _T("   log <text>                        - Write given text to server log file\n")
 1659             _T("   logmark                           - Write marker ******* MARK ******* to server log file\n")
 1660             _T("   ping <address>                    - Send ICMP echo request to given IP address\n")
 1661             _T("   poll <type> <node>                - Initiate node poll\n")
 1662             _T("   raise <exception>                 - Raise exception\n")
 1663             _T("   scan rangeStart rangeEnd [proxy <id>|zone <uin>] [discovery] \n")
 1664             _T("                                     - Manual active discovery scan for given range. Without 'discovery' parameter prints results only\n")
 1665             _T("   set <variable> <value>            - Set value of server configuration variable\n")
 1666             _T("   show arp <node>                   - Show ARP cache for node\n")
 1667             _T("   show components <node>            - Show physical components of given node\n")
 1668             _T("   show dbcp                         - Show active sessions in database connection pool\n")
 1669             _T("   show dbstats                      - Show DB library statistics\n")
 1670             _T("   show discovery queue              - Show content of network discovery queue\n")
 1671             _T("   show ep                           - Show event processing threads statistics\n")
 1672             _T("   show fdb <node>                   - Show forwarding database for node\n")
 1673             _T("   show flags                        - Show internal server flags\n")
 1674             _T("   show heap details                 - Show detailed heap information\n")
 1675             _T("   show heap summary                 - Show heap usage summary\n")
 1676             _T("   show index <index>                - Show internal index\n")
 1677             _T("   show modules                      - Show loaded server modules\n")
 1678             _T("   show msgwq                        - Show message wait queues information\n")
 1679             _T("   show ndd                          - Show loaded network device drivers\n")
 1680             _T("   show objects [<filter>]           - Dump network objects to screen\n")
 1681             _T("   show pe                           - Show registered prediction engines\n")
 1682             _T("   show pollers                      - Show poller threads state information\n")
 1683             _T("   show queues                       - Show internal queues statistics\n")
 1684             _T("   show routing-table <node>         - Show cached routing table for node\n")
 1685             _T("   show sessions                     - Show active client sessions\n")
 1686             _T("   show stats                        - Show global server statistics\n")
 1687             _T("   show syncer                       - Show syncer statistics\n")
 1688             _T("   show topology <node>              - Collect and show link layer topology for node\n")
 1689             _T("   show tunnels                      - Show active agent tunnels\n")
 1690             _T("   show users                        - Show users\n")
 1691             _T("   show vlans <node>                 - Show cached VLAN information for node\n")
 1692             _T("   show watchdog                     - Display watchdog information\n")
 1693             _T("   trace <node1> <node2>             - Show network path trace between two nodes\n")
 1694             _T("   tunnel bind <tunnel> <node>       - Bind agent tunnel to node\n")
 1695             _T("   tunnel unbind <node>              - Unbind agent tunnel from node\n")
 1696             _T("\nAlmost all commands can be abbreviated to 2 or 3 characters\n")
 1697             _T("\n"));
 1698    }
 1699    else
 1700    {
 1701       bool processed = false;
 1702       ENUMERATE_MODULES(pfProcessServerConsoleCommand)
 1703       {
 1704          if (CURRENT_MODULE.pfProcessServerConsoleCommand(pszCmdLine, pCtx))
 1705          {
 1706             processed = true;
 1707             break;
 1708          }
 1709       }
 1710 
 1711       if (!processed)
 1712          ConsoleWrite(pCtx, _T("UNKNOWN COMMAND\n\n"));
 1713    }
 1714 
 1715    return nExitCode;
 1716 }