"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/server/core/snmptrap.cpp" (23 Feb 2021, 42330 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 "snmptrap.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.7.95_vs_3.7.116.

    1 /*
    2 ** NetXMS - Network Management System
    3 ** Copyright (C) 2003-2020 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: snmptrap.cpp
   20 **
   21 **/
   22 
   23 #include "nxcore.h"
   24 
   25 #define DEBUG_TAG _T("snmp.trap")
   26 
   27 #define BY_OBJECT_ID 0
   28 #define BY_POSITION 1
   29 
   30 /**
   31  * Total number of received SNMP traps
   32  */
   33 VolatileCounter64 g_snmpTrapsReceived = 0;
   34 
   35 /**
   36  * Max SNMP packet length
   37  */
   38 #define MAX_PACKET_LENGTH     65536
   39 
   40 /**
   41  * Static data
   42  */
   43 static Mutex s_trapCfgLock;
   44 static ObjectArray<SNMPTrapConfiguration> m_trapCfgList(16, 4, Ownership::True);
   45 static VolatileCounter64 s_trapId = 0; // Last used trap ID
   46 static uint16_t s_trapListenerPort = 162;
   47 
   48 /**
   49  * Create new SNMP trap configuration object
   50  */
   51 SNMPTrapConfiguration::SNMPTrapConfiguration() : m_objectId(), m_mappings(8, 8, Ownership::True)
   52 {
   53    m_guid = uuid::generate();
   54    m_id = CreateUniqueId(IDG_SNMP_TRAP);
   55    m_eventCode = EVENT_SNMP_UNMATCHED_TRAP;
   56    m_eventTag = nullptr;
   57    m_description = nullptr;
   58    m_scriptSource = nullptr;
   59    m_script = nullptr;
   60 }
   61 
   62 /**
   63  * Create SNMP trap configuration object from database
   64  */
   65 SNMPTrapConfiguration::SNMPTrapConfiguration(DB_RESULT trapResult, DB_HANDLE hdb, DB_STATEMENT stmt, int row) : m_mappings(8, 8, Ownership::True)
   66 {
   67    m_id = DBGetFieldULong(trapResult, row, 0);
   68    TCHAR buffer[MAX_OID_LENGTH];
   69    m_objectId = SNMP_ObjectId::parse(DBGetField(trapResult, row, 1, buffer, MAX_OID_LENGTH));
   70    m_eventCode = DBGetFieldULong(trapResult, row, 2);
   71    m_description = DBGetField(trapResult, row, 3, nullptr, 0);
   72    m_eventTag = DBGetField(trapResult, row, 4, nullptr, 0);
   73    m_guid = DBGetFieldGUID(trapResult, row, 5);
   74    m_scriptSource = DBGetField(trapResult, row, 6, nullptr, 0);
   75    m_script = nullptr;
   76 
   77    DB_RESULT mapResult;
   78    if (stmt != nullptr)
   79    {
   80       DBBind(stmt, 1, DB_SQLTYPE_INTEGER, m_id);
   81       mapResult = DBSelectPrepared(stmt);
   82    }
   83    else
   84    {
   85       TCHAR query[256];
   86       _sntprintf(query, 256, _T("SELECT snmp_oid,description,flags FROM snmp_trap_pmap WHERE trap_id=%u ORDER BY parameter"), m_id);
   87       mapResult = DBSelect(hdb, query);
   88    }
   89    if (mapResult != nullptr)
   90    {
   91       int mapCount = DBGetNumRows(mapResult);
   92       for(int i = 0; i < mapCount; i++)
   93       {
   94          SNMPTrapParameterMapping *param = new SNMPTrapParameterMapping(mapResult, i);
   95          if (!param->isPositional() && !param->getOid()->isValid())
   96             nxlog_write(NXLOG_WARNING, _T("Invalid trap parameter OID %s for trap %u in trap configuration table"), (const TCHAR *)param->getOid()->toString(), m_id);
   97          m_mappings.add(param);
   98       }
   99       DBFreeResult(mapResult);
  100    }
  101 
  102    compileScript();
  103 }
  104 
  105 /**
  106  * Create SNMP trap configuration object from config entry
  107  */
  108 SNMPTrapConfiguration::SNMPTrapConfiguration(const ConfigEntry& entry, const uuid& guid, uint32_t id, uint32_t eventCode) : m_mappings(8, 8, Ownership::True)
  109 {
  110    if (id == 0)
  111       m_id = CreateUniqueId(IDG_SNMP_TRAP);
  112    else
  113       m_id = id;
  114 
  115    m_guid = guid;
  116    m_objectId = SNMP_ObjectId::parse(entry.getSubEntryValue(_T("oid"), 0, _T("")));
  117    m_eventCode = eventCode;
  118    m_description = MemCopyString(entry.getSubEntryValue(_T("description")));
  119    m_eventTag = MemCopyString(entry.getSubEntryValue(_T("eventTag"), 0, entry.getSubEntryValue(_T("userTag"))));
  120    m_scriptSource = MemCopyString(entry.getSubEntryValue(_T("transformationScript")));
  121    m_script = nullptr;
  122 
  123    const ConfigEntry *parametersRoot = entry.findEntry(_T("parameters"));
  124    if (parametersRoot != nullptr)
  125    {
  126       ObjectArray<ConfigEntry> *parameters = parametersRoot->getOrderedSubEntries(_T("parameter#*"));
  127       if (parameters->size() > 0)
  128       {
  129          for(int i = 0; i < parameters->size(); i++)
  130          {
  131             SNMPTrapParameterMapping *param = new SNMPTrapParameterMapping(parameters->get(i));
  132             if (!param->isPositional() && !param->getOid()->isValid())
  133                nxlog_write(NXLOG_WARNING, _T("Invalid trap parameter OID %s for trap %u in trap configuration table"), param->getOid()->toString().cstr(), m_id);
  134             m_mappings.add(param);
  135          }
  136       }
  137       delete parameters;
  138    }
  139 
  140    compileScript();
  141 }
  142 
  143 /**
  144  * Create SNMP trap configuration object from NXCPMessage
  145  */
  146 SNMPTrapConfiguration::SNMPTrapConfiguration(NXCPMessage *msg) : m_mappings(8, 8, Ownership::True)
  147 {
  148    UINT32 buffer[MAX_OID_LENGTH];
  149 
  150    m_id = msg->getFieldAsUInt32(VID_TRAP_ID);
  151    msg->getFieldAsInt32Array(VID_TRAP_OID, msg->getFieldAsUInt32(VID_TRAP_OID_LEN), buffer);
  152    m_objectId = SNMP_ObjectId(buffer, msg->getFieldAsUInt32(VID_TRAP_OID_LEN));
  153    m_eventCode = msg->getFieldAsUInt32(VID_EVENT_CODE);
  154    m_description = msg->getFieldAsString(VID_DESCRIPTION);
  155    m_eventTag = msg->getFieldAsString(VID_USER_TAG);
  156    m_scriptSource = msg->getFieldAsString(VID_TRANSFORMATION_SCRIPT);
  157    m_script = nullptr;
  158 
  159    // Read new mappings from message
  160    int count = msg->getFieldAsInt32(VID_TRAP_NUM_MAPS);
  161    UINT32 base = VID_TRAP_PBASE;
  162    for(int i = 0; i < count; i++, base += 10)
  163    {
  164       m_mappings.add(new SNMPTrapParameterMapping(msg, base));
  165    }
  166 
  167    compileScript();
  168 }
  169 
  170 /**
  171  * Destructor for SNMP trap configuration object
  172  */
  173 SNMPTrapConfiguration::~SNMPTrapConfiguration()
  174 {
  175    MemFree(m_description);
  176    MemFree(m_eventTag);
  177    MemFree(m_scriptSource);
  178    delete m_script;
  179 }
  180 
  181 /**
  182  * Compile transformation script
  183  */
  184 void SNMPTrapConfiguration::compileScript()
  185 {
  186    delete m_script;
  187    if ((m_scriptSource != nullptr) && (*m_scriptSource != 0))
  188    {
  189       TCHAR errorMessage[1024];
  190       m_script = NXSLCompile(m_scriptSource, errorMessage, 1024, nullptr);
  191       if (m_script == nullptr)
  192       {
  193          TCHAR buffer[1024];
  194          _sntprintf(buffer, 1024, _T("SNMPTrap::%d"), m_id);
  195          PostSystemEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, errorMessage, m_id);
  196          nxlog_write_tag(NXLOG_WARNING, DEBUG_TAG, _T("Failed to compile SNMP trap transformation script for trap mapping [%u] (%s)"), m_id, errorMessage);
  197       }
  198    }
  199    else
  200    {
  201       m_script = nullptr;
  202    }
  203 }
  204 
  205 /**
  206  * Fill NXCP message with trap configuration data
  207  */
  208 void SNMPTrapConfiguration::fillMessage(NXCPMessage *msg) const
  209 {
  210    msg->setField(VID_TRAP_ID, m_id);
  211    msg->setField(VID_TRAP_OID_LEN, (UINT32)m_objectId.length());
  212    msg->setFieldFromInt32Array(VID_TRAP_OID, m_objectId.length(), m_objectId.value());
  213    msg->setField(VID_EVENT_CODE, m_eventCode);
  214    msg->setField(VID_DESCRIPTION, CHECK_NULL_EX(m_description));
  215    msg->setField(VID_USER_TAG, CHECK_NULL_EX(m_eventTag));
  216    msg->setField(VID_TRANSFORMATION_SCRIPT, CHECK_NULL_EX(m_scriptSource));
  217 
  218    msg->setField(VID_TRAP_NUM_MAPS, (UINT32)m_mappings.size());
  219    UINT32 base = VID_TRAP_PBASE;
  220    for(int i = 0; i < m_mappings.size(); i++, base += 10)
  221    {
  222       m_mappings.get(i)->fillMessage(msg, base);
  223    }
  224 }
  225 
  226 /**
  227  * Fill NXCP message with trap configuration for list
  228  */
  229 void SNMPTrapConfiguration::fillMessage(NXCPMessage *msg, UINT32 base) const
  230 {
  231    msg->setField(base, m_id);
  232    msg->setField(base + 1, CHECK_NULL_EX(m_description));
  233    msg->setFieldFromInt32Array(base + 2, m_objectId.length(), m_objectId.value());
  234    msg->setField(base + 3, m_eventCode);
  235 }
  236 
  237 /**
  238  * Notify clients about trap configuration change
  239  */
  240 void NotifyOnTrapCfgChangeCB(ClientSession *session, NXCPMessage *msg)
  241 {
  242    if (session->isAuthenticated())
  243       session->postMessage(msg);
  244 }
  245 
  246 /**
  247  * Notify clients of trap cfg change
  248  */
  249 void SNMPTrapConfiguration::notifyOnTrapCfgChange(UINT32 code)
  250 {
  251    NXCPMessage msg;
  252    msg.setCode(CMD_TRAP_CFG_UPDATE);
  253    msg.setField(VID_NOTIFICATION_CODE, code);
  254    fillMessage(&msg);
  255    EnumerateClientSessions(NotifyOnTrapCfgChangeCB, &msg);
  256 }
  257 
  258 /**
  259  * SNMP trap parameter map default constructor
  260  */
  261 SNMPTrapParameterMapping::SNMPTrapParameterMapping()
  262 {
  263    m_objectId = new SNMP_ObjectId();
  264    m_position = 0;
  265    m_flags = 0;
  266    m_description = nullptr;
  267 }
  268 
  269 /**
  270  * Create SNMP trap parameter map object from database
  271  */
  272 SNMPTrapParameterMapping::SNMPTrapParameterMapping(DB_RESULT mapResult, int row)
  273 {
  274    TCHAR oid[MAX_DB_STRING];
  275    DBGetField(mapResult, row, 0, oid, MAX_DB_STRING);
  276 
  277    if (!_tcsncmp(oid, _T("POS:"), 4))
  278    {
  279       m_objectId = nullptr;
  280       m_position = _tcstoul(&oid[4], nullptr, 10);
  281    }
  282    else
  283    {
  284       m_objectId = new SNMP_ObjectId(SNMP_ObjectId::parse(oid));
  285       m_position = 0;
  286    }
  287 
  288    m_description = DBGetField(mapResult, row, 1, nullptr, 0);
  289    m_flags = DBGetFieldULong(mapResult, row, 2);
  290 }
  291 
  292 /**
  293  * Create SNMP trap parameter map object from config entry
  294  */
  295 SNMPTrapParameterMapping::SNMPTrapParameterMapping(ConfigEntry *entry)
  296 {
  297    int position = entry->getSubEntryValueAsInt(_T("position"), 0, -1);
  298    if (position > 0)
  299    {
  300       m_objectId = nullptr;
  301       m_position = position; // Positional parameter
  302    }
  303    else
  304    {
  305       m_objectId = new SNMP_ObjectId(SNMP_ObjectId::parse(entry->getSubEntryValue(_T("oid"), 0, _T("")))); // OID parameter
  306       m_position = 0;
  307    }
  308 
  309    m_description = MemCopyString(entry->getSubEntryValue(_T("description")));
  310    m_flags = entry->getSubEntryValueAsUInt(_T("flags"), 0, 0);
  311 }
  312 
  313 /**
  314  * Create SNMP trap parameter map object from NXCPMessage
  315  */
  316 SNMPTrapParameterMapping::SNMPTrapParameterMapping(NXCPMessage *msg, UINT32 base)
  317 {
  318    m_flags = msg->getFieldAsUInt32(base);
  319    m_description = msg->getFieldAsString(base + 1);
  320    if (msg->getFieldAsUInt32(base + 2) == BY_POSITION)
  321    {
  322       m_objectId = nullptr;
  323       m_position = msg->getFieldAsUInt32(base + 3);
  324    }
  325    else
  326    {
  327       UINT32 buffer[MAX_OID_LENGTH];
  328       msg->getFieldAsInt32Array(base + 3, msg->getFieldAsUInt32(base + 4), buffer);
  329       m_objectId = new SNMP_ObjectId(buffer, msg->getFieldAsUInt32(base + 4));
  330    }
  331 }
  332 
  333 /**
  334  * Destructor for SNMP trap parameter map object
  335  */
  336 SNMPTrapParameterMapping::~SNMPTrapParameterMapping()
  337 {
  338    delete m_objectId;
  339    MemFree(m_description);
  340 }
  341 
  342 /**
  343  * Fill NXCP message with trap parameter map configuration data
  344  */
  345 void SNMPTrapParameterMapping::fillMessage(NXCPMessage *msg, UINT32 base) const
  346 {
  347    msg->setField(base, isPositional());
  348    if (isPositional())
  349       msg->setField(base + 1, m_position);
  350    else
  351       msg->setFieldFromInt32Array(base + 1, m_objectId->length(), m_objectId->value());
  352    msg->setField(base + 2, CHECK_NULL_EX(m_description));
  353    msg->setField(base + 3, m_flags);
  354 
  355 }
  356 
  357 /**
  358  * Load trap configuration from database
  359  */
  360 void LoadTrapCfg()
  361 {
  362    DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
  363 
  364    // Load traps
  365    DB_RESULT hResult = DBSelect(hdb, _T("SELECT trap_id,snmp_oid,event_code,description,user_tag,guid,transformation_script FROM snmp_trap_cfg"));
  366    if (hResult != nullptr)
  367    {
  368       DB_STATEMENT hStmt = (g_dbSyntax == DB_SYNTAX_ORACLE) ?
  369                DBPrepare(hdb, _T("SELECT snmp_oid,description,flags FROM snmp_trap_pmap WHERE trap_id=? ORDER BY parameter"), true)
  370                : nullptr;
  371       if ((g_dbSyntax != DB_SYNTAX_ORACLE) || (hStmt != nullptr))
  372       {
  373          int numRows = DBGetNumRows(hResult);
  374          for(int i = 0; i < numRows; i++)
  375          {
  376             SNMPTrapConfiguration *trapCfg = new SNMPTrapConfiguration(hResult, hdb, hStmt, i);
  377             if (!trapCfg->getOid().isValid())
  378             {
  379                TCHAR buffer[MAX_DB_STRING];
  380                nxlog_write(NXLOG_ERROR, _T("Invalid trap enterprise ID %s in trap configuration table"),
  381                         DBGetField(hResult, i, 1, buffer, MAX_DB_STRING));
  382             }
  383             m_trapCfgList.add(trapCfg);
  384          }
  385          if (hStmt != nullptr)
  386             DBFreeStatement(hStmt);
  387       }
  388       DBFreeResult(hResult);
  389    }
  390 
  391    DBConnectionPoolReleaseConnection(hdb);
  392 }
  393 
  394 /**
  395  * Get last SNMP Trap id
  396  */
  397 int64_t GetLastSnmpTrapId()
  398 {
  399    return s_trapId;
  400 }
  401 
  402 /**
  403  * Initialize trap handling
  404  */
  405 void InitTraps()
  406 {
  407    LoadTrapCfg();
  408 
  409    int64_t id = ConfigReadInt64(_T("LastSNMPTrapId"), 0);
  410    if (id > s_trapId)
  411       s_trapId = id;
  412    DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
  413    DB_RESULT hResult = DBSelect(hdb, _T("SELECT max(trap_id) FROM snmp_trap_log"));
  414    if (hResult != nullptr)
  415    {
  416       if (DBGetNumRows(hResult) > 0)
  417          s_trapId = std::max(DBGetFieldInt64(hResult, 0, 0), static_cast<int64_t>(s_trapId));
  418       DBFreeResult(hResult);
  419    }
  420    DBConnectionPoolReleaseConnection(hdb);
  421 
  422    s_trapListenerPort = static_cast<uint16_t>(ConfigReadULong(_T("SNMP.Traps.ListenerPort"), s_trapListenerPort)); // 162 by default;
  423 }
  424 
  425 /**
  426  * Generate event for matched trap
  427  */
  428 static void GenerateTrapEvent(const shared_ptr<Node>& node, UINT32 dwIndex, SNMP_PDU *pdu, int sourcePort)
  429 {
  430    SNMPTrapConfiguration *trapCfg = m_trapCfgList.get(dwIndex);
  431 
  432    StringMap parameters;
  433    parameters.set(_T("oid"), pdu->getTrapId()->toString());
  434 
  435     // Extract varbinds from trap and add them as event's parameters
  436    int numMaps = trapCfg->getParameterMappingCount();
  437    for(int i = 0; i < numMaps; i++)
  438    {
  439       const SNMPTrapParameterMapping *pm = trapCfg->getParameterMapping(i);
  440       if (pm->isPositional())
  441       {
  442             // Extract by varbind position
  443          // Position numbering in mapping starts from 1,
  444          // SNMP v2/v3 trap contains uptime and trap OID at positions 0 and 1,
  445          // so map first mapping position to index 2 and so on
  446          int index = (pdu->getVersion() == SNMP_VERSION_1) ? pm->getPosition() - 1 : pm->getPosition() + 1;
  447          SNMP_Variable *varbind = pdu->getVariable(index);
  448          if (varbind != nullptr)
  449          {
  450                 bool convertToHex = true;
  451             TCHAR name[64], buffer[3072];
  452             _sntprintf(name, 64, _T("%d"), pm->getPosition());
  453                 parameters.set(name,
  454                ((g_flags & AF_ALLOW_TRAP_VARBIND_CONVERSION) && !(pm->getFlags() & TRAP_VARBIND_FORCE_TEXT)) ?
  455                   varbind->getValueAsPrintableString(buffer, 3072, &convertToHex) :
  456                   varbind->getValueAsString(buffer, 3072));
  457          }
  458       }
  459       else
  460       {
  461             // Extract by varbind OID
  462          for(int j = 0; j < pdu->getNumVariables(); j++)
  463          {
  464             SNMP_Variable *varbind = pdu->getVariable(j);
  465             int result = varbind->getName().compare(*(pm->getOid()));
  466             if ((result == OID_EQUAL) || (result == OID_LONGER))
  467             {
  468                     bool convertToHex = true;
  469                     TCHAR buffer[3072];
  470                     parameters.set(varbind->getName().toString(),
  471                   ((g_flags & AF_ALLOW_TRAP_VARBIND_CONVERSION) && !(pm->getFlags() & TRAP_VARBIND_FORCE_TEXT)) ?
  472                      varbind->getValueAsPrintableString(buffer, 3072, &convertToHex) :
  473                      varbind->getValueAsString(buffer, 3072));
  474                break;
  475             }
  476          }
  477       }
  478    }
  479 
  480    parameters.set(_T("sourcePort"), sourcePort);
  481 
  482    NXSL_VM *vm;
  483    if ((trapCfg->getScript() != nullptr) && !trapCfg->getScript()->isEmpty())
  484    {
  485       vm = CreateServerScriptVM(trapCfg->getScript(), node);
  486       if (vm != nullptr)
  487       {
  488          vm->setGlobalVariable("$trap", vm->createValue(pdu->getTrapId()->toString()));
  489          NXSL_Array *varbinds = new NXSL_Array(vm);
  490          for(int i = (pdu->getVersion() == SNMP_VERSION_1) ? 0 : 2; i < pdu->getNumVariables(); i++)
  491          {
  492             varbinds->append(vm->createValue(new NXSL_Object(vm, &g_nxslSnmpVarBindClass, new SNMP_Variable(pdu->getVariable(i)))));
  493          }
  494          vm->setGlobalVariable("$varbinds", vm->createValue(varbinds));
  495       }
  496       else
  497       {
  498          nxlog_debug_tag(DEBUG_TAG, 6, _T("GenerateTrapEvent: cannot load transformation script for trap mapping [%u]"), trapCfg->getId());
  499       }
  500    }
  501    else
  502    {
  503       vm = nullptr;
  504    }
  505    TransformAndPostEvent(trapCfg->getEventCode(), EventOrigin::SNMP, 0, node->getId(), trapCfg->getEventTag(), &parameters, vm);
  506    delete vm;
  507 }
  508 
  509 /**
  510  * Handler for EnumerateSessions()
  511  */
  512 static void BroadcastNewTrap(ClientSession *pSession, NXCPMessage *msg)
  513 {
  514    pSession->onNewSNMPTrap(msg);
  515 }
  516 
  517 /**
  518  * Build trap varbind list
  519  */
  520 static StringBuffer BuildVarbindList(SNMP_PDU *pdu)
  521 {
  522    StringBuffer out;
  523    TCHAR oidText[1024], data[4096];
  524 
  525    for(int i = (pdu->getVersion() == SNMP_VERSION_1) ? 0 : 2; i < pdu->getNumVariables(); i++)
  526    {
  527       SNMP_Variable *v = pdu->getVariable(i);
  528       if (!out.isEmpty())
  529          out.append(_T("; "));
  530 
  531       v->getName().toString(oidText, 1024);
  532 
  533       bool convertToHex = true;
  534       if (g_flags & AF_ALLOW_TRAP_VARBIND_CONVERSION)
  535          v->getValueAsPrintableString(data, 4096, &convertToHex);
  536       else
  537          v->getValueAsString(data, 4096);
  538 
  539       nxlog_debug_tag(DEBUG_TAG, 5, _T("   %s == '%s'"), oidText, data);
  540 
  541       out.append(oidText);
  542       out.append(_T(" == '"));
  543       out.append(data);
  544       out.append(_T('\''));
  545    }
  546 
  547    return out;
  548 }
  549 
  550 /**
  551  * Process trap
  552  */
  553 void ProcessTrap(SNMP_PDU *pdu, const InetAddress& srcAddr, int32_t zoneUIN, int srcPort, SNMP_Transport *snmpTransport, SNMP_Engine *localEngine, bool isInformRq)
  554 {
  555    StringBuffer varbinds;
  556    TCHAR buffer[4096];
  557     bool processedByModule = false;
  558    int iResult;
  559 
  560    InterlockedIncrement64(&g_snmpTrapsReceived);
  561    nxlog_debug_tag(DEBUG_TAG, 4, _T("Received SNMP %s %s from %s"), isInformRq ? _T("INFORM-REQUEST") : _T("TRAP"),
  562              pdu->getTrapId()->toString(&buffer[96], 4000), srcAddr.toString(buffer));
  563 
  564     if (isInformRq)
  565     {
  566         SNMP_PDU response(SNMP_RESPONSE, pdu->getRequestId(), pdu->getVersion());
  567         if (snmpTransport->getSecurityContext() == nullptr)
  568         {
  569            snmpTransport->setSecurityContext(new SNMP_SecurityContext(pdu->getCommunity()));
  570         }
  571         response.setMessageId(pdu->getMessageId());
  572         response.setContextEngineId(localEngine->getId(), localEngine->getIdLen());
  573         snmpTransport->sendMessage(&response, 0);
  574     }
  575 
  576    // Match IP address to object
  577    shared_ptr<Node> node = FindNodeByIP(zoneUIN, (g_flags & AF_TRAP_SOURCES_IN_ALL_ZONES) != 0, srcAddr);
  578 
  579    // Write trap to log if required
  580    if ((node != nullptr) || (g_flags & AF_LOG_ALL_SNMP_TRAPS))
  581    {
  582       time_t timestamp = time(nullptr);
  583 
  584       nxlog_debug_tag(DEBUG_TAG, 5, _T("Varbinds for %s %s from %s:"), isInformRq ? _T("INFORM-REQUEST") : _T("TRAP"), &buffer[96], buffer);
  585       varbinds = BuildVarbindList(pdu);
  586 
  587       // Write new trap to database
  588         uint64_t trapId = InterlockedIncrement64(&s_trapId);
  589       TCHAR query[8192], oidText[1024];
  590       _sntprintf(query, 8192, _T("INSERT INTO snmp_trap_log (trap_id,trap_timestamp,")
  591                                 _T("ip_addr,object_id,zone_uin,trap_oid,trap_varlist) VALUES ")
  592                                 _T("(") UINT64_FMT _T(",%s") INT64_FMT _T("%s,'%s',%d,%d,'%s',%s)"),
  593                  trapId, (g_dbSyntax == DB_SYNTAX_TSDB) ? _T("to_timestamp(") : _T(""), static_cast<int64_t>(timestamp),
  594                  (g_dbSyntax == DB_SYNTAX_TSDB) ? _T(")") : _T(""), srcAddr.toString(buffer),
  595                  (node != nullptr) ? node->getId() : (UINT32)0, (node != nullptr) ? node->getZoneUIN() : zoneUIN,
  596                  pdu->getTrapId()->toString(oidText, 1024),
  597                  (const TCHAR *)DBPrepareString(g_dbDriver, varbinds));
  598       QueueSQLRequest(query);
  599 
  600       // Notify connected clients
  601       NXCPMessage msg;
  602       msg.setCode(CMD_TRAP_LOG_RECORDS);
  603       msg.setField(VID_NUM_RECORDS, (UINT32)1);
  604       msg.setField(VID_RECORDS_ORDER, (WORD)RECORD_ORDER_NORMAL);
  605       msg.setField(VID_TRAP_LOG_MSG_BASE, trapId);
  606       msg.setFieldFromTime(VID_TRAP_LOG_MSG_BASE + 1, timestamp);
  607       msg.setField(VID_TRAP_LOG_MSG_BASE + 2, srcAddr);
  608       msg.setField(VID_TRAP_LOG_MSG_BASE + 3, (node != nullptr) ? node->getId() : (UINT32)0);
  609       msg.setField(VID_TRAP_LOG_MSG_BASE + 4, pdu->getTrapId()->toString(oidText, 1024));
  610       msg.setField(VID_TRAP_LOG_MSG_BASE + 5, varbinds);
  611       EnumerateClientSessions(BroadcastNewTrap, &msg);
  612    }
  613    else if (nxlog_get_debug_level_tag(DEBUG_TAG) >= 5)
  614    {
  615       nxlog_debug_tag(DEBUG_TAG, 5, _T("Varbinds for %s %s:"), isInformRq ? _T("INFORM-REQUEST") : _T("TRAP"), &buffer[96]);
  616       BuildVarbindList(pdu);
  617    }
  618 
  619    // Process trap if it is coming from host registered in database
  620    if (node != nullptr)
  621    {
  622       nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: trap matched to node %s [%d]"), node->getName(), node->getId());
  623       node->incSnmpTrapCount();
  624       if (node->checkTrapShouldBeProcessed())
  625       {
  626          if ((node->getStatus() != STATUS_UNMANAGED) || (g_flags & AF_TRAPS_FROM_UNMANAGED_NODES))
  627          {
  628             // Pass trap to loaded modules
  629             ENUMERATE_MODULES(pfTrapHandler)
  630             {
  631                if (CURRENT_MODULE.pfTrapHandler(pdu, node))
  632                {
  633                   processedByModule = true;
  634                   break;   // Trap was processed by the module
  635                }
  636             }
  637 
  638             // Find if we have this trap in our list
  639             s_trapCfgLock.lock();
  640 
  641             // Try to find closest match
  642             size_t matchLen = 0;
  643             int matchIndex;
  644             for(int i = 0; i < m_trapCfgList.size(); i++)
  645             {
  646                const SNMPTrapConfiguration *trapCfg = m_trapCfgList.get(i);
  647                if (trapCfg->getOid().length() > 0)
  648                {
  649                   iResult = pdu->getTrapId()->compare(trapCfg->getOid());
  650                   if (iResult == OID_EQUAL)
  651                   {
  652                      matchLen = trapCfg->getOid().length();
  653                      matchIndex = i;
  654                      break;   // Find exact match
  655                   }
  656                   else if (iResult == OID_LONGER)
  657                   {
  658                      if (trapCfg->getOid().length() > matchLen)
  659                      {
  660                         matchLen = trapCfg->getOid().length();
  661                         matchIndex = i;
  662                      }
  663                   }
  664                }
  665             }
  666 
  667             if (matchLen > 0)
  668             {
  669                GenerateTrapEvent(node, matchIndex, pdu, srcPort);
  670             }
  671             else if (!processedByModule)    // Process unmatched traps not processed by module
  672             {
  673                // Generate default event for unmatched traps
  674                const TCHAR *names[3] = { _T("oid"), nullptr, _T("sourcePort") };
  675                TCHAR oidText[1024];
  676                PostEventWithNames(EVENT_SNMP_UNMATCHED_TRAP, EventOrigin::SNMP, 0, node->getId(), "ssd", names,
  677                   pdu->getTrapId()->toString(oidText, 1024), (const TCHAR *)varbinds, srcPort);
  678             }
  679             s_trapCfgLock.unlock();
  680          }
  681          else
  682          {
  683             nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: Node %s [%d] is in UNMANAGED state, trap ignored"), node->getName(), node->getId());
  684          }
  685       }
  686       else
  687       {
  688          nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: Node %s [%d] is in trap flood state, trap is dropped"), node->getName(), node->getId());
  689       }
  690    }
  691    else if (g_flags & AF_SNMP_TRAP_DISCOVERY)  // unknown node, discovery enabled
  692    {
  693       nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: trap not matched to node, adding new IP address %s for discovery"), srcAddr.toString(buffer));
  694       CheckPotentialNode(srcAddr, zoneUIN, DA_SRC_SNMP_TRAP, 0);
  695    }
  696    else  // unknown node, discovery disabled
  697    {
  698       nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: trap not matched to any node"));
  699    }
  700 }
  701 
  702 /**
  703  * Context finder - tries to find SNMPv3 security context by IP address
  704  */
  705 static SNMP_SecurityContext *ContextFinder(struct sockaddr *addr, socklen_t addrLen)
  706 {
  707    InetAddress ipAddr = InetAddress::createFromSockaddr(addr);
  708     shared_ptr<Node> node = FindNodeByIP((g_flags & AF_TRAP_SOURCES_IN_ALL_ZONES) ? ALL_ZONES : 0, ipAddr);
  709     TCHAR buffer[64];
  710     nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: looking for SNMP security context for node %s %s"),
  711       ipAddr.toString(buffer), (node != nullptr) ? node->getName() : _T("<unknown>"));
  712     return (node != nullptr) ? node->getSnmpSecurityContext() : nullptr;
  713 }
  714 
  715 /**
  716  * Create SNMP transport for receiver
  717  */
  718 static SNMP_Transport *CreateTransport(SOCKET hSocket)
  719 {
  720    if (hSocket == INVALID_SOCKET)
  721       return nullptr;
  722 
  723    SNMP_Transport *t = new SNMP_UDPTransport(hSocket);
  724     t->enableEngineIdAutoupdate(true);
  725     t->setPeerUpdatedOnRecv(true);
  726    return t;
  727 }
  728 
  729 /**
  730  * SNMP trap receiver thread
  731  */
  732 void SNMPTrapReceiver()
  733 {
  734    static BYTE engineId[] = { 0x80, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00 };
  735    SNMP_Engine localEngine(engineId, 12);
  736 
  737    ThreadSetName("SNMPTrapRecv");
  738 
  739    SOCKET hSocket = CreateSocket(AF_INET, SOCK_DGRAM, 0);
  740 #ifdef WITH_IPV6
  741    SOCKET hSocket6 = CreateSocket(AF_INET6, SOCK_DGRAM, 0);
  742 #endif
  743 
  744 #ifdef WITH_IPV6
  745    if ((hSocket == INVALID_SOCKET) && (hSocket6 == INVALID_SOCKET))
  746 #else
  747    if (hSocket == INVALID_SOCKET)
  748 #endif
  749    {
  750       TCHAR buffer[1024];
  751       nxlog_write(NXLOG_ERROR, _T("Unable to create socket for SNMP trap receiver (%s)"), GetLastSocketErrorText(buffer, 1024));
  752       return;
  753    }
  754 
  755    SetSocketExclusiveAddrUse(hSocket);
  756    SetSocketReuseFlag(hSocket);
  757 #ifndef _WIN32
  758    fcntl(hSocket, F_SETFD, fcntl(hSocket, F_GETFD) | FD_CLOEXEC);
  759 #endif
  760 
  761 #ifdef WITH_IPV6
  762    SetSocketExclusiveAddrUse(hSocket6);
  763    SetSocketReuseFlag(hSocket6);
  764 #ifndef _WIN32
  765    fcntl(hSocket6, F_SETFD, fcntl(hSocket6, F_GETFD) | FD_CLOEXEC);
  766 #endif
  767 #ifdef IPV6_V6ONLY
  768    int on = 1;
  769    setsockopt(hSocket6, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(int));
  770 #endif
  771 #endif
  772 
  773    // Fill in local address structure
  774    struct sockaddr_in servAddr;
  775    memset(&servAddr, 0, sizeof(struct sockaddr_in));
  776    servAddr.sin_family = AF_INET;
  777 
  778 #ifdef WITH_IPV6
  779    struct sockaddr_in6 servAddr6;
  780    memset(&servAddr6, 0, sizeof(struct sockaddr_in6));
  781    servAddr6.sin6_family = AF_INET6;
  782 #endif
  783    if (!_tcscmp(g_szListenAddress, _T("*")))
  784     {
  785         servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  786 #ifdef WITH_IPV6
  787         memset(servAddr6.sin6_addr.s6_addr, 0, 16);
  788 #endif
  789     }
  790     else
  791     {
  792       InetAddress bindAddress = InetAddress::resolveHostName(g_szListenAddress, AF_INET);
  793       if (bindAddress.isValid() && (bindAddress.getFamily() == AF_INET))
  794       {
  795            servAddr.sin_addr.s_addr = htonl(bindAddress.getAddressV4());
  796       }
  797       else
  798       {
  799         servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  800       }
  801 #ifdef WITH_IPV6
  802       bindAddress = InetAddress::resolveHostName(g_szListenAddress, AF_INET6);
  803       if (bindAddress.isValid() && (bindAddress.getFamily() == AF_INET6))
  804       {
  805            memcpy(servAddr6.sin6_addr.s6_addr, bindAddress.getAddressV6(), 16);
  806       }
  807       else
  808       {
  809         memset(servAddr6.sin6_addr.s6_addr, 0, 15);
  810          servAddr6.sin6_addr.s6_addr[15] = 1;
  811       }
  812 #endif
  813     }
  814    servAddr.sin_port = htons(s_trapListenerPort);
  815 #ifdef WITH_IPV6
  816    servAddr6.sin6_port = htons(s_trapListenerPort);
  817 #endif
  818 
  819    // Bind socket
  820    TCHAR buffer[64];
  821    int bindFailures = 0;
  822    nxlog_debug_tag(DEBUG_TAG, 5, _T("Trying to bind on UDP %s:%d"), SockaddrToStr((struct sockaddr *)&servAddr, buffer), ntohs(servAddr.sin_port));
  823    if (bind(hSocket, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
  824    {
  825       TCHAR buffer[1024];
  826       nxlog_write(NXLOG_ERROR, _T("Unable to bind IPv4 socket for SNMP trap receiver (%s)"), GetLastSocketErrorText(buffer, 1024));
  827       bindFailures++;
  828       closesocket(hSocket);
  829       hSocket = INVALID_SOCKET;
  830    }
  831 
  832 #ifdef WITH_IPV6
  833    nxlog_debug_tag(DEBUG_TAG, 5, _T("Trying to bind on UDP [%s]:%d"), SockaddrToStr((struct sockaddr *)&servAddr6, buffer), ntohs(servAddr6.sin6_port));
  834    if (bind(hSocket6, (struct sockaddr *)&servAddr6, sizeof(struct sockaddr_in6)) != 0)
  835    {
  836       TCHAR buffer[1024];
  837       nxlog_write(NXLOG_ERROR, _T("Unable to bind IPv6 socket for SNMP trap receiver (%s)"), GetLastSocketErrorText(buffer, 1024));
  838       bindFailures++;
  839       closesocket(hSocket6);
  840       hSocket6 = INVALID_SOCKET;
  841    }
  842 #else
  843    bindFailures++;
  844 #endif
  845 
  846    // Abort if cannot bind to at least one socket
  847    if (bindFailures == 2)
  848    {
  849       nxlog_debug_tag(DEBUG_TAG, 1, _T("SNMP trap receiver aborted - cannot bind at least one socket"));
  850       return;
  851    }
  852 
  853    if (hSocket != INVALID_SOCKET)
  854    {
  855       TCHAR ipAddrText[64];
  856        nxlog_write(NXLOG_INFO, _T("Listening for SNMP traps on UDP socket %s:%u"), InetAddress(ntohl(servAddr.sin_addr.s_addr)).toString(ipAddrText), s_trapListenerPort);
  857    }
  858 #ifdef WITH_IPV6
  859    if (hSocket6 != INVALID_SOCKET)
  860    {
  861       TCHAR ipAddrText[64];
  862       nxlog_write(NXLOG_INFO, _T("Listening for SNMP traps on UDP socket %s:%u"), InetAddress(servAddr6.sin6_addr.s6_addr).toString(ipAddrText), s_trapListenerPort);
  863    }
  864 #endif
  865 
  866    SNMP_Transport *snmp = CreateTransport(hSocket);
  867 #ifdef WITH_IPV6
  868    SNMP_Transport *snmp6 = CreateTransport(hSocket6);
  869 #endif
  870 
  871    SocketPoller sp;
  872 
  873    nxlog_debug_tag(DEBUG_TAG, 1, _T("SNMP Trap Receiver started on port %u"), s_trapListenerPort);
  874 
  875    // Wait for packets
  876    while(!IsShutdownInProgress())
  877    {
  878       sp.reset();
  879       if (hSocket != INVALID_SOCKET)
  880          sp.add(hSocket);
  881 #ifdef WITH_IPV6
  882       if (hSocket6 != INVALID_SOCKET)
  883          sp.add(hSocket6);
  884 #endif
  885 
  886       int rc = sp.poll(1000);
  887       if ((rc > 0) && !IsShutdownInProgress())
  888       {
  889          SockAddrBuffer addr;
  890          socklen_t addrLen = sizeof(SockAddrBuffer);
  891          SNMP_PDU *pdu;
  892 #ifdef WITH_IPV6
  893          SNMP_Transport *transport = sp.isSet(hSocket) ? snmp : snmp6;
  894 #else
  895          SNMP_Transport *transport = snmp;
  896 #endif
  897          int bytes = transport->readMessage(&pdu, 2000, (struct sockaddr *)&addr, &addrLen, ContextFinder);
  898          if ((bytes > 0) && (pdu != nullptr))
  899          {
  900             InetAddress sourceAddr = InetAddress::createFromSockaddr((struct sockaddr *)&addr);
  901             nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: received PDU of type %d from %s"), pdu->getCommand(), (const TCHAR *)sourceAddr.toString());
  902                if ((pdu->getCommand() == SNMP_TRAP) || (pdu->getCommand() == SNMP_INFORM_REQUEST))
  903                {
  904                    if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_INFORM_REQUEST))
  905                    {
  906                        SNMP_SecurityContext *context = transport->getSecurityContext();
  907                        context->setAuthoritativeEngine(localEngine);
  908                    }
  909                ProcessTrap(pdu, sourceAddr, 0, ntohs(SA_PORT(&addr)), transport, &localEngine, pdu->getCommand() == SNMP_INFORM_REQUEST);
  910                }
  911                else if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_GET_REQUEST) && (pdu->getAuthoritativeEngine().getIdLen() == 0))
  912                {
  913                    // Engine ID discovery
  914                    nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: EngineId discovery"));
  915 
  916                    SNMP_PDU *response = new SNMP_PDU(SNMP_REPORT, pdu->getRequestId(), pdu->getVersion());
  917                    response->setReportable(false);
  918                    response->setMessageId(pdu->getMessageId());
  919                    response->setContextEngineId(localEngine.getId(), localEngine.getIdLen());
  920 
  921                    SNMP_Variable *var = new SNMP_Variable(_T(".1.3.6.1.6.3.15.1.1.4.0"));
  922                    var->setValueFromString(ASN_INTEGER, _T("2"));
  923                    response->bindVariable(var);
  924 
  925                    SNMP_SecurityContext *context = new SNMP_SecurityContext();
  926                    localEngine.setTime((int)time(nullptr));
  927                    context->setAuthoritativeEngine(localEngine);
  928                    context->setSecurityModel(SNMP_SECURITY_MODEL_USM);
  929                    context->setAuthMethod(SNMP_AUTH_NONE);
  930                    context->setPrivMethod(SNMP_ENCRYPT_NONE);
  931                    transport->setSecurityContext(context);
  932 
  933                    transport->sendMessage(response, 0);
  934                    delete response;
  935                }
  936                else if (pdu->getCommand() == SNMP_REPORT)
  937                {
  938                    nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: REPORT PDU with error %s"), (const TCHAR *)pdu->getVariable(0)->getName().toString());
  939                }
  940             delete pdu;
  941          }
  942          else
  943          {
  944             // Sleep on error
  945             ThreadSleepMs(100);
  946          }
  947       }
  948    }
  949 
  950    delete snmp;
  951 #ifdef WITH_IPV6
  952    delete snmp6;
  953 #endif
  954    nxlog_debug_tag(DEBUG_TAG, 1, _T("SNMP Trap Receiver terminated"));
  955 }
  956 
  957 /**
  958  * Send all trap configuration records to client
  959  */
  960 void SendTrapsToClient(ClientSession *pSession, UINT32 dwRqId)
  961 {
  962    NXCPMessage msg;
  963 
  964    // Prepare message
  965    msg.setCode(CMD_TRAP_CFG_RECORD);
  966    msg.setId(dwRqId);
  967 
  968    s_trapCfgLock.lock();
  969    for(int i = 0; i < m_trapCfgList.size(); i++)
  970    {
  971       m_trapCfgList.get(i)->fillMessage(&msg);
  972       pSession->sendMessage(&msg);
  973       msg.deleteAllFields();
  974    }
  975    s_trapCfgLock.unlock();
  976 
  977    msg.setField(VID_TRAP_ID, (UINT32)0);
  978    pSession->sendMessage(&msg);
  979 }
  980 
  981 /**
  982  * Prepare single message with all trap configuration records
  983  */
  984 void CreateTrapCfgMessage(NXCPMessage *msg)
  985 {
  986    s_trapCfgLock.lock();
  987     msg->setField(VID_NUM_TRAPS, m_trapCfgList.size());
  988    for(int i = 0, id = VID_TRAP_INFO_BASE; i < m_trapCfgList.size(); i++, id += 10)
  989       m_trapCfgList.get(i)->fillMessage(msg, id);
  990    s_trapCfgLock.unlock();
  991 }
  992 
  993 static void NotifyOnTrapCfgDelete(UINT32 id)
  994 {
  995     NXCPMessage msg;
  996 
  997     msg.setCode(CMD_TRAP_CFG_UPDATE);
  998     msg.setField(VID_NOTIFICATION_CODE, (UINT32)NX_NOTIFY_TRAPCFG_DELETED);
  999     msg.setField(VID_TRAP_ID, id);
 1000     EnumerateClientSessions(NotifyOnTrapCfgChangeCB, &msg);
 1001 }
 1002 
 1003 /**
 1004  * Delete trap configuration record
 1005  */
 1006 UINT32 DeleteTrap(UINT32 id)
 1007 {
 1008    UINT32 dwResult = RCC_INVALID_TRAP_ID;
 1009 
 1010    s_trapCfgLock.lock();
 1011 
 1012    for(int i = 0; i < m_trapCfgList.size(); i++)
 1013    {
 1014       if (m_trapCfgList.get(i)->getId() == id)
 1015       {
 1016          // Remove trap entry from database
 1017          DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
 1018          DB_STATEMENT hStmtCfg = DBPrepare(hdb, _T("DELETE FROM snmp_trap_cfg WHERE trap_id=?"));
 1019          DB_STATEMENT hStmtMap = DBPrepare(hdb, _T("DELETE FROM snmp_trap_pmap WHERE trap_id=?"));
 1020 
 1021          if (hStmtCfg != nullptr && hStmtMap != nullptr)
 1022          {
 1023             DBBind(hStmtCfg, 1, DB_SQLTYPE_INTEGER, id);
 1024             DBBind(hStmtMap, 1, DB_SQLTYPE_INTEGER, id);
 1025 
 1026             if (DBBegin(hdb))
 1027             {
 1028                if (DBExecute(hStmtCfg) && DBExecute(hStmtMap))
 1029                {
 1030                   m_trapCfgList.remove(i);
 1031                   NotifyOnTrapCfgDelete(id);
 1032                   dwResult = RCC_SUCCESS;
 1033                   DBCommit(hdb);
 1034                }
 1035                else
 1036                   DBRollback(hdb);
 1037 
 1038                DBFreeStatement(hStmtCfg);
 1039                DBFreeStatement(hStmtMap);
 1040             }
 1041          }
 1042          DBConnectionPoolReleaseConnection(hdb);
 1043          break;
 1044       }
 1045    }
 1046 
 1047    s_trapCfgLock.unlock();
 1048    return dwResult;
 1049 }
 1050 
 1051 /**
 1052  * Save parameter mapping to database
 1053  */
 1054 bool SNMPTrapConfiguration::saveParameterMapping(DB_HANDLE hdb)
 1055 {
 1056    if (!ExecuteQueryOnObject(hdb, m_id, _T("DELETE FROM snmp_trap_pmap WHERE trap_id=?")))
 1057       return false;
 1058 
 1059    if (m_mappings.isEmpty())
 1060       return true;
 1061 
 1062    DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO snmp_trap_pmap (trap_id,parameter,snmp_oid,description,flags) VALUES (?,?,?,?,?)"), true);
 1063    if (hStmt == nullptr)
 1064       return false;
 1065 
 1066    DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
 1067 
 1068    bool success = true;
 1069    TCHAR oid[1024];
 1070    for(int i = 0; (i < m_mappings.size()) && success; i++)
 1071    {
 1072       const SNMPTrapParameterMapping *pm = m_mappings.get(i);
 1073       if (!pm->isPositional())
 1074          pm->getOid()->toString(oid, 1024);
 1075       else
 1076          _sntprintf(oid, 1024, _T("POS:%d"), pm->getPosition());
 1077 
 1078       DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, i + 1);
 1079       DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, oid, DB_BIND_STATIC);
 1080       DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, pm->getDescription(), DB_BIND_STATIC);
 1081       DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, pm->getFlags());
 1082 
 1083       success = DBExecute(hStmt);
 1084    }
 1085    DBFreeStatement(hStmt);
 1086    return success;
 1087 }
 1088 
 1089 /**
 1090  * Create new trap configuration record
 1091  */
 1092 UINT32 CreateNewTrap(UINT32 *pdwTrapId)
 1093 {
 1094    UINT32 rcc = RCC_DB_FAILURE;
 1095 
 1096    DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
 1097    DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO snmp_trap_cfg (guid,trap_id,snmp_oid,event_code,description,user_tag) VALUES (?,?,'',?,'','')"));
 1098    if (hStmt != nullptr)
 1099    {
 1100       SNMPTrapConfiguration *trapCfg = new SNMPTrapConfiguration();
 1101       DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, trapCfg->getGuid());
 1102       DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, trapCfg->getId());
 1103       DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, trapCfg->getEventCode());
 1104 
 1105       if (DBExecute(hStmt))
 1106       {
 1107          AddTrapCfgToList(trapCfg);
 1108          trapCfg->notifyOnTrapCfgChange(NX_NOTIFY_TRAPCFG_CREATED);
 1109          *pdwTrapId = trapCfg->getId();
 1110          rcc = RCC_SUCCESS;
 1111       }
 1112       else
 1113       {
 1114          delete trapCfg;
 1115       }
 1116 
 1117       DBFreeStatement(hStmt);
 1118    }
 1119    DBConnectionPoolReleaseConnection(hdb);
 1120    return rcc;
 1121 }
 1122 
 1123 /**
 1124  * Update trap configuration record from message
 1125  */
 1126 UINT32 UpdateTrapFromMsg(NXCPMessage *pMsg)
 1127 {
 1128    UINT32 rcc = RCC_INVALID_TRAP_ID;
 1129    TCHAR oid[1024];
 1130 
 1131    UINT32 id = pMsg->getFieldAsUInt32(VID_TRAP_ID);
 1132    DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
 1133 
 1134    for(int i = 0; i < m_trapCfgList.size(); i++)
 1135    {
 1136       if (m_trapCfgList.get(i)->getId() == id)
 1137       {
 1138          DB_STATEMENT hStmt = DBPrepare(hdb, _T("UPDATE snmp_trap_cfg SET snmp_oid=?,event_code=?,description=?,user_tag=?,transformation_script=? WHERE trap_id=?"));
 1139          if (hStmt != nullptr)
 1140          {
 1141             SNMPTrapConfiguration *trapCfg = new SNMPTrapConfiguration(pMsg);
 1142             trapCfg->getOid().toString(oid, 1024);
 1143             DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, oid, DB_BIND_STATIC);
 1144             DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, trapCfg->getEventCode());
 1145             DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, trapCfg->getDescription(), DB_BIND_STATIC);
 1146             DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, trapCfg->getEventTag(), DB_BIND_STATIC);
 1147             DBBind(hStmt, 5, DB_SQLTYPE_TEXT, trapCfg->getScriptSource(), DB_BIND_STATIC);
 1148             DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, trapCfg->getId());
 1149 
 1150             if (DBBegin(hdb))
 1151             {
 1152                if (DBExecute(hStmt) && trapCfg->saveParameterMapping(hdb))
 1153                {
 1154                   AddTrapCfgToList(trapCfg);
 1155                   trapCfg->notifyOnTrapCfgChange(NX_NOTIFY_TRAPCFG_MODIFIED);
 1156                   rcc = RCC_SUCCESS;
 1157                   DBCommit(hdb);
 1158                }
 1159                else
 1160                {
 1161                   DBRollback(hdb);
 1162                   rcc = RCC_DB_FAILURE;
 1163                }
 1164             }
 1165             else
 1166             {
 1167                rcc = RCC_DB_FAILURE;
 1168             }
 1169             DBFreeStatement(hStmt);
 1170 
 1171             if (rcc != RCC_SUCCESS)
 1172                delete trapCfg;
 1173          }
 1174 
 1175             DBConnectionPoolReleaseConnection(hdb);
 1176          break;
 1177       }
 1178    }
 1179 
 1180    return rcc;
 1181 }
 1182 
 1183 /**
 1184  * Create trap record in NXMP file
 1185  */
 1186 void CreateTrapExportRecord(StringBuffer &xml, UINT32 id)
 1187 {
 1188     TCHAR szBuffer[1024];
 1189     SNMPTrapConfiguration *trapCfg;
 1190 
 1191     s_trapCfgLock.lock();
 1192    for(int i = 0; i < m_trapCfgList.size(); i++)
 1193    {
 1194       trapCfg = m_trapCfgList.get(i);
 1195       if (trapCfg->getId() == id)
 1196       {
 1197          xml.append(_T("\t\t<trap id=\""));
 1198          xml.append(id);
 1199          xml.append(_T("\">\n\t\t\t<guid>"));
 1200          xml.append(trapCfg->getGuid());
 1201          xml.append(_T("</guid>\n\t\t\t<oid>"));
 1202          xml.append(trapCfg->getOid().toString());
 1203          xml.append(_T("</oid>\n\t\t\t<description>"));
 1204          xml.append(EscapeStringForXML2(trapCfg->getDescription()));
 1205          xml.append(_T("</description>\n\t\t\t<eventTag>"));
 1206          xml.append(EscapeStringForXML2(trapCfg->getEventTag()));
 1207          xml.append(_T("</eventTag>\n\t\t\t<event>"));
 1208          EventNameFromCode(trapCfg->getEventCode(), szBuffer);
 1209          xml.append(EscapeStringForXML2(szBuffer));
 1210          xml.append(_T("</event>\n\t\t\t<transformationScript>"));
 1211          xml.append(EscapeStringForXML2(trapCfg->getScriptSource()));
 1212          xml.append(_T("</transformationScript>\n"));
 1213             if (trapCfg->getParameterMappingCount() > 0)
 1214             {
 1215             xml.append(_T("\t\t\t<parameters>\n"));
 1216                 for(int j = 0; j < trapCfg->getParameterMappingCount(); j++)
 1217                 {
 1218                    const SNMPTrapParameterMapping *pm = trapCfg->getParameterMapping(j);
 1219                     xml.appendFormattedString(_T("\t\t\t\t<parameter id=\"%d\">\n")
 1220                                          _T("\t\t\t\t\t<flags>%d</flags>\n")
 1221                                            _T("\t\t\t\t\t<description>%s</description>\n"),
 1222                                                   j + 1, pm->getFlags(),
 1223                                                   (const TCHAR *)EscapeStringForXML2(pm->getDescription()));
 1224                if (!pm->isPositional())
 1225                     {
 1226                         xml.appendFormattedString(_T("\t\t\t\t\t<oid>%s</oid>\n"), pm->getOid()->toString(szBuffer, 1024));
 1227                     }
 1228                     else
 1229                     {
 1230                         xml.appendFormattedString(_T("\t\t\t\t\t<position>%d</position>\n"), pm->getPosition());
 1231                     }
 1232                xml.append(_T("\t\t\t\t</parameter>\n"));
 1233                 }
 1234             xml.append(_T("\t\t\t</parameters>\n"));
 1235             }
 1236          xml.append(_T("\t\t</trap>\n"));
 1237             break;
 1238         }
 1239     }
 1240    s_trapCfgLock.unlock();
 1241 }
 1242 
 1243 /**
 1244  * Find if trap with guid already exists
 1245  */
 1246 UINT32 ResolveTrapGuid(const uuid& guid)
 1247 {
 1248    UINT32 id = 0;
 1249 
 1250    DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
 1251 
 1252    DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT trap_id FROM snmp_trap_cfg WHERE guid=?"));
 1253    if (hStmt != nullptr)
 1254    {
 1255       DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, guid);
 1256       DB_RESULT hResult = DBSelectPrepared(hStmt);
 1257       if (hResult != nullptr)
 1258       {
 1259          if (DBGetNumRows(hResult) > 0)
 1260             id = DBGetFieldULong(hResult, 0, 0);
 1261          DBFreeResult(hResult);
 1262       }
 1263       DBFreeStatement(hStmt);
 1264    }
 1265 
 1266    DBConnectionPoolReleaseConnection(hdb);
 1267    return id;
 1268 }
 1269 
 1270 /**
 1271  * Add SNMP trap configuration to local list
 1272  */
 1273 void AddTrapCfgToList(SNMPTrapConfiguration *trapCfg)
 1274 {
 1275    s_trapCfgLock.lock();
 1276 
 1277    for(int i = 0; i < m_trapCfgList.size(); i++)
 1278    {
 1279       if (m_trapCfgList.get(i)->getId() == trapCfg->getId())
 1280       {
 1281          m_trapCfgList.remove(i);
 1282       }
 1283    }
 1284    m_trapCfgList.add(trapCfg);
 1285 
 1286    s_trapCfgLock.unlock();
 1287 }