implemented SNMP target sync with agent for cached DCIs; GUID functions refactoring...
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 31 May 2015 15:05:47 +0000 (18:05 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 31 May 2015 15:05:47 +0000 (18:05 +0300)
46 files changed:
include/nms_cscp.h
include/nms_util.h
include/nxdbapi.h
include/nxsnmp.h
include/uuid.h
src/agent/core/Makefile.am
src/agent/core/datacoll.cpp
src/agent/core/dcsnmp.cpp [new file with mode: 0644]
src/agent/core/nxagentd.h
src/agent/core/nxagentd.vcproj
src/db/libnxdb/session.cpp
src/libnetxms/Makefile.am
src/libnetxms/hashmapbase.cpp [new file with mode: 0644]
src/libnetxms/libnetxms.vcproj
src/libnetxms/log.cpp
src/libnetxms/unicode.cpp
src/libnetxms/uuid.c [deleted file]
src/libnetxms/uuid.cpp [moved from src/libnetxms/gen_uuid.c with 58% similarity]
src/libnetxms/uuidP.h [deleted file]
src/server/core/bridge.cpp
src/server/core/cdp.cpp
src/server/core/fdb.cpp
src/server/core/lldp.cpp
src/server/core/main.cpp
src/server/core/ndp.cpp
src/server/core/node.cpp
src/server/core/nxslext.cpp
src/server/core/objtools.cpp
src/server/core/stp.cpp
src/server/core/tools.cpp
src/server/drivers/airespace/airespace.cpp
src/server/drivers/at/at.cpp
src/server/drivers/mikrotik/mikrotik.cpp
src/server/drivers/ntws/ntws.cpp
src/server/drivers/ping3/ping3.cpp
src/server/drivers/ubnt/ubnt.cpp
src/server/include/nms_core.h
src/server/include/nms_objects.h
src/server/include/nxsrvapi.h
src/server/libnxsrv/Makefile.am
src/server/libnxsrv/libnxsrv.vcproj
src/server/libnxsrv/main.cpp
src/server/libnxsrv/ndd.cpp
src/snmp/libnxsnmp/Makefile.am
src/snmp/libnxsnmp/libnxsnmp.vcproj
src/snmp/libnxsnmp/util.cpp [moved from src/server/libnxsrv/snmp.cpp with 79% similarity]

index af0e25f..703e0a3 100644 (file)
@@ -1063,6 +1063,9 @@ typedef struct
 #define VID_ELEMENT_LIST_BASE       ((UINT32)0x10000000)
 #define VID_LINK_LIST_BASE          ((UINT32)0x40000000)
 
+// Node info list base
+#define VID_NODE_INFO_LIST_BASE     ((UINT32)0x60000000)
+
 // Variable ranges for object's ACL
 #define VID_ACL_USER_BASE           ((UINT32)0x00001000)
 #define VID_ACL_USER_LAST           ((UINT32)0x00001FFF)
index 5f88860..56b3a08 100644 (file)
@@ -639,6 +639,64 @@ public:
 };
 
 /**
+ * Opaque hash map entry structure
+ */
+struct HashMapEntry;
+
+/**
+ * Hash map base class (for fixed size non-pointer keys)
+ */
+class LIBNETXMS_EXPORTABLE HashMapBase
+{
+private:
+   HashMapEntry *m_data;
+       bool m_objectOwner;
+   unsigned int m_keylen;
+
+       HashMapEntry *find(const void *key);
+       void destroyObject(void *object) { if (object != NULL) m_objectDestructor(object); }
+
+protected:
+       void (*m_objectDestructor)(void *);
+
+       HashMapBase(bool objectOwner, unsigned int keylen);
+
+       void *_get(const void *key);
+       void _set(const void *key, void *value);
+       void _remove(const void *key);
+
+   bool _contains(const void *key) { return find(key) != NULL; }
+
+public:
+   virtual ~HashMapBase();
+
+   void setOwner(bool owner) { m_objectOwner = owner; }
+       void clear();
+
+       int size();
+
+   bool forEach(bool (*cb)(const void *, const void *, void *), void *userData);
+   const void *findElement(bool (*comparator)(const void *, const void *, void *), void *userData);
+};
+
+/**
+ * Hash map template for holding objects as values
+ */
+template <class K, class V> class HashMap : public HashMapBase
+{
+private:
+       static void destructor(void *object) { delete (V*)object; }
+
+public:
+       HashMap(bool objectOwner = false) : HashMapBase(objectOwner, sizeof(K)) { m_objectDestructor = destructor; }
+
+       V *get(const K& key) { return (V*)_get(&key); }
+       void set(const K& key, V *value) { _set(&key, (void *)value); }
+   void remove(const K& key) { _remove(&key); }
+   bool contains(const K& key) { return _contains(&key); }
+};
+
+/**
  * Byte stream
  */
 class LIBNETXMS_EXPORTABLE ByteStream
index b256e69..9051584 100644 (file)
@@ -212,4 +212,7 @@ void LIBNXDB_EXPORTABLE DBSetLongRunningThreshold(UINT32 threshold);
 void LIBNXDB_EXPORTABLE DBSetDebugPrintCallback(void (*cb)(int, const TCHAR *, va_list));
 ObjectArray<PoolConnectionInfo> LIBNXDB_EXPORTABLE *DBConnectionPoolGetConnectionList();
 
+bool LIBNXDB_EXPORTABLE IsDatabaseRecordExist(DB_HANDLE hdb, const TCHAR *table, const TCHAR *idColumn, UINT32 id);
+bool LIBNXDB_EXPORTABLE IsDatabaseRecordExist(DB_HANDLE hdb, const TCHAR *table, const TCHAR *idColumn, const uuid_t id);
+
 #endif   /* _nxsrvapi_h_ */
index ac31995..7341ce2 100644 (file)
 #define MIB_TYPE_OBJGROUP              33
 #define MIB_TYPE_NOTIFGROUP            34
 
-
-//
-// Flags for SNMPSaveMIBTree
-//
-
+/**
+ * Flags for SNMPSaveMIBTree
+ */
 #define SMT_COMPRESS_DATA        0x01
 #define SMT_SKIP_DESCRIPTIONS    0x02
 
+/**
+ * Flags for SnmpGet
+ */
+#define SG_VERBOSE        0x0001
+#define SG_STRING_RESULT  0x0002
+#define SG_RAW_RESULT     0x0004
+#define SG_HSTRING_RESULT 0x0008
+#define SG_PSTRING_RESULT 0x0010
 
 #endif      /* NXSNMP_WITH_NET_SNMP */
 
@@ -699,6 +705,20 @@ UINT32 LIBNXSNMP_EXPORTABLE SNMPGetMIBTreeTimestamp(const TCHAR *fileName, UINT3
 UINT32 LIBNXSNMP_EXPORTABLE SNMPResolveDataType(const TCHAR *pszType);
 TCHAR LIBNXSNMP_EXPORTABLE *SNMPDataTypeName(UINT32 type, TCHAR *buffer, size_t bufferSize);
 
+UINT32 LIBNXSNMP_EXPORTABLE SnmpNewRequestId();
+void LIBNXSNMP_EXPORTABLE SnmpSetMessageIds(DWORD msgParseError, DWORD msgTypeError, DWORD msgGetError);
+void LIBNXSNMP_EXPORTABLE SnmpSetDefaultTimeout(UINT32 timeout);
+UINT32 LIBNXSNMP_EXPORTABLE SnmpGetDefaultTimeout();
+UINT32 LIBNXSNMP_EXPORTABLE SnmpGet(int version, SNMP_Transport *transport,
+                                    const TCHAR *szOidStr, const UINT32 *oidBinary, size_t oidLen, void *pValue,
+                                    size_t bufferSize, UINT32 dwFlags);
+UINT32 LIBNXSNMP_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
+                                      const TCHAR *szOidStr, const UINT32 *oidBinary, size_t oidLen, void *pValue,
+                                      size_t bufferSize, UINT32 dwFlags, UINT32 *dataLen);
+UINT32 LIBNXSNMP_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport, const TCHAR *szRootOid,
+                                                                  UINT32 (* pHandler)(UINT32, SNMP_Variable *, SNMP_Transport *, void *),
+                                     void *pUserArg, BOOL bVerbose);
+
 #endif   /* __cplusplus */
 
 /** @} */
index 7b54ef6..576ad00 100644 (file)
@@ -25,19 +25,11 @@ typedef unsigned char uuid_t[16];
 #define UUID_VARIANT_MICROSOFT   2
 #define UUID_VARIANT_OTHER       3
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void LIBNETXMS_EXPORTABLE uuid_clear(uuid_t uu);
-int LIBNETXMS_EXPORTABLE uuid_compare(uuid_t uu1, uuid_t uu2);
+int LIBNETXMS_EXPORTABLE uuid_compare(const uuid_t uu1, const uuid_t uu2);
 void LIBNETXMS_EXPORTABLE uuid_generate(uuid_t out);
-int LIBNETXMS_EXPORTABLE uuid_is_null(uuid_t uu);
+int LIBNETXMS_EXPORTABLE uuid_is_null(const uuid_t uu);
 int LIBNETXMS_EXPORTABLE uuid_parse(const TCHAR *in, uuid_t uu);
-TCHAR LIBNETXMS_EXPORTABLE *uuid_to_string(uuid_t uu, TCHAR *out);
-
-#ifdef __cplusplus
-}
-#endif
+TCHAR LIBNETXMS_EXPORTABLE *uuid_to_string(const uuid_t uu, TCHAR *out);
 
 #endif
index 0357304..82772a8 100644 (file)
@@ -1,10 +1,10 @@
 AM_CPPFLAGS=-I@top_srcdir@/include
 bin_PROGRAMS = nxagentd
 nxagentd_SOURCES = messages.c actions.cpp appagent.cpp comm.cpp config.cpp \
-                   ctrl.cpp datacoll.cpp epp.cpp exec.cpp extagent.cpp \
-                   getparam.cpp localdb.cpp master.cpp nxagentd.cpp \
-                   policy.cpp push.cpp register.cpp sa.cpp sd.cpp \
-                   session.cpp snmpproxy.cpp snmptrapproxy.cpp \
+                   ctrl.cpp datacoll.cpp dcsnmp.cpp epp.cpp exec.cpp \
+                   extagent.cpp getparam.cpp localdb.cpp master.cpp \
+                   nxagentd.cpp policy.cpp push.cpp register.cpp sa.cpp \
+                   sd.cpp session.cpp snmpproxy.cpp snmptrapproxy.cpp \
                    static_subagents.cpp subagent.cpp sysinfo.cpp tools.cpp \
                    trap.cpp upgrade.cpp watchdog.cpp
 if USE_INTERNAL_EXPAT
index 303c4f7..317a860 100644 (file)
 #include "nxagentd.h"
 
 /**
+ * Externals
+ */
+void UpdateSnmpTarget(SNMPTarget *target);
+bool GetSnmpValue(const uuid_t& target, UINT16 port, const TCHAR *oid, TCHAR *value, int interpretRawValue);
+
+/**
  * Database schema version
  */
 #define DATACOLL_SCHEMA_VERSION     3
@@ -40,6 +46,7 @@ private:
    BYTE m_type;
    BYTE m_origin;
    UINT16 m_snmpPort;
+   BYTE m_snmpRawValueType;
        uuid_t m_snmpTargetGuid;
    time_t m_lastPollTime;
 
@@ -49,18 +56,23 @@ public:
    DataCollectionItem(const DataCollectionItem *item);
    virtual ~DataCollectionItem();
 
-   UINT32 getId() { return m_id; }
-   UINT64 getServerId() { return m_serverId; }
-   const TCHAR *getName() { return m_name; }
-   int getType() { return (int)m_type; }
-   int getOrigin() { return (int)m_origin; }
-   bool equals(const DataCollectionItem *item);
+   UINT32 getId() const { return m_id; }
+   UINT64 getServerId() const { return m_serverId; }
+   const TCHAR *getName() const { return m_name; }
+   int getType() const { return (int)m_type; }
+   int getOrigin() const { return (int)m_origin; }
+   const uuid_t& getSnmpTargetGuid() const { return m_snmpTargetGuid; }
+   UINT16 getSnmpPort() const { return m_snmpPort; }
+   int getSnmpRawValueType() const { return (int)m_snmpRawValueType; }
+
+   bool equals(const DataCollectionItem *item) const { return (m_serverId == item->m_serverId) && (m_id == item->m_id); }
+
    void updateAndSave(const DataCollectionItem *item);
    void saveToDatabase(bool newObject);
    void deleteFromDatabase();
    void setLastPollTime(time_t time);
 
-   UINT32 getTimeToNextPoll(time_t now)
+   UINT32 getTimeToNextPoll(time_t now) const
    {
       time_t diff = now - m_lastPollTime;
       return (diff >= m_pollingInterval) ? 0 : m_pollingInterval - (UINT32)diff;
@@ -81,10 +93,11 @@ DataCollectionItem::DataCollectionItem(UINT64 serverId, NXCPMessage *msg, UINT32
    m_lastPollTime = msg->getFieldAsTime(baseId + 5);
    msg->getFieldAsBinary(baseId + 6, m_snmpTargetGuid, UUID_LENGTH);
    m_snmpPort = msg->getFieldAsUInt16(baseId + 7);
+   m_snmpRawValueType = (BYTE)msg->getFieldAsUInt16(baseId + 8);
 }
 
 /**
- * Data is selected in this order: server_id,dci_id,type,origin,name,polling_interval,last_poll,snmp_port,snmp_target_guid
+ * Data is selected in this order: server_id,dci_id,type,origin,name,polling_interval,last_poll,snmp_port,snmp_target_guid,snmp_raw_type
  */
 DataCollectionItem::DataCollectionItem(DB_RESULT hResult, int row)
 {
@@ -98,6 +111,7 @@ DataCollectionItem::DataCollectionItem(DB_RESULT hResult, int row)
    m_lastPollTime = (time_t)DBGetFieldULong(hResult, row, 6);
    DBGetFieldGUID(hResult, row, 7, m_snmpTargetGuid);
    m_snmpPort = DBGetFieldULong(hResult, row, 8);
+   m_snmpRawValueType = (BYTE)DBGetFieldULong(hResult, row, 9);
 }
 
 /**
@@ -114,6 +128,7 @@ DataCollectionItem::DataCollectionItem(DB_RESULT hResult, int row)
    m_lastPollTime = item->m_lastPollTime;
    memcpy(m_snmpTargetGuid, item->m_snmpTargetGuid, UUID_LENGTH);
    m_snmpPort = item->m_snmpPort;
+   m_snmpRawValueType = item->m_snmpRawValueType;
  }
 
 /**
@@ -124,13 +139,6 @@ DataCollectionItem::~DataCollectionItem()
    safe_free(m_name);
 }
 
-bool DataCollectionItem::equals(const DataCollectionItem *item)
-{
-   if(m_serverId == item->m_serverId && m_id == item->m_id)
-      return true;
-   return false;
-}
-
 /**
  * Will check if object has changed. If at least one field is changed - all data will be updated and
  * saved to database.
@@ -138,9 +146,9 @@ bool DataCollectionItem::equals(const DataCollectionItem *item)
 void DataCollectionItem::updateAndSave(const DataCollectionItem *item)
 {
    //if at leas one of fields changed - set all fields and save to DB
-   if(m_type != item->m_type || m_origin != item->m_origin || _tcscmp(m_name, item->m_name) != 0 ||
-      m_pollingInterval != item->m_pollingInterval || uuid_compare(m_snmpTargetGuid, (unsigned char*)item->m_snmpTargetGuid)!= 0 ||
-      m_snmpPort != item->m_snmpPort)
+   if ((m_type != item->m_type) || (m_origin != item->m_origin) || _tcscmp(m_name, item->m_name) ||
+       (m_pollingInterval != item->m_pollingInterval) || uuid_compare(m_snmpTargetGuid, item->m_snmpTargetGuid) ||
+       (m_snmpPort != item->m_snmpPort) || (m_snmpRawValueType != item->m_snmpRawValueType))
    {
       m_type = item->m_type;
       m_origin = item->m_origin;
@@ -149,11 +157,14 @@ void DataCollectionItem::updateAndSave(const DataCollectionItem *item)
       m_lastPollTime = item->m_lastPollTime;
       memcpy(m_snmpTargetGuid, item->m_snmpTargetGuid, UUID_LENGTH);
       m_snmpPort = item->m_snmpPort;
+      m_snmpRawValueType = item->m_snmpRawValueType;
       saveToDatabase(false);
    }
-
 }
 
+/**
+ * Save configuration object to database
+ */
 void DataCollectionItem::saveToDatabase(bool newObject)
 {
    DebugPrintf(INVALID_INDEX, 6, _T("DataCollectionItem::saveToDatabase: %s object(serverId=%ld,dciId=%d) saved to database"),
@@ -161,27 +172,23 @@ void DataCollectionItem::saveToDatabase(bool newObject)
    DB_HANDLE db = GetLocalDatabaseHandle();
    DB_STATEMENT hStmt;
 
-   if(newObject)
+   if (newObject)
    {
                hStmt = DBPrepare(db,
                     _T("INSERT INTO dc_config (type,origin,name,polling_interval,")
-                    _T("last_poll,snmp_port,snmp_target_guid,server_id,dci_id)")
-                    _T("VALUES (?,?,?,?,?,?,?,?,?)"));
+                    _T("last_poll,snmp_port,snmp_target_guid,snmp_raw_type,server_id,dci_id)")
+                    _T("VALUES (?,?,?,?,?,?,?,?,?,?)"));
    }
    else
    {
       hStmt = DBPrepare(db,
                     _T("UPDATE dc_config SET type=?,origin=?,name=?,")
                     _T("polling_interval=?,last_poll=?,snmp_port=?,")
-                    _T("snmp_target_guid=? WHERE server_id=? AND dci_id=?"));
+                    _T("snmp_target_guid=?,snmp_raw_type=? WHERE server_id=? AND dci_id=?"));
    }
 
        if (hStmt == NULL)
-       {
-          DebugPrintf(INVALID_INDEX, 2, _T("DataCollectionItem::saveToDatabase: not possible to prepare save quary for %s object(serverId=%ld,dciId=%d)"),
-                  newObject ? _T("new") : _T("existing"), m_serverId, m_id);
                return;
-   }
 
    TCHAR buffer[64];
        DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (LONG)m_type);
@@ -191,14 +198,12 @@ void DataCollectionItem::saveToDatabase(bool newObject)
        DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_lastPollTime);
        DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (LONG)m_snmpPort);
    DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, uuid_to_string(m_snmpTargetGuid, buffer), DB_BIND_STATIC);
-       DBBind(hStmt, 8, DB_SQLTYPE_BIGINT, m_serverId);
-       DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_id);
+       DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_snmpRawValueType);
+       DBBind(hStmt, 9, DB_SQLTYPE_BIGINT, m_serverId);
+       DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, (LONG)m_id);
 
-   if(!DBExecute(hStmt))
-   {
-      DebugPrintf(INVALID_INDEX, 2, _T("DataCollectionItem::saveToDatabase: not possible to save %s object(serverId=%ld,dciId=%d) to database"),
-                  newObject ? _T("new") : _T("existing"), m_serverId, m_id);
-   }
+   DBExecute(hStmt);
+   DBFreeStatement(hStmt);
 }
 
 /**
@@ -299,18 +304,22 @@ public:
 
    time_t getTimestamp() { return m_timestamp; }
    UINT64 getServerId() { return m_serverId; }
+   
    void saveToDatabase();
    bool sendToServer();
 };
 
 /**
- *
+ * Save data element to database
  */
 void DataElement::saveToDatabase()
 {
    /* TODO: implement */
 }
 
+/**
+ * Send collected data to server
+ */
 bool DataElement::sendToServer()
 {
    /* TODO: implement */
@@ -318,56 +327,58 @@ bool DataElement::sendToServer()
 }
 
 /**
- * Information about
+ * Server data sync status object
  */
-class ServerQueueInfo
+struct ServerSyncStatus
 {
-private:
-   UINT64 m_serverId;
-   bool m_saveToDatabase;
+   INT32 queueSize;
 
-public:
-   ServerQueueInfo(UINT64 serverId){ m_serverId = serverId; m_saveToDatabase = false; }
-   bool equals(const UINT64 serverId) {return serverId == m_serverId; }
-   bool saveToDatabase() { return m_saveToDatabase; }
-   void setSaveToDatabase(bool saveToDB) { m_saveToDatabase = saveToDB; }
+   ServerSyncStatus()
+   {
+      queueSize = 0;
+   }
 };
 
 /**
- * Server queue information, mutex lock for info, resend que reference
+ * Server sync status information
  */
-static ObjectArray<ServerQueueInfo> s_serversInfo(5, 5, false);
-static MUTEX s_serverInfoLock = INVALID_MUTEX_HANDLE;
-static THREAD s_dataReconnectThread = INVALID_THREAD_HANDLE;
-
-/**
- * Data sender queue
- */
-static Queue s_dataSenderQueue;
+static HashMap<UINT64, ServerSyncStatus> s_serverSyncStatus(true);
+static MUTEX s_serverSyncStatusLock = INVALID_MUTEX_HANDLE;
 
 /**
- * This method will find info about session or create new object and add it to structure.
- * s_serverInfoLock should be locked before this function execution.
+ * Data reconcillation thread
  */
-static ServerQueueInfo *FindServerInfo(UINT64 serverId)
+static THREAD_RESULT THREAD_CALL ReconcillationThread(void *arg)
 {
-   ServerQueueInfo *info = NULL;
-   for(int i=0; i < s_serversInfo.size(); i++)
+   DB_HANDLE hdb = GetLocalDatabaseHandle();
+   UINT32 sleepTime = 60000;
+   DebugPrintf(INVALID_INDEX, 1, _T("Data reconcillation thread started"));
+   
+   while(!AgentSleepAndCheckForShutdown(sleepTime))
    {
-      if(s_serversInfo.get(i)->equals(serverId))
+      DB_RESULT hResult = DBSelect(hdb, _T("SELECT server_id,dci_id,dci_type,timestamp,value FROM dc_queue ORDER BY timestamp DESC LIMIT 100"));
+      if (hResult == NULL)
+         continue;
+
+      int count = DBGetNumRows(hResult);
+      for(int i = 0; i < count; i++)
       {
-         info = s_serversInfo.get(i);
       }
+      DBFreeResult(hResult);
+
+      sleepTime = (count == 100) ? 1000 : 60000;
    }
-   if(info == NULL)
-   {
-      info = new ServerQueueInfo(serverId);
-      s_serversInfo.add(info);
-   }
-   return info;
+   
+   DebugPrintf(INVALID_INDEX, 1, _T("Data reconcillation thread stopped"));
+   return THREAD_OK;
 }
 
 /**
+ * Data sender queue
+ */
+static Queue s_dataSenderQueue;
+
+/**
  * Data sender
  */
 static THREAD_RESULT THREAD_CALL DataSender(void *arg)
@@ -379,22 +390,27 @@ static THREAD_RESULT THREAD_CALL DataSender(void *arg)
       if (e == INVALID_POINTER_VALUE)
          break;
 
-      MutexLock(s_serverInfoLock);
-      ServerQueueInfo *info = FindServerInfo(e->getServerId());
-      if(!info->saveToDatabase())
+      MutexLock(s_serverSyncStatusLock);
+      ServerSyncStatus *status = s_serverSyncStatus.get(e->getServerId());
+      if (status == NULL)
       {
-         if(!e->sendToServer())
+         status = new ServerSyncStatus();
+         s_serverSyncStatus.set(e->getServerId(), status);
+      }
+
+      if (status->queueSize == 0)
+      {
+         if (!e->sendToServer())
          {
             e->saveToDatabase();
-            info->setSaveToDatabase(true);
-            /* TODO: start thread that will check if connection is restored */
+            status->queueSize++;
          }
       }
       else
       {
          e->saveToDatabase();
       }
-      MutexUnlock(s_serverInfoLock);
+      MutexUnlock(s_serverSyncStatusLock);
 
       delete e;
    }
@@ -430,7 +446,7 @@ public:
 /**
  * Collect data from agent
  */
-DataElement *CollectDataFromAgent(DataCollectionItem *dci)
+static DataElement *CollectDataFromAgent(DataCollectionItem *dci)
 {
    VirtualSession session(dci->getServerId());
 
@@ -460,10 +476,16 @@ DataElement *CollectDataFromAgent(DataCollectionItem *dci)
 /**
  * Collect data from SNMP
  */
-DataElement *CollectDataFromSNMP(DataCollectionItem *dci)
+static DataElement *CollectDataFromSNMP(DataCollectionItem *dci)
 {
-   /* TODO: implement SNMP data collection */
-   return NULL;
+   DataElement *e = NULL;
+   if (dci->getType() == DCO_TYPE_ITEM)
+   {
+      TCHAR value[MAX_RESULT_LENGTH];
+      if (GetSnmpValue(dci->getSnmpTargetGuid(), dci->getSnmpPort(), dci->getName(), value, dci->getSnmpRawValueType()))
+         e = new DataElement(dci, value);
+   }
+   return e;
 }
 
 /**
@@ -546,10 +568,20 @@ static THREAD_RESULT THREAD_CALL DataCollector(void *arg)
  */
 void ConfigureDataCollection(UINT64 serverId, NXCPMessage *msg)
 {
+   int count = msg->getFieldAsInt32(VID_NUM_NODES);
+   UINT32 fieldId = VID_NODE_INFO_LIST_BASE;
+   for(int i = 0; i < count; i++)
+   {
+      SNMPTarget *target = new SNMPTarget(serverId, msg, fieldId);
+      UpdateSnmpTarget(target);
+      fieldId += 50;
+   }
+   DebugPrintf(INVALID_INDEX, 4, _T("%d SNMP targets received from server ") UINT64X_FMT(_T("016")), count, serverId);
+
    ObjectArray<DataCollectionItem> config(32, 32, true);
 
-   int count = msg->getFieldAsInt32(VID_NUM_ELEMENTS);
-   UINT32 fieldId = VID_ELEMENT_LIST_BASE;
+   count = msg->getFieldAsInt32(VID_NUM_ELEMENTS);
+   fieldId = VID_ELEMENT_LIST_BASE;
    for(int i = 0; i < count; i++)
    {
       config.add(new DataCollectionItem(serverId, msg, fieldId));
@@ -558,7 +590,8 @@ void ConfigureDataCollection(UINT64 serverId, NXCPMessage *msg)
    DebugPrintf(INVALID_INDEX, 4, _T("%d data collection elements received from server ") UINT64X_FMT(_T("016")), count, serverId);
 
    MutexLock(s_itemLock);
-   //Update and add new
+   
+   // Update and add new
    for(int j = 0; j < config.size(); j++)
    {
       DataCollectionItem *item = config.get(j);
@@ -571,14 +604,15 @@ void ConfigureDataCollection(UINT64 serverId, NXCPMessage *msg)
             exist = true;
          }
       }
-      if(!exist)
+      if (!exist)
       {
          DataCollectionItem *newItem = new DataCollectionItem(item);
          s_items.add(newItem);
          newItem->saveToDatabase(true);
       }
    }
-   //Remove not existing configuration and data for it
+   
+   // Remove not existing configuration and data for it
    for(int i = 0; i < s_items.size(); i++)
    {
       DataCollectionItem *item = s_items.get(i);
@@ -605,20 +639,13 @@ void ConfigureDataCollection(UINT64 serverId, NXCPMessage *msg)
 }
 
 /**
- * Data collector and sender thread handles
- */
-static THREAD s_dataCollectorThread = INVALID_THREAD_HANDLE;
-static THREAD s_dataSenderThread = INVALID_THREAD_HANDLE;
-
-/**
  * Loads configuration to for DCI
  */
 static void LoadConfiguration()
 {
    DB_HANDLE db = GetLocalDatabaseHandle();
-   const TCHAR *query = _T("SELECT server_id,dci_id,type,origin,name,polling_interval,last_poll,snmp_port,snmp_target_guid FROM dc_config");
-   DB_RESULT hResult = DBSelect(db, query);
-   if(hResult != NULL)
+   DB_RESULT hResult = DBSelect(db, _T("SELECT server_id,dci_id,type,origin,name,polling_interval,last_poll,snmp_port,snmp_target_guid,snmp_raw_type FROM dc_config"));
+   if (hResult != NULL)
    {
       for(int i = 0; i < DBGetNumRows(hResult); i++)
       {
@@ -636,6 +663,7 @@ static const TCHAR *s_upgradeQueries[] =
    _T("CREATE TABLE dc_queue (")
    _T("  server_id number(20) not null,")
    _T("  dci_id integer not null,")
+   _T("  dci_type integer not null,")
    _T("  timestamp integer not null,")
    _T("  value varchar not null,")
    _T("  PRIMARY KEY(server_id,dci_id,timestamp))"),
@@ -650,33 +678,42 @@ static const TCHAR *s_upgradeQueries[] =
    _T("  last_poll integer not null,")
    _T("  snmp_port integer not null,")
    _T("  snmp_target_guid varchar(36) not null,")
+   _T("  snmp_raw_type integer not null,")
    _T("  PRIMARY KEY(server_id,dci_id))"),
 
    _T("CREATE TABLE dc_snmp_targets (")
    _T("  guid varchar(36) not null,")
-   _T("  version integer not null,")
+   _T("  server_id number(20) not null,")
    _T("  ip_address varchar(48) not null,")
+   _T("  snmp_version integer not null,")
    _T("  port integer not null,")
    _T("  auth_type integer not null,")
    _T("  enc_type integer not null,")
-   _T("  auth_pass varchar(255),")
-   _T("  enc_pass varchar(255),")
-   _T("  username varchar(255),")
+   _T("  auth_name varchar(63),")
+   _T("  auth_pass varchar(63),")
+   _T("  enc_pass varchar(63),")
    _T("  PRIMARY KEY(guid))")
 };
 
 /**
+ * Data collector and sender thread handles
+ */
+static THREAD s_dataCollectorThread = INVALID_THREAD_HANDLE;
+static THREAD s_dataSenderThread = INVALID_THREAD_HANDLE;
+static THREAD s_reconcillationThread = INVALID_THREAD_HANDLE;
+
+/**
  * Initialize and start local data collector
  */
 void StartLocalDataCollector()
 {
-   /* TODO: database init and configuration load */
    DB_HANDLE db = GetLocalDatabaseHandle();
    if (db == NULL)
    {
       DebugPrintf(INVALID_INDEX, 5, _T("StartLocalDataCollector: local database unavailable"));
       return;
    }
+
    INT32 dbVersion = ReadMetadataAsInt(_T("DataCollectionSchemaVersion"));
    while(dbVersion < DATACOLL_SCHEMA_VERSION)
    {
@@ -693,9 +730,10 @@ void StartLocalDataCollector()
    /* TODO: add reading form database snmp_targets table */
 
    s_itemLock = MutexCreate();
-   s_serverInfoLock = MutexCreate();
+   s_serverSyncStatusLock = MutexCreate();
    s_dataCollectorThread = ThreadCreateEx(DataCollector, 0, NULL);
    s_dataSenderThread = ThreadCreateEx(DataSender, 0, NULL);
+   s_reconcillationThread = ThreadCreateEx(ReconcillationThread, 0, NULL);
 }
 
 /**
@@ -710,13 +748,9 @@ void ShutdownLocalDataCollector()
    s_dataSenderQueue.Put(INVALID_POINTER_VALUE);
    ThreadJoin(s_dataSenderThread);
 
-
-   if(s_dataReconnectThread != INVALID_THREAD_HANDLE)
-   {
-      DebugPrintf(INVALID_INDEX, 5, _T("Waiting for data sender resumption thread termination"));
-      ThreadJoin(s_dataReconnectThread);
-   }
+   DebugPrintf(INVALID_INDEX, 5, _T("Waiting for data reconcillation thread termination"));
+   ThreadJoin(s_reconcillationThread);
 
    MutexDestroy(s_itemLock);
-   MutexDestroy(s_serverInfoLock);
+   MutexDestroy(s_serverSyncStatusLock);
 }
diff --git a/src/agent/core/dcsnmp.cpp b/src/agent/core/dcsnmp.cpp
new file mode 100644 (file)
index 0000000..d6a905e
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+** NetXMS multiplatform core agent
+** Copyright (C) 2003-2015 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: dcsnmp.cpp
+**
+**/
+
+#include "nxagentd.h"
+
+/**
+ * SNMP targets
+ */
+static HashMap<uuid_t, SNMPTarget> s_snmpTargets(true);
+static MUTEX s_snmpTargetsLock = MutexCreate();
+
+/**
+ * Create SNMP target from NXCP message
+ */
+SNMPTarget::SNMPTarget(UINT64 serverId, NXCPMessage *msg, UINT32 baseId)
+{
+   msg->getFieldAsBinary(baseId, m_guid, UUID_LENGTH);
+   m_serverId = serverId;
+   m_ipAddress = msg->getFieldAsInetAddress(baseId + 1);
+   m_snmpVersion = (BYTE)msg->getFieldAsInt16(baseId + 2);
+   m_port = msg->getFieldAsUInt16(baseId + 3);
+   m_authType = (BYTE)msg->getFieldAsInt16(baseId + 4);
+   m_encType = (BYTE)msg->getFieldAsInt16(baseId + 5);
+   m_authName = msg->getFieldAsUtf8String(baseId + 6);
+   m_authPassword = msg->getFieldAsUtf8String(baseId + 7);
+   m_encPassword = msg->getFieldAsUtf8String(baseId + 8);
+   m_transport = NULL;
+}
+
+/**
+ * Create SNMP target from database record
+ * Expected field order:
+ *   guid,server_id,ip_address,snmp_version,port,auth_type,enc_type,auth_name,auth_pass,enc_pass
+ */
+SNMPTarget::SNMPTarget(DB_RESULT hResult, int row)
+{
+   DBGetFieldGUID(hResult, row, 0, m_guid);
+   m_serverId = DBGetFieldUInt64(hResult, row, 1);
+   m_ipAddress = DBGetFieldInetAddr(hResult, row, 2);
+   m_snmpVersion = (BYTE)DBGetFieldLong(hResult, row, 3);
+   m_port = (UINT16)DBGetFieldLong(hResult, row, 4);
+   m_authType = (BYTE)DBGetFieldLong(hResult, row, 5);
+   m_encType = (BYTE)DBGetFieldLong(hResult, row, 6);
+   m_authName = DBGetFieldUTF8(hResult, row, 7, NULL, 0);
+   m_authPassword = DBGetFieldUTF8(hResult, row, 8, NULL, 0);
+   m_encPassword = DBGetFieldUTF8(hResult, row, 9, NULL, 0);
+   m_transport = NULL;
+}
+
+/**
+ * SNMP target destructor
+ */
+SNMPTarget::~SNMPTarget()
+{
+   safe_free(m_authName);
+   safe_free(m_authPassword);
+   safe_free(m_encPassword);
+   delete m_transport;
+}
+
+/**
+ * Save SNMP target object to database
+ */
+bool SNMPTarget::saveToDatabase()
+{
+   DB_HANDLE hdb = GetLocalDatabaseHandle();
+
+   DB_STATEMENT hStmt;
+   if (IsDatabaseRecordExist(hdb, _T("dc_snmp_targets"), _T("guid"), m_guid))
+      hStmt = DBPrepare(hdb, _T("UPDATE dc_snmp_targets SET server_id=?,ip_address=?,snmp_version=?,port=?,auth_type=?,enc_type=?,auth_name=?,auth_pass=?,enc_pass=? WHERE guid=?"));
+   else
+      hStmt = DBPrepare(hdb, _T("INSERT INTO dc_snmp_targets (server_id,ip_address,snmp_version,port,auth_type,enc_type,auth_name,auth_pass,enc_pass,guid) VALUES (?,?,?,?,?,?,?,?,?,?)"));
+   if (hStmt == NULL)
+      return false;
+
+   DBBind(hStmt, 1, DB_SQLTYPE_BIGINT, m_serverId);
+   DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, (const TCHAR *)m_ipAddress.toString(), DB_BIND_TRANSIENT);
+   DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (INT32)m_snmpVersion);
+   DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (INT32)m_port);
+   DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (INT32)m_authType);
+   DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (INT32)m_encType);
+   DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, WideStringFromUTF8String(m_authName), DB_BIND_DYNAMIC);
+   DBBind(hStmt, 8, DB_SQLTYPE_VARCHAR, WideStringFromUTF8String(m_authPassword), DB_BIND_DYNAMIC);
+   DBBind(hStmt, 9, DB_SQLTYPE_VARCHAR, WideStringFromUTF8String(m_encPassword), DB_BIND_DYNAMIC);
+   TCHAR guidText[64];
+   DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, uuid_to_string(m_guid, guidText), DB_BIND_STATIC);
+
+   bool success = DBExecute(hStmt);
+   DBFreeStatement(hStmt);
+   return success;
+}
+
+/**
+ * Get SNMP transport (create if needed)
+ */
+SNMP_Transport *SNMPTarget::getTransport(UINT16 port)
+{
+   if (m_transport != NULL)
+      return m_transport;
+
+   m_transport = new SNMP_UDPTransport;
+       ((SNMP_UDPTransport *)m_transport)->createUDPTransport(m_ipAddress, (port != 0) ? port : m_port);
+   m_transport->setSnmpVersion(m_snmpVersion);
+   SNMP_SecurityContext *ctx = new SNMP_SecurityContext(m_authName, m_authPassword, m_encPassword, m_authType, m_encType);
+       ctx->setSecurityModel((m_snmpVersion == SNMP_VERSION_3) ? SNMP_SECURITY_MODEL_USM : SNMP_SECURITY_MODEL_V2C);
+   m_transport->setSecurityContext(ctx);
+   return m_transport;
+}
+
+/**
+ * Update SNMP target information
+ */
+void UpdateSnmpTarget(SNMPTarget *target)
+{
+   MutexLock(s_snmpTargetsLock);
+   s_snmpTargets.set(target->getGuid(), target);
+   target->saveToDatabase();
+   MutexUnlock(s_snmpTargetsLock);
+}
+
+/**
+ * Get value from SNMP node
+ */
+bool GetSnmpValue(const uuid_t& target, UINT16 port, const TCHAR *oid, TCHAR *value, int interpretRawValue)
+{
+   bool success = false;
+
+   MutexLock(s_snmpTargetsLock);
+   SNMPTarget *t = s_snmpTargets.get(target);
+   if (t != NULL)
+   {
+      SNMP_Transport *snmp = t->getTransport(port);
+      UINT32 rcc;
+
+      if (interpretRawValue == SNMP_RAWTYPE_NONE)
+      {
+         rcc = SnmpGetEx(snmp, oid, NULL, 0, value, MAX_RESULT_LENGTH * sizeof(TCHAR), SG_PSTRING_RESULT, NULL);
+      }
+      else
+      {
+                       BYTE rawValue[1024];
+                       memset(rawValue, 0, 1024);
+         rcc = SnmpGetEx(snmp, oid, NULL, 0, rawValue, 1024, SG_RAW_RESULT, NULL);
+                       if (rcc == SNMP_ERR_SUCCESS)
+                       {
+                               switch(interpretRawValue)
+                               {
+                                       case SNMP_RAWTYPE_INT32:
+                                               _sntprintf(value, MAX_RESULT_LENGTH, _T("%d"), ntohl(*((LONG *)rawValue)));
+                                               break;
+                                       case SNMP_RAWTYPE_UINT32:
+                                               _sntprintf(value, MAX_RESULT_LENGTH, _T("%u"), ntohl(*((UINT32 *)rawValue)));
+                                               break;
+                                       case SNMP_RAWTYPE_INT64:
+                                               _sntprintf(value, MAX_RESULT_LENGTH, INT64_FMT, (INT64)ntohq(*((INT64 *)rawValue)));
+                                               break;
+                                       case SNMP_RAWTYPE_UINT64:
+                                               _sntprintf(value, MAX_RESULT_LENGTH, UINT64_FMT, ntohq(*((QWORD *)rawValue)));
+                                               break;
+                                       case SNMP_RAWTYPE_DOUBLE:
+                                               _sntprintf(value, MAX_RESULT_LENGTH, _T("%f"), ntohd(*((double *)rawValue)));
+                                               break;
+                                       case SNMP_RAWTYPE_IP_ADDR:
+                                               IpToStr(ntohl(*((UINT32 *)rawValue)), value);
+                                               break;
+                                       case SNMP_RAWTYPE_MAC_ADDR:
+                                               MACToStr(rawValue, value);
+                                               break;
+                                       default:
+                                               value[0] = 0;
+                                               break;
+                               }
+                       }
+      }
+      success = (rcc == SNMP_ERR_SUCCESS);
+   }
+   else
+   {
+      TCHAR buffer[64];
+      DebugPrintf(INVALID_INDEX, 6, _T("SNMP target with guid %s not found"), uuid_to_string(target, buffer));
+   }
+   MutexUnlock(s_snmpTargetsLock);
+   
+   return success;
+}
index b6188fc..576c42e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ** NetXMS multiplatform core agent
-** Copyright (C) 2003-2012 Victor Kirhenshtein
+** Copyright (C) 2003-2015 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
@@ -415,6 +415,35 @@ public:
 };
 
 /**
+ * SNMP target
+ */
+class SNMPTarget
+{
+private:
+   uuid_t m_guid;
+   UINT64 m_serverId;
+   InetAddress m_ipAddress;
+   UINT16 m_port;
+   BYTE m_snmpVersion;
+   BYTE m_authType;
+   BYTE m_encType;
+   char *m_authName;
+   char *m_authPassword;
+   char *m_encPassword;
+   SNMP_Transport *m_transport;
+
+public:
+   SNMPTarget(UINT64 serverId, NXCPMessage *msg, UINT32 baseId);
+   SNMPTarget(DB_RESULT hResult, int row);
+   ~SNMPTarget();
+
+   const uuid_t& getGuid() const { return m_guid; }
+   SNMP_Transport *getTransport(UINT16 port);
+
+   bool saveToDatabase();
+};
+
+/**
  * Functions
  */
 BOOL Initialize();
index 07f79fc..4d87e24 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath=".\dcsnmp.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath=".\epp.cpp"
                                >
                        </File>
index 23875d6..bfb0de3 100644 (file)
@@ -1810,3 +1810,55 @@ int LIBNXDB_EXPORTABLE DBGetSyntax(DB_HANDLE conn)
 
        return syntax;
 }
+
+/**
+ * Check if given record exists in database
+ */
+bool LIBNXDB_EXPORTABLE IsDatabaseRecordExist(DB_HANDLE hdb, const TCHAR *table, const TCHAR *idColumn, UINT32 id)
+{
+       bool exist = false;
+
+       TCHAR query[256];
+       _sntprintf(query, 256, _T("SELECT %s FROM %s WHERE %s=?"), idColumn, table, idColumn);
+
+       DB_STATEMENT hStmt = DBPrepare(hdb, query);
+       if (hStmt != NULL)
+       {
+               DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, id);
+               DB_RESULT hResult = DBSelectPrepared(hStmt);
+               if (hResult != NULL)
+               {
+                       exist = (DBGetNumRows(hResult) > 0);
+                       DBFreeResult(hResult);
+               }
+               DBFreeStatement(hStmt);
+       }
+       return exist;
+}
+
+/**
+ * Check if given record exists in database
+ */
+bool LIBNXDB_EXPORTABLE IsDatabaseRecordExist(DB_HANDLE hdb, const TCHAR *table, const TCHAR *idColumn, const uuid_t id)
+{
+       bool exist = false;
+
+       TCHAR query[256];
+       _sntprintf(query, 256, _T("SELECT %s FROM %s WHERE %s=?"), idColumn, table, idColumn);
+
+       DB_STATEMENT hStmt = DBPrepare(hdb, query);
+       if (hStmt != NULL)
+       {
+      TCHAR guidText[64];
+      uuid_to_string(id, guidText);
+               DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, guidText, DB_BIND_STATIC);
+               DB_RESULT hResult = DBSelectPrepared(hStmt);
+               if (hResult != NULL)
+               {
+                       exist = (DBGetNumRows(hResult) > 0);
+                       DBFreeResult(hResult);
+               }
+               DBFreeStatement(hStmt);
+       }
+       return exist;
+}
index 004b5ad..eec14df 100644 (file)
@@ -1,13 +1,13 @@
-SOURCES = array.cpp base64.cpp bytestream.cpp config.cpp \
-         crypto.cpp dirw_unix.c gen_uuid.c geolocation.cpp getopt.c \
-         dload.cpp hash.cpp ice.c icmp.cpp icmp6.cpp iconv.cpp \
+SOURCES = array.cpp base64.cpp bytestream.cpp config.cpp crypto.cpp \
+         dirw_unix.c geolocation.cpp getopt.c dload.cpp hash.cpp \
+         hashmapbase.cpp ice.c icmp.cpp icmp6.cpp iconv.cpp \
          inet_pton.c inetaddr.cpp log.cpp main.cpp md5.cpp message.cpp \
          msgrecv.cpp msgwq.cpp net.cpp nxcp.cpp pa.cpp \
          parisc_atomic.cpp qsort.c queue.cpp rwlock.cpp scandir.c \
          serial.cpp sha1.cpp sha2.cpp solaris9_atomic.c string.cpp \
          stringlist.cpp strmap.cpp strmapbase.cpp strptime.c strset.cpp \
          strtoll.c strtoull.c table.cpp threads.cpp timegm.c tools.cpp \
-         tp.cpp unicode.cpp uuid.c wcstoll.c wcstoull.c xml.cpp \
+         tp.cpp unicode.cpp uuid.cpp wcstoll.c wcstoull.c xml.cpp \
          wcscasecmp.cpp wcsncasecmp.cpp
 
 lib_LTLIBRARIES = libnetxms.la
@@ -32,7 +32,7 @@ endif
 
 EXTRA_DIST = \
        libnetxms.vcproj \
-       libnetxms.h ice.h md5.h sha1.h sha2.h strmap-internal.h uuidP.h \
+       libnetxms.h ice.h md5.h sha1.h sha2.h strmap-internal.h \
        dir.c dirw.c \
        seh.cpp StackWalker.cpp StackWalker.h \
        ldcw.s
diff --git a/src/libnetxms/hashmapbase.cpp b/src/libnetxms/hashmapbase.cpp
new file mode 100644 (file)
index 0000000..5f1fee1
--- /dev/null
@@ -0,0 +1,203 @@
+/* 
+** NetXMS - Network Management System
+** NetXMS Foundation Library
+** Copyright (C) 2003-2015 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published
+** by the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: hashmapbase.cpp
+**
+**/
+
+#include "libnetxms.h"
+#include <uthash.h>
+
+/**
+ * Entry
+ */
+struct HashMapEntry
+{
+   UT_hash_handle hh;
+   union
+   {
+      BYTE d[16];
+      void *p;
+   } key;
+   void *value;
+};
+
+/**
+ * Delete key
+ */
+#define DELETE_KEY(e) do { if (m_keylen > 16) free(e->key.p); } while(0)
+
+/**
+ * Get pointer to key
+ */
+#define GET_KEY(e) ((m_keylen <= 16) ? (e)->key.d : (e)->key.p)
+
+/**
+ * Standard object destructor
+ */
+static void ObjectDestructor(void *object)
+{
+       free(object);
+}
+
+/**
+ * Constructors
+ */
+HashMapBase::HashMapBase(bool objectOwner, unsigned int keylen)
+{
+       m_data = NULL;
+       m_objectOwner = objectOwner;
+   m_keylen = keylen;
+       m_objectDestructor = ObjectDestructor;
+}
+
+/**
+ * Destructor
+ */
+HashMapBase::~HashMapBase()
+{
+       clear();
+}
+
+/**
+ * Clear map
+ */
+void HashMapBase::clear()
+{
+   HashMapEntry *entry, *tmp;
+   HASH_ITER(hh, m_data, entry, tmp)
+   {
+      HASH_DEL(m_data, entry);
+      DELETE_KEY(entry);
+      destroyObject(entry->value);
+      free(entry);
+   }
+}
+
+/**
+ * Find entry index by key
+ */
+HashMapEntry *HashMapBase::find(const void *key)
+{
+       if (key == NULL)
+               return NULL;
+
+   HashMapEntry *entry;
+   HASH_FIND(hh, m_data, key, m_keylen, entry);
+   return entry;
+}
+
+/**
+ * Set value
+ */
+void HashMapBase::_set(const void *key, void *value)
+{
+   if (key == NULL)
+      return;
+
+       HashMapEntry *entry = find(key);
+       if (entry != NULL)
+       {
+               if (m_objectOwner)
+         destroyObject(entry->value);
+      entry->value = value;
+       }
+       else
+       {
+      entry = (HashMapEntry *)malloc(sizeof(HashMapEntry));
+      if (m_keylen <= 16)
+         memcpy(entry->key.d, key, m_keylen);
+      else
+         entry->key.p = nx_memdup(key, m_keylen);
+      entry->value = value;
+      HASH_ADD_KEYPTR(hh, m_data, GET_KEY(entry), m_keylen, entry);
+       }
+}
+
+/**
+ * Get value by key
+ */
+void *HashMapBase::_get(const void *key)
+{
+   HashMapEntry *entry;
+   HASH_FIND(hh, m_data, key, m_keylen, entry);
+   return (entry != NULL) ? entry->value : NULL;
+}
+
+/**
+ * Delete value
+ */
+void HashMapBase::_remove(const void *key)
+{
+   HashMapEntry *entry;
+   HASH_FIND(hh, m_data, key, m_keylen, entry);
+   if (entry != NULL)
+   {
+      HASH_DEL(m_data, entry);
+      DELETE_KEY(entry);
+               if (m_objectOwner)
+         destroyObject(entry->value);
+      free(entry);
+   }
+}
+
+/**
+ * Enumerate entries
+ * Returns true if whole map was enumerated and false if enumeration was aborted by callback.
+ */
+bool HashMapBase::forEach(bool (*cb)(const void *, const void *, void *), void *userData)
+{
+   bool result = true;
+   HashMapEntry *entry, *tmp;
+   HASH_ITER(hh, m_data, entry, tmp)
+   {
+      if (!cb(GET_KEY(entry), entry->value, userData))
+      {
+         result = false;
+         break;
+      }
+   }
+   return result;
+}
+
+/**
+ * Find entry
+ */
+const void *HashMapBase::findElement(bool (*comparator)(const void *, const void *, void *), void *userData)
+{
+   const void *result = NULL;
+   HashMapEntry *entry, *tmp;
+   HASH_ITER(hh, m_data, entry, tmp)
+   {
+      if (comparator(GET_KEY(entry), entry->value, userData))
+      {
+         result = entry->value;
+         break;
+      }
+   }
+   return result;
+}
+
+/**
+ * Get size
+ */
+int HashMapBase::size()
+{
+   return HASH_COUNT(m_data);
+}
index 6481887..d9ec2e4 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath=".\gen_uuid.c"
-                               >
-                       </File>
-                       <File
                                RelativePath=".\geolocation.cpp"
                                >
                        </File>
                                >
                        </File>
                        <File
+                               RelativePath=".\hashmapbase.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath=".\ice.c"
                                >
                        </File>
                                >
                        </File>
                        <File
-                               RelativePath=".\uuid.c"
+                               RelativePath=".\uuid.cpp"
                                >
                        </File>
                        <File
                                RelativePath="..\..\include\uuid.h"
                                >
                        </File>
-                       <File
-                               RelativePath=".\uuidP.h"
-                               >
-                       </File>
                </Filter>
                <Filter
                        Name="Resource Files"
index dc3cbb3..6bfcf1a 100644 (file)
@@ -538,7 +538,7 @@ void LIBNETXMS_EXPORTABLE nxlog_write(DWORD msg, WORD wType, const char *format,
        char *mbMsg;
 #endif
 
-       if (!(m_flags & NXLOG_IS_OPEN))
+       if (!(m_flags & NXLOG_IS_OPEN) || (msg == 0))
                return;
 
    memset(strings, 0, sizeof(TCHAR *) * 16);
index 461586d..bd9eb39 100644 (file)
@@ -393,11 +393,10 @@ UINT32 LIBNETXMS_EXPORTABLE inet_addr_w(const WCHAR *pszAddr)
  */
 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBString(const char *pszString)
 {
-   WCHAR *pwszOut;
-   int nLen;
-
-   nLen = (int) strlen(pszString) + 1;
-   pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
+   if (pszString == NULL)
+      return NULL;
+   int nLen = (int) strlen(pszString) + 1;
+   WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszString, -1, pwszOut, nLen);
    return pwszOut;
 }
@@ -407,11 +406,10 @@ WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBString(const char *pszString)
  */
 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
 {
-   WCHAR *pwszOut;
-   int nLen;
-
-   nLen = (int) strlen(pszString) + 1;
-   pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
+   if (pszString == NULL)
+      return NULL;
+   int nLen = (int)strlen(pszString) + 1;
+   WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
    MultiByteToWideChar(CP_UTF8, 0, pszString, -1, pwszOut, nLen);
    return pwszOut;
 }
@@ -422,11 +420,10 @@ WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
  */
 char LIBNETXMS_EXPORTABLE *MBStringFromWideString(const WCHAR *pwszString)
 {
-   char *pszOut;
-   int nLen;
-
-   nLen = (int)wcslen(pwszString) + 1;
-   pszOut = (char *)malloc(nLen);
+   if (pwszString == NULL)
+      return NULL;
+   int nLen = (int)wcslen(pwszString) + 1;
+   char *pszOut = (char *)malloc(nLen);
    WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, pszOut, nLen, NULL, NULL);
    return pszOut;
 }
diff --git a/src/libnetxms/uuid.c b/src/libnetxms/uuid.c
deleted file mode 100644 (file)
index e06ff3f..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/* 
-** libuuid integrated into NetXMS project
-** Copyright (C) 1996, 1997 Theodore Ts'o.
-** Integrated into NetXMS by Victor Kirhenshtein
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU Lesser General Public License as published
-** by the Free Software Foundation; either version 3 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU Lesser General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-** File: uuid.cpp
-**
-**/
-
-#include "libnetxms.h"
-#include "uuidP.h"
-
-
-//
-// Clear a UUID
-//
-
-void LIBNETXMS_EXPORTABLE uuid_clear(uuid_t uu)
-{
-       memset(uu, 0, 16);
-}
-
-#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
-
-
-//
-// compare whether or not two UUID's are the same
-//
-// Returns 1/-1 if the two UUID's are different, and 0 if they are the same.
-//
-
-int LIBNETXMS_EXPORTABLE uuid_compare(uuid_t uu1, uuid_t uu2)
-{
-       struct uuid     uuid1, uuid2;
-
-       uuid_unpack(uu1, &uuid1);
-       uuid_unpack(uu2, &uuid2);
-
-       UUCMP(uuid1.time_low, uuid2.time_low);
-       UUCMP(uuid1.time_mid, uuid2.time_mid);
-       UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
-       UUCMP(uuid1.clock_seq, uuid2.clock_seq);
-       return memcmp(uuid1.node, uuid2.node, 6);
-}
-
-
-//
-// isnull.c --- Check whether or not the UUID is null
-// Returns 1 if the uuid is the NULL uuid
-//
-
-int LIBNETXMS_EXPORTABLE uuid_is_null(uuid_t uu)
-{
-       unsigned char   *cp;
-       int i;
-
-       for (i=0, cp = uu; i < 16; i++)
-               if (*cp++)
-                       return 0;
-       return 1;
-}
-
-
-//
-// Internal routine for packing UUID's
-//
-
-void uuid_pack(struct uuid *uu, uuid_t ptr)
-{
-       unsigned int    tmp;
-       unsigned char   *out = ptr;
-
-       tmp = uu->time_low;
-       out[3] = (unsigned char) tmp;
-       tmp >>= 8;
-       out[2] = (unsigned char) tmp;
-       tmp >>= 8;
-       out[1] = (unsigned char) tmp;
-       tmp >>= 8;
-       out[0] = (unsigned char) tmp;
-       
-       tmp = uu->time_mid;
-       out[5] = (unsigned char) tmp;
-       tmp >>= 8;
-       out[4] = (unsigned char) tmp;
-
-       tmp = uu->time_hi_and_version;
-       out[7] = (unsigned char) tmp;
-       tmp >>= 8;
-       out[6] = (unsigned char) tmp;
-
-       tmp = uu->clock_seq;
-       out[9] = (unsigned char) tmp;
-       tmp >>= 8;
-       out[8] = (unsigned char) tmp;
-
-       memcpy(out+10, uu->node, 6);
-}
-
-
-//
-// Internal routine for unpacking UUID
-//
-
-void uuid_unpack(uuid_t in, struct uuid *uu)
-{
-       unsigned char   *ptr = in;
-       unsigned int    tmp;
-
-       tmp = *ptr++;
-       tmp = (tmp << 8) | *ptr++;
-       tmp = (tmp << 8) | *ptr++;
-       tmp = (tmp << 8) | *ptr++;
-       uu->time_low = tmp;
-
-       tmp = *ptr++;
-       tmp = (tmp << 8) | *ptr++;
-       uu->time_mid = tmp;
-       
-       tmp = *ptr++;
-       tmp = (tmp << 8) | *ptr++;
-       uu->time_hi_and_version = tmp;
-
-       tmp = *ptr++;
-       tmp = (tmp << 8) | *ptr++;
-       uu->clock_seq = tmp;
-
-       memcpy(uu->node, ptr, 6);
-}
-
-
-//
-// Parse UUID
-//
-
-int LIBNETXMS_EXPORTABLE uuid_parse(const TCHAR *in, uuid_t uu)
-{
-       struct uuid uuid;
-       int i;
-       const TCHAR *cp;
-       TCHAR buf[3];
-
-       if (_tcslen(in) != 36)
-               return -1;
-       for (i=0, cp = in; i <= 36; i++,cp++) {
-               if ((i == 8) || (i == 13) || (i == 18) ||
-                   (i == 23))
-                       if (*cp == _T('-'))
-                               continue;
-               if (i == 36)
-                       if (*cp == 0)
-                               continue;
-               if (!_istxdigit(*cp))
-                       return -1;
-       }
-       uuid.time_low = _tcstoul(in, NULL, 16);
-       uuid.time_mid = (WORD)_tcstoul(in + 9, NULL, 16);
-       uuid.time_hi_and_version = (WORD)_tcstoul(in + 14, NULL, 16);
-       uuid.clock_seq = (WORD)_tcstoul(in + 19, NULL, 16);
-       cp = in + 24;
-       buf[2] = 0;
-       for(i = 0; i < 6; i++)
-   {
-               buf[0] = *cp++;
-               buf[1] = *cp++;
-               uuid.node[i] = (BYTE)_tcstoul(buf, NULL, 16);
-       }
-       
-       uuid_pack(&uuid, uu);
-       return 0;
-}
-
-
-//
-// Convert packed UUID to string
-//
-
-TCHAR LIBNETXMS_EXPORTABLE *uuid_to_string(uuid_t uu, TCHAR *out)
-{
-       struct uuid uuid;
-
-       uuid_unpack(uu, &uuid);
-       _sntprintf(out, 64,
-               _T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"),
-               uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
-               uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
-               uuid.node[0], uuid.node[1], uuid.node[2],
-               uuid.node[3], uuid.node[4], uuid.node[5]);
-   return out;
-}
similarity index 58%
rename from src/libnetxms/gen_uuid.c
rename to src/libnetxms/uuid.cpp
index 36f11a2..c22ed16 100644 (file)
@@ -1,19 +1,28 @@
-/*
- * gen_uuid.c --- generate a DCE-compatible uuid
- *
- * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU 
- * Library General Public License.
- * %End-Header%
- */
-
-#undef _XOPEN_SOURCE
-#undef _XOPEN_SOURCE_EXTENDED
+/* 
+** libuuid integrated into NetXMS project
+** Copyright (C) 1996, 1997 Theodore Ts'o.
+** Integrated into NetXMS by Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published
+** by the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: uuid.cpp
+**
+**/
 
 #include "libnetxms.h"
-#include "uuidP.h"
+#include <uuid.h>
 
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
 
 #ifdef HAVE_SRANDOM
-# define srand(x)      srandom(x)
-# define rand()                random()
+#define srand(x) srandom(x)
+#define rand()   random()
 #endif
 
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW  0x13814000
+
+/**
+ * Unpacked UUID structure
+ */
+struct __uuid
+{
+       DWORD   time_low;
+       WORD    time_mid;
+       WORD    time_hi_and_version;
+       WORD    clock_seq;
+       BYTE    node[6];
+};
+
+/**
+ * Internal routine for packing UUID's
+ */
+static void uuid_pack(struct __uuid *uu, uuid_t ptr)
+{
+       unsigned int    tmp;
+       unsigned char   *out = ptr;
+
+       tmp = uu->time_low;
+       out[3] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[2] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[1] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[0] = (unsigned char) tmp;
+       
+       tmp = uu->time_mid;
+       out[5] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[4] = (unsigned char) tmp;
+
+       tmp = uu->time_hi_and_version;
+       out[7] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[6] = (unsigned char) tmp;
+
+       tmp = uu->clock_seq;
+       out[9] = (unsigned char) tmp;
+       tmp >>= 8;
+       out[8] = (unsigned char) tmp;
+
+       memcpy(out+10, uu->node, 6);
+}
+
+/**
+ * Internal routine for unpacking UUID
+ */
+static void uuid_unpack(const uuid_t in, struct __uuid *uu)
+{
+       const unsigned char *ptr = in;
+       unsigned int tmp;
+
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->time_low = tmp;
+
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->time_mid = tmp;
+       
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->time_hi_and_version = tmp;
+
+       tmp = *ptr++;
+       tmp = (tmp << 8) | *ptr++;
+       uu->clock_seq = tmp;
+
+       memcpy(uu->node, ptr, 6);
+}
+
+/**
+ * Clear a UUID
+ */
+void LIBNETXMS_EXPORTABLE uuid_clear(uuid_t uu)
+{
+       memset(uu, 0, 16);
+}
+
+#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
+
+/**
+ * compare whether or not two UUID's are the same
+ *
+ * Returns 1/-1 if the two UUID's are different, and 0 if they are the same.
+ */
+int LIBNETXMS_EXPORTABLE uuid_compare(const uuid_t uu1, const uuid_t uu2)
+{
+       struct __uuid   uuid1, uuid2;
+
+       uuid_unpack(uu1, &uuid1);
+       uuid_unpack(uu2, &uuid2);
+
+       UUCMP(uuid1.time_low, uuid2.time_low);
+       UUCMP(uuid1.time_mid, uuid2.time_mid);
+       UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
+       UUCMP(uuid1.clock_seq, uuid2.clock_seq);
+       return memcmp(uuid1.node, uuid2.node, 6);
+}
+
+/**
+ * isnull.c --- Check whether or not the UUID is null
+ * Returns 1 if the uuid is the NULL uuid
+ */
+int LIBNETXMS_EXPORTABLE uuid_is_null(const uuid_t uu)
+{
+       const unsigned char *cp;
+       int i;
+
+       for (i=0, cp = uu; i < 16; i++)
+               if (*cp++)
+                       return 0;
+       return 1;
+}
+
+/**
+ * Parse UUID
+ */
+int LIBNETXMS_EXPORTABLE uuid_parse(const TCHAR *in, uuid_t uu)
+{
+       struct __uuid uuid;
+       int i;
+       const TCHAR *cp;
+       TCHAR buf[3];
+
+       if (_tcslen(in) != 36)
+               return -1;
+       for (i=0, cp = in; i <= 36; i++,cp++) {
+               if ((i == 8) || (i == 13) || (i == 18) ||
+                   (i == 23))
+                       if (*cp == _T('-'))
+                               continue;
+               if (i == 36)
+                       if (*cp == 0)
+                               continue;
+               if (!_istxdigit(*cp))
+                       return -1;
+       }
+       uuid.time_low = _tcstoul(in, NULL, 16);
+       uuid.time_mid = (WORD)_tcstoul(in + 9, NULL, 16);
+       uuid.time_hi_and_version = (WORD)_tcstoul(in + 14, NULL, 16);
+       uuid.clock_seq = (WORD)_tcstoul(in + 19, NULL, 16);
+       cp = in + 24;
+       buf[2] = 0;
+       for(i = 0; i < 6; i++)
+   {
+               buf[0] = *cp++;
+               buf[1] = *cp++;
+               uuid.node[i] = (BYTE)_tcstoul(buf, NULL, 16);
+       }
+       
+       uuid_pack(&uuid, uu);
+       return 0;
+}
+
+/**
+ * Convert packed UUID to string
+ */
+TCHAR LIBNETXMS_EXPORTABLE *uuid_to_string(const uuid_t uu, TCHAR *out)
+{
+       struct __uuid uuid;
+
+       uuid_unpack(uu, &uuid);
+       _sntprintf(out, 64,
+               _T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"),
+               uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+               uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+               uuid.node[0], uuid.node[1], uuid.node[2],
+               uuid.node[3], uuid.node[4], uuid.node[5]);
+   return out;
+}
+
 #ifndef _WIN32
 
 static int get_random_fd()
@@ -269,7 +461,7 @@ static void uuid_generate_time(uuid_t out)
 {
        static unsigned char node_id[6];
        static int has_init = 0;
-       struct uuid uu;
+       struct __uuid uu;
        DWORD clock_mid;
 
        if (!has_init)
@@ -297,7 +489,7 @@ static void uuid_generate_time(uuid_t out)
 static void uuid_generate_random(uuid_t out)
 {
        uuid_t  buf;
-       struct uuid uu;
+       struct __uuid uu;
 
        get_random_bytes(buf, sizeof(buf));
        uuid_unpack(buf, &uu);
diff --git a/src/libnetxms/uuidP.h b/src/libnetxms/uuidP.h
deleted file mode 100644 (file)
index ccbbf40..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * uuid.h -- private header file for uuids
- * 
- * Copyright (C) 1996, 1997 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU 
- * Library General Public License.
- * %End-Header%
- */
-
-#ifndef _uuidP_h_
-#define _uuidP_h_
-
-#include <sys/types.h>
-
-#include <uuid.h>
-
-/*
- * Offset between 15-Oct-1582 and 1-Jan-70
- */
-#define TIME_OFFSET_HIGH 0x01B21DD2
-#define TIME_OFFSET_LOW  0x13814000
-
-struct uuid
-{
-       DWORD   time_low;
-       WORD    time_mid;
-       WORD    time_hi_and_version;
-       WORD    clock_seq;
-       BYTE    node[6];
-};
-
-
-/*
- * prototypes
- */
-void uuid_pack(struct uuid *uu, uuid_t ptr);
-void uuid_unpack(uuid_t in, struct uuid *uu);
-
-#endif
index 1421bf3..f11b3bc 100644 (file)
@@ -38,7 +38,7 @@ static UINT32 PortMapCallback(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Trans
        pRqPDU->bindVariable(new SNMP_Variable(oid));
 
        SNMP_PDU *pRespPDU;
-   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
 
        if (rcc == SNMP_ERR_SUCCESS)
index 2c3ff5b..13f9fd9 100644 (file)
@@ -53,7 +53,7 @@ static UINT32 CDPTopoHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Transp
        pRqPDU->bindVariable(new SNMP_Variable(newOid, oid->getLength()));
 
    SNMP_PDU *pRespPDU = NULL;
-   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
 
        if (rcc == SNMP_ERR_SUCCESS)
index f7402e2..c6d516b 100644 (file)
@@ -233,7 +233,7 @@ static UINT32 FDBHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Transport *
        pRqPDU->bindVariable(new SNMP_Variable(oid, oidLen));
 
    SNMP_PDU *pRespPDU;
-   UINT32 rcc = pTransport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = pTransport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
 
        if (rcc == SNMP_ERR_SUCCESS)
@@ -285,7 +285,7 @@ static UINT32 Dot1qTpFdbHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Tran
        pRqPDU->bindVariable(new SNMP_Variable(oid, oidLen));
 
    SNMP_PDU *pRespPDU;
-   UINT32 rcc = pTransport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = pTransport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
 
        if (rcc == SNMP_ERR_SUCCESS)
index c208d4f..703e5f2 100644 (file)
@@ -40,7 +40,7 @@ static UINT32 PortLocalInfoHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_
        pRqPDU->bindVariable(new SNMP_Variable(newOid, oid->getLength()));
 
        SNMP_PDU *pRespPDU = NULL;
-   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
        if (rcc == SNMP_ERR_SUCCESS)
    {
@@ -166,7 +166,7 @@ static UINT32 LLDPTopoHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Trans
        pRqPDU->bindVariable(new SNMP_Variable(newOid, oid->getLength()));
 
        SNMP_PDU *pRespPDU = NULL;
-   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
        if (rcc == SNMP_ERR_SUCCESS)
    {
index c19a998..3bf8b45 100644 (file)
@@ -376,10 +376,12 @@ static void LoadGlobalConfig()
    g_icmpPingTimeout = ConfigReadInt(_T("IcmpPingTimeout"), 1500);
        g_icmpPingSize = ConfigReadInt(_T("IcmpPingSize"), 46);
        g_lockTimeout = ConfigReadInt(_T("LockTimeout"), 60000);
-       g_snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 2000);
        g_agentCommandTimeout = ConfigReadInt(_T("AgentCommandTimeout"), 4000);
        g_thresholdRepeatInterval = ConfigReadInt(_T("ThresholdRepeatInterval"), 0);
        g_requiredPolls = ConfigReadInt(_T("PollCountForStatusChange"), 1);
+
+       UINT32 snmpTimeout = ConfigReadInt(_T("SNMPRequestTimeout"), 2000);
+   SnmpSetDefaultTimeout(snmpTimeout);
 }
 
 /**
@@ -630,6 +632,7 @@ BOOL NXCORE_EXPORTABLE Initialize()
 #endif
 
        InitLocalNetInfo();
+   SnmpSetMessageIds(MSG_OID_PARSE_ERROR, MSG_SNMP_UNKNOWN_TYPE, MSG_SNMP_GET_ERROR);
 
    Timer::globalInit();
 
index f70deb6..3992da6 100644 (file)
@@ -39,7 +39,7 @@ static WORD ReadRemoteSlotAndPort(Node *node, SNMP_ObjectId *oid, UINT32 snmpVer
 
        WORD result = 0;
        SNMP_PDU *pRespPDU = NULL;
-   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   UINT32 rcc = transport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
        delete pRqPDU;
        if ((rcc == SNMP_ERR_SUCCESS) && (pRespPDU->getNumVariables() > 0) && (pRespPDU->getVariable(0)->getType() == ASN_OCTET_STRING))
    {
index 374abe0..4837bf0 100644 (file)
@@ -48,7 +48,7 @@ Node::Node() : DataCollectionTarget()
    m_szSharedSecret[0] = 0;
    m_iStatusPollType = POLL_ICMP_PING;
    m_snmpVersion = SNMP_VERSION_1;
-   m_wSNMPPort = SNMP_DEFAULT_PORT;
+   m_snmpPort = SNMP_DEFAULT_PORT;
        char community[MAX_COMMUNITY_LENGTH];
    ConfigReadStrA(_T("DefaultCommunityString"), community, MAX_COMMUNITY_LENGTH, "public");
        m_snmpSecurity = new SNMP_SecurityContext(community);
@@ -127,7 +127,7 @@ Node::Node(const InetAddress& addr, UINT32 dwFlags, UINT32 agentProxy, UINT32 sn
    m_szSharedSecret[0] = 0;
    m_iStatusPollType = POLL_ICMP_PING;
    m_snmpVersion = SNMP_VERSION_1;
-   m_wSNMPPort = SNMP_DEFAULT_PORT;
+   m_snmpPort = SNMP_DEFAULT_PORT;
        char community[MAX_COMMUNITY_LENGTH];
    ConfigReadStrA(_T("DefaultCommunityString"), community, MAX_COMMUNITY_LENGTH, "public");
        m_snmpSecurity = new SNMP_SecurityContext(community);
@@ -292,7 +292,7 @@ BOOL Node::loadFromDatabase(UINT32 dwId)
    m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 15);
    m_sysDescription = DBGetField(hResult, 0, 16, NULL, 0);
    m_nUseIfXTable = (BYTE)DBGetFieldLong(hResult, 0, 17);
-       m_wSNMPPort = (WORD)DBGetFieldLong(hResult, 0, 18);
+       m_snmpPort = (WORD)DBGetFieldLong(hResult, 0, 18);
 
        // SNMP authentication parameters
        char snmpAuthObject[256], snmpAuthPassword[256], snmpPrivPassword[256];
@@ -440,7 +440,7 @@ BOOL Node::saveToDatabase(DB_HANDLE hdb)
 
        DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_ipAddress.toString(ipAddr), DB_BIND_STATIC);
        DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, m_primaryName, DB_BIND_STATIC);
-       DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_wSNMPPort);
+       DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_snmpPort);
        DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_dwFlags);
        DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_snmpVersion);
 #ifdef UNICODE
@@ -1427,7 +1427,7 @@ restart_agent_check:
          m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0);
                        DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from agent"), m_name, m_id, (UINT32)m_bootTime);
       }
-      else if (getItemFromSNMP(m_wSNMPPort, _T(".1.3.6.1.2.1.1.3.0"), MAX_RESULT_LENGTH, buffer, SNMP_RAWTYPE_NONE) == DCE_SUCCESS)
+      else if (getItemFromSNMP(m_snmpPort, _T(".1.3.6.1.2.1.1.3.0"), MAX_RESULT_LENGTH, buffer, SNMP_RAWTYPE_NONE) == DCE_SUCCESS)
       {
          m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0) / 100;   // sysUpTime is in hundredths of a second
                        DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from SNMP"), m_name, m_id, (UINT32)m_bootTime);
@@ -3439,7 +3439,7 @@ static UINT32 ReadSNMPTableRow(SNMP_Transport *snmp, SNMP_ObjectId *rowOid, size
    }
 
    SNMP_PDU *response;
-   UINT32 rc = snmp->doRequest(&request, &response, g_snmpTimeout, 3);
+   UINT32 rc = snmp->doRequest(&request, &response, SnmpGetDefaultTimeout(), 3);
    if (rc == SNMP_ERR_SUCCESS)
    {
       if (((int)response->getNumVariables() >= columns->size()) &&
@@ -4142,7 +4142,7 @@ void Node::fillMessageInternal(NXCPMessage *pMsg)
        pMsg->setFieldFromMBString(VID_SNMP_PRIV_PASSWORD, m_snmpSecurity->getPrivPassword());
        pMsg->setField(VID_SNMP_USM_METHODS, (WORD)((WORD)m_snmpSecurity->getAuthMethod() | ((WORD)m_snmpSecurity->getPrivMethod() << 8)));
    pMsg->setField(VID_SNMP_OID, m_szObjectId);
-   pMsg->setField(VID_SNMP_PORT, m_wSNMPPort);
+   pMsg->setField(VID_SNMP_PORT, m_snmpPort);
    pMsg->setField(VID_SNMP_VERSION, (WORD)m_snmpVersion);
    pMsg->setField(VID_AGENT_VERSION, m_szAgentVersion);
    pMsg->setField(VID_PLATFORM_NAME, m_szPlatformName);
@@ -4330,7 +4330,7 @@ UINT32 Node::modifyFromMessageInternal(NXCPMessage *pRequest)
 
    // Change SNMP port
    if (pRequest->isFieldExist(VID_SNMP_PORT))
-               m_wSNMPPort = pRequest->getFieldAsUInt16(VID_SNMP_PORT);
+               m_snmpPort = pRequest->getFieldAsUInt16(VID_SNMP_PORT);
 
    // Change SNMP authentication data
    if (pRequest->isFieldExist(VID_SNMP_AUTH_OBJECT))
@@ -5200,7 +5200,7 @@ SNMP_Transport *Node::createSnmpTransport(WORD port, const TCHAR *context)
        if (snmpProxy == 0)
        {
                pTransport = new SNMP_UDPTransport;
-               ((SNMP_UDPTransport *)pTransport)->createUDPTransport(m_ipAddress, (port != 0) ? port : m_wSNMPPort);
+               ((SNMP_UDPTransport *)pTransport)->createUDPTransport(m_ipAddress, (port != 0) ? port : m_snmpPort);
        }
        else
        {
@@ -5213,7 +5213,7 @@ SNMP_Transport *Node::createSnmpTransport(WORD port, const TCHAR *context)
                        if (pConn != NULL)
                        {
             // Use loopback address if node is SNMP proxy for itself
-            pTransport = new SNMP_ProxyTransport(pConn, (snmpProxy == m_id) ? InetAddress::LOOPBACK : m_ipAddress, (port != 0) ? port : m_wSNMPPort);
+            pTransport = new SNMP_ProxyTransport(pConn, (snmpProxy == m_id) ? InetAddress::LOOPBACK : m_ipAddress, (port != 0) ? port : m_snmpPort);
                        }
                }
        }
@@ -6709,6 +6709,77 @@ AccessPointState Node::getAccessPointState(AccessPoint *ap, SNMP_Transport *snmp
 }
 
 /**
+ * SNMP proxy information structure
+ */
+struct SnmpProxyInfo
+{
+   UINT32 proxyId;
+   NXCPMessage *msg;
+   UINT32 fieldId;
+   UINT32 count;
+   UINT32 nodeInfoFieldId;
+   UINT32 nodeInfoCount;
+};
+
+/**
+ * Collect info for SNMP proxy
+ */
+void Node::collectSnmpProxyInfo(SnmpProxyInfo *info)
+{
+   bool isTarget = false;
+
+   lockDciAccess(false);
+   for(int i = 0; i < m_dcObjects->size(); i++)
+   {
+      DCObject *dco = m_dcObjects->get(i);
+      if ((dco->getDataSource() == DS_SNMP_AGENT) &&
+          (dco->getProxyNode() == info->proxyId) &&
+          (dco->getAgentCacheMode() == AGENT_CACHE_ON))
+      {
+         info->msg->setField(info->fieldId++, dco->getId());
+         info->msg->setField(info->fieldId++, (INT16)dco->getType());
+         info->msg->setField(info->fieldId++, (INT16)dco->getDataSource());
+         info->msg->setField(info->fieldId++, dco->getName());
+         info->msg->setField(info->fieldId++, (INT32)dco->getPollingInterval());
+         info->msg->setFieldFromTime(info->fieldId++, dco->getLastPollTime());
+         info->msg->setField(info->fieldId++, m_guid, UUID_LENGTH);
+         info->msg->setField(info->fieldId++, dco->getSnmpPort());
+         if (dco->getType() == DCO_TYPE_ITEM)
+            info->msg->setField(info->fieldId++, ((DCItem *)dco)->getSnmpRawValueType());
+         else
+            info->msg->setField(info->fieldId++, (INT16)0);
+         info->fieldId += 1;
+         info->count++;
+         isTarget = true;
+      }
+   }
+   unlockDciAccess();
+
+   if (isTarget)
+   {
+      info->msg->setField(info->nodeInfoFieldId++, m_guid, UUID_LENGTH);
+      info->msg->setField(info->nodeInfoFieldId++, m_ipAddress);
+      info->msg->setField(info->nodeInfoFieldId++, m_snmpVersion);
+      info->msg->setField(info->nodeInfoFieldId++, m_snmpPort);
+      info->msg->setField(info->nodeInfoFieldId++, (INT16)m_snmpSecurity->getAuthMethod());
+      info->msg->setField(info->nodeInfoFieldId++, (INT16)m_snmpSecurity->getPrivMethod());
+      info->msg->setFieldFromMBString(info->nodeInfoFieldId++, m_snmpSecurity->getUser());
+      info->msg->setFieldFromMBString(info->nodeInfoFieldId++, m_snmpSecurity->getAuthPassword());
+      info->msg->setFieldFromMBString(info->nodeInfoFieldId++, m_snmpSecurity->getPrivPassword());
+      info->nodeInfoFieldId += 41;
+      info->nodeInfoCount++;
+   }
+}
+
+/**
+ * Callback for colecting proxied SNMP DCIs
+ */
+void Node::collectSNMPProxyInfoCallback(NetObj *node, void *data)
+{
+   ((Node *)node)->collectSnmpProxyInfo((SnmpProxyInfo *)data);
+}
+
+/**
  * Synchronize data collection settings with agent
  */
 void Node::syncDataCollectionWithAgent(AgentConnectionEx *conn)
@@ -6736,7 +6807,17 @@ void Node::syncDataCollectionWithAgent(AgentConnectionEx *conn)
       }
    }
    unlockDciAccess();
-   msg.setField(VID_NUM_ELEMENTS, count);
+
+   SnmpProxyInfo data;
+   data.proxyId = m_id;
+   data.count = count;
+   data.msg = &msg;
+   data.fieldId = fieldId;
+   data.nodeInfoCount = 0;
+   data.nodeInfoFieldId = VID_NODE_INFO_LIST_BASE;
+   g_idxNodeById.forEach(Node::collectSNMPProxyInfoCallback, &data);
+   msg.setField(VID_NUM_ELEMENTS, data.count);
+   msg.setField(VID_NUM_NODES, data.nodeInfoCount);
 
    UINT32 rcc = ERR_CONNECTION_BROKEN;
    NXCPMessage *response = conn->customRequest(&msg);
index b4f6550..200a18a 100644 (file)
@@ -943,7 +943,7 @@ static int F_SNMPGet(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_VM
        pdu->bindVariable(new SNMP_Variable(varName, nameLen));
 
        SNMP_PDU *rspPDU;
-   result = trans->doRequest(pdu, &rspPDU, g_snmpTimeout, 3 /* num retries */);
+   result = trans->doRequest(pdu, &rspPDU, SnmpGetDefaultTimeout(), 3);
    if (result == SNMP_ERR_SUCCESS)
    {
       if ((rspPDU->getNumVariables() > 0) && (rspPDU->getErrorCode() == SNMP_PDU_ERR_SUCCESS))
@@ -1066,7 +1066,7 @@ static int F_SNMPSet(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_VM
 
        // Send request and process response
        UINT32 snmpResult;
-       if ((snmpResult = trans->doRequest(request, &response, g_snmpTimeout, 3)) == SNMP_ERR_SUCCESS)
+       if ((snmpResult = trans->doRequest(request, &response, SnmpGetDefaultTimeout(), 3)) == SNMP_ERR_SUCCESS)
        {
                if (response->getErrorCode() != 0)
                {
@@ -1136,7 +1136,7 @@ static int F_SNMPWalk(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_V
    {
       rqPDU = new SNMP_PDU(SNMP_GET_NEXT_REQUEST, requestId++, trans->getSnmpVersion());
       rqPDU->bindVariable(new SNMP_Variable(name, nameLen));
-      result = trans->doRequest(rqPDU, &rspPDU, g_snmpTimeout, 3);
+      result = trans->doRequest(rqPDU, &rspPDU, SnmpGetDefaultTimeout(), 3);
 
       // Analyze response
       if (result == SNMP_ERR_SUCCESS)
index 4331a31..fbf84b6 100644 (file)
@@ -370,7 +370,7 @@ static UINT32 TableHandler(UINT32 dwVersion, SNMP_Variable *pVar, SNMP_Transport
       }
    }
 
-   dwResult = pTransport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+   dwResult = pTransport->doRequest(pRqPDU, &pRespPDU, SnmpGetDefaultTimeout(), 3);
    delete pRqPDU;
    if (dwResult == SNMP_ERR_SUCCESS)
    {
index 5f4e455..1214e63 100644 (file)
@@ -45,7 +45,7 @@ static UINT32 STPPortListHandler(UINT32 snmpVersion, SNMP_Variable *var, SNMP_Tr
    request->bindVariable(new SNMP_Variable(oid, var->getName()->getLength()));
 
        SNMP_PDU *response = NULL;
-   UINT32 rcc = transport->doRequest(request, &response, g_snmpTimeout, 3);
+   UINT32 rcc = transport->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
        delete request;
        if (rcc == SNMP_ERR_SUCCESS)
    {
index 4d6d91f..b7e798a 100644 (file)
@@ -316,31 +316,6 @@ void EscapeString(String &str)
 }
 
 /**
- * Check if given record exists in database
- */
-bool NXCORE_EXPORTABLE IsDatabaseRecordExist(DB_HANDLE hdb, const TCHAR *table, const TCHAR *idColumn, UINT32 id)
-{
-       bool exist = false;
-
-       TCHAR query[256];
-       _sntprintf(query, 256, _T("SELECT %s FROM %s WHERE %s=?"), idColumn, table, idColumn);
-
-       DB_STATEMENT hStmt = DBPrepare(hdb, query);
-       if (hStmt != NULL)
-       {
-               DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, id);
-               DB_RESULT hResult = DBSelectPrepared(hStmt);
-               if (hResult != NULL)
-               {
-                       exist = (DBGetNumRows(hResult) > 0);
-                       DBFreeResult(hResult);
-               }
-               DBFreeStatement(hStmt);
-       }
-       return exist;
-}
-
-/**
  * Prepare and execute SQL query with single binding - object ID.
  */
 bool NXCORE_EXPORTABLE ExecuteQueryOnObject(DB_HANDLE hdb, UINT32 objectId, const TCHAR *query)
index 441a268..46bdcb8 100644 (file)
@@ -144,7 +144,7 @@ static UINT32 HandlerAccessPointList(UINT32 version, SNMP_Variable *var, SNMP_Tr
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
    SNMP_PDU *response;
-   UINT32 rcc = snmp->doRequest(request, &response, g_snmpTimeout, 3);
+   UINT32 rcc = snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
        delete request;
    if (rcc == SNMP_ERR_SUCCESS)
    {
@@ -241,7 +241,7 @@ static UINT32 HandlerWirelessStationList(UINT32 version, SNMP_Variable *var, SNM
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
    SNMP_PDU *response;
-   UINT32 rcc = snmp->doRequest(request, &response, g_snmpTimeout, 3);
+   UINT32 rcc = snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
        delete request;
    if (rcc == SNMP_ERR_SUCCESS)
    {
index 3b1c17c..89393d5 100644 (file)
@@ -135,7 +135,7 @@ InterfaceList *AlliedTelesisDriver::getInterfaces(SNMP_Transport *snmp, StringMa
             request->bindVariable(new SNMP_Variable(oid));
 
             SNMP_PDU *response;
-            UINT32 rcc = snmp->doRequest(request, &response, g_snmpTimeout, 3);
+            UINT32 rcc = snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
                 delete request;
             if (rcc == SNMP_ERR_SUCCESS)
             {
@@ -239,7 +239,7 @@ VlanList *AlliedTelesisDriver::getVlans(SNMP_Transport *snmp, StringMap *attribu
       request->bindVariable(new SNMP_Variable(oid));
       
       SNMP_PDU *response;
-      if (snmp->doRequest(request, &response, g_snmpTimeout, 3) == SNMP_ERR_SUCCESS)
+      if (snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3) == SNMP_ERR_SUCCESS)
       {
          if ((response->getNumVariables() == 2) && 
              (response->getVariable(0)->getType() != ASN_NO_SUCH_OBJECT) &&
index 2977bcd..2fbaecc 100644 (file)
@@ -152,7 +152,7 @@ static UINT32 HandlerAccessPointList(UINT32 version, SNMP_Variable *var, SNMP_Tr
    request->bindVariable(new SNMP_Variable(oid, 11));
 
    SNMP_PDU *response;
-   UINT32 rcc = snmp->doRequest(request, &response, g_snmpTimeout, 3);
+   UINT32 rcc = snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
        delete request;
    if (rcc == SNMP_ERR_SUCCESS)
    {
index 29dd722..ec1df77 100644 (file)
@@ -155,7 +155,7 @@ static UINT32 HandlerAccessPointListAdopted(UINT32 version, SNMP_Variable *var,
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
    SNMP_PDU *response;
-   if (transport->doRequest(request, &response, g_snmpTimeout, 3) == SNMP_ERR_SUCCESS)
+   if (transport->doRequest(request, &response, SnmpGetDefaultTimeout(), 3) == SNMP_ERR_SUCCESS)
    {
       if (response->getNumVariables() >= 5)
       {
@@ -206,7 +206,7 @@ static UINT32 HandlerRadioList(UINT32 version, SNMP_Variable *var, SNMP_Transpor
    request->bindVariable(new SNMP_Variable(oid, nameLen));
 
    SNMP_PDU *response;
-   if (transport->doRequest(request, &response, g_snmpTimeout, 3) == SNMP_ERR_SUCCESS)
+   if (transport->doRequest(request, &response, SnmpGetDefaultTimeout(), 3) == SNMP_ERR_SUCCESS)
    {
       if (response->getNumVariables() >= 2)
       {
index dc941b1..40e9023 100644 (file)
@@ -98,7 +98,7 @@ InterfaceList *Ping3Driver::getInterfaces(SNMP_Transport *snmp, StringMap *attri
    request->bindVariable(new SNMP_Variable(_T(".1.3.6.1.4.1.35160.1.6.0")));  // MAC address
 
    SNMP_PDU *response;
-   UINT32 rcc = snmp->doRequest(request, &response, g_snmpTimeout, 3);
+   UINT32 rcc = snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
        delete request;
    if (rcc == SNMP_ERR_SUCCESS)
    {
index 96af556..4266ade 100644 (file)
@@ -151,7 +151,7 @@ static UINT32 HandlerAccessPointList(UINT32 version, SNMP_Variable *var, SNMP_Tr
    request->bindVariable(new SNMP_Variable(oid, 11));
 
    SNMP_PDU *response;
-   UINT32 rcc = snmp->doRequest(request, &response, g_snmpTimeout, 3);
+   UINT32 rcc = snmp->doRequest(request, &response, SnmpGetDefaultTimeout(), 3);
        delete request;
    if (rcc == SNMP_ERR_SUCCESS)
    {
index e60551f..b968648 100644 (file)
@@ -861,8 +861,6 @@ void StopDBWriter();
 void PerfDataStorageRequest(DCItem *dci, time_t timestamp, const TCHAR *value);
 void PerfDataStorageRequest(DCTable *dci, time_t timestamp, Table *value);
 
-bool NXCORE_EXPORTABLE IsDatabaseRecordExist(DB_HANDLE hdb, const TCHAR *table, const TCHAR *idColumn, UINT32 id);
-
 void DecodeSQLStringAndSetVariable(NXCPMessage *pMsg, UINT32 dwVarId, TCHAR *pszStr);
 
 SNMP_SecurityContext *SnmpCheckCommSettings(SNMP_Transport *pTransport, INT16 *version, SNMP_SecurityContext *originalContext, StringList *customTestOids);
index ff5a8a2..be423c4 100644 (file)
@@ -1052,6 +1052,7 @@ public:
 };
 
 class Subnet;
+struct SnmpProxyInfo;
 
 /**
  * Node
@@ -1075,7 +1076,7 @@ protected:
    TCHAR m_szSharedSecret[MAX_SECRET_LENGTH];
    INT16 m_iStatusPollType;
    INT16 m_snmpVersion;
-   UINT16 m_wSNMPPort;
+   UINT16 m_snmpPort;
        UINT16 m_nUseIfXTable;
        SNMP_SecurityContext *m_snmpSecurity;
    TCHAR m_szObjectId[MAX_OID_LEN * 4];
@@ -1170,6 +1171,8 @@ protected:
        void updateInstances(DCItem *root, StringMap *instances, UINT32 requestId);
 
    void syncDataCollectionWithAgent(AgentConnectionEx *conn);
+   void collectSnmpProxyInfo(SnmpProxyInfo *info);
+   static void collectSNMPProxyInfoCallback(NetObj *node, void *data);
 
        void updateContainerMembership();
        bool updateInterfaceConfiguration(UINT32 rqid, int maskBits);
@@ -1248,7 +1251,7 @@ public:
 
        void setPrimaryName(const TCHAR *name) { nx_strncpy(m_primaryName, name, MAX_DNS_NAME); }
        void setAgentPort(WORD port) { m_agentPort = port; }
-       void setSnmpPort(WORD port) { m_wSNMPPort = port; }
+       void setSnmpPort(WORD port) { m_snmpPort = port; }
    void changeIPAddress(const InetAddress& ipAddr);
        void changeZone(UINT32 newZone);
 
index 7cc27cc..d40e567 100644 (file)
 #define ENCRYPTION_REQUIRED   3
 
 /**
- * Flags for SnmpGet
- */
-#define SG_VERBOSE        0x0001
-#define SG_STRING_RESULT  0x0002
-#define SG_RAW_RESULT     0x0004
-#define SG_HSTRING_RESULT 0x0008
-#define SG_PSTRING_RESULT 0x0010
-
-/**
  * Agent action output callback events
  */
 enum ActionCallbackEvent
@@ -673,22 +664,10 @@ void LIBNXSRV_EXPORTABLE SetAgentDEP(int iPolicy);
 
 const TCHAR LIBNXSRV_EXPORTABLE *ISCErrorCodeToText(UINT32 code);
 
-UINT32 LIBNXSRV_EXPORTABLE SnmpNewRequestId();
-UINT32 LIBNXSRV_EXPORTABLE SnmpGet(int version, SNMP_Transport *transport,
-                                  const TCHAR *szOidStr, const UINT32 *oidBinary, size_t oidLen, void *pValue,
-                                  size_t bufferSize, UINT32 dwFlags);
-UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
-                                     const TCHAR *szOidStr, const UINT32 *oidBinary, size_t oidLen, void *pValue,
-                                     size_t bufferSize, UINT32 dwFlags, UINT32 *dataLen);
-UINT32 LIBNXSRV_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport, const TCHAR *szRootOid,
-                                                                UINT32 (* pHandler)(UINT32, SNMP_Variable *, SNMP_Transport *, void *),
-                                   void *pUserArg, BOOL bVerbose);
-
 /**
  * Variables
  */
 extern UINT64 LIBNXSRV_EXPORTABLE g_flags;
-extern UINT32 LIBNXSRV_EXPORTABLE g_snmpTimeout;
 extern UINT32 LIBNXSRV_EXPORTABLE g_debugLevel;
 
 /**
index 34697d5..c7dcce6 100644 (file)
@@ -1,6 +1,6 @@
 lib_LTLIBRARIES = libnxsrv.la
 libnxsrv_la_SOURCES = messages.c agent.cpp apinfo.cpp hdlink.cpp iflist.cpp isc.cpp \
-                      main.cpp ndd.cpp snmp.cpp snmpproxy.cpp vlan.cpp
+                      main.cpp ndd.cpp snmpproxy.cpp vlan.cpp
 libnxsrv_la_CPPFLAGS=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 libnxsrv_la_LDFLAGS = -version-info $(NETXMS_LIBRARY_VERSION)
 libnxsrv_la_LIBADD = \
index cb80a5a..52de13c 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath=".\snmp.cpp"
-                               >
-                       </File>
-                       <File
                                RelativePath=".\snmpproxy.cpp"
                                >
                        </File>
index baca91c..934ac1b 100644 (file)
@@ -27,7 +27,6 @@
  * Global variables
  */
 UINT64 LIBNXSRV_EXPORTABLE g_flags = AF_USE_SYSLOG | AF_CATCH_EXCEPTIONS | AF_LOG_SQL_ERRORS;
-UINT32 LIBNXSRV_EXPORTABLE g_snmpTimeout = 2000;
 UINT32 LIBNXSRV_EXPORTABLE g_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
 
 /**
index 5d5d9c6..ba8a301 100644 (file)
@@ -263,7 +263,7 @@ static UINT32 HandlerIpAddressTable(UINT32 version, SNMP_Variable *var, SNMP_Tra
    oid[9] = 5; // ipAddressPrefix
    request.bindVariable(new SNMP_Variable(oid, oidLen));
    SNMP_PDU *response;
-   if (snmp->doRequest(&request, &response, g_snmpTimeout, 3) == SNMP_ERR_SUCCESS)
+   if (snmp->doRequest(&request, &response, SnmpGetDefaultTimeout(), 3) == SNMP_ERR_SUCCESS)
    {
       // check number of varbinds and address type (1 = unicast)
       if ((response->getNumVariables() == 2) && (response->getVariable(0)->getValueAsInt() == 1))
index fec9743..a4432e3 100644 (file)
@@ -1,5 +1,5 @@
 SOURCES = ber.cpp engine.cpp main.cpp mib.cpp oid.cpp pdu.cpp \
-          security.cpp transport.cpp variable.cpp zfile.cpp
+          security.cpp transport.cpp util.cpp variable.cpp zfile.cpp
 
 lib_LTLIBRARIES = libnxsnmp.la
 
index 4e95eb0..97348c9 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath=".\util.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath=".\variable.cpp"
                                >
                        </File>
similarity index 79%
rename from src/server/libnxsrv/snmp.cpp
rename to src/snmp/libnxsnmp/util.cpp
index 8ea65d4..6feebfd 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** NetXMS - Network Management System
-** Copyright (C) 2003-2014 Victor Kirhenshtein
+** Copyright (C) 2003-2015 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** along with this program; if not, write to the Free Software
 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 **
-** File: snmp.cpp
+** File: util.cpp
 **
 **/
 
-#include "libnxsrv.h"
+#include "libnxsnmp.h"
 
 /**
  * Unique request ID
@@ -30,26 +30,63 @@ static VolatileCounter s_requestId = 1;
 /**
  * Generate new request ID
  */
-UINT32 LIBNXSRV_EXPORTABLE SnmpNewRequestId()
+UINT32 LIBNXSNMP_EXPORTABLE SnmpNewRequestId()
 {
    return (UINT32)InterlockedIncrement(&s_requestId);
 }
 
 /**
+ * Message codes
+ */
+static DWORD s_msgParseError = 0;
+static DWORD s_msgTypeError = 0;
+static DWORD s_msgGetError = 0;
+
+/**
+ * Configure SNMP utility function logging
+ */
+void LIBNXSNMP_EXPORTABLE SnmpSetMessageIds(DWORD msgParseError, DWORD msgTypeError, DWORD msgGetError)
+{
+   s_msgParseError = msgParseError;
+   s_msgTypeError = msgTypeError;
+   s_msgGetError = msgGetError;
+}
+
+/**
+ * Default timeout for utility finctions
+ */
+static UINT32 s_snmpTimeout = 2000;
+
+/**
+ * Set SNMP timeout
+ */
+void LIBNXSNMP_EXPORTABLE SnmpSetDefaultTimeout(UINT32 timeout)
+{
+   s_snmpTimeout = timeout;
+}
+
+/**
+ * Get SNMP timeout
+ */
+UINT32 LIBNXSNMP_EXPORTABLE SnmpGetDefaultTimeout()
+{
+   return s_snmpTimeout;
+}
+
+/**
  * Get value for SNMP variable
  * If szOidStr is not NULL, string representation of OID is used, otherwise -
  * binary representation from oidBinary and dwOidLen
  * Note: buffer size is in bytes
  */
-UINT32 LIBNXSRV_EXPORTABLE SnmpGet(int version, SNMP_Transport *transport,
-                                   const TCHAR *szOidStr, const UINT32 *oidBinary, size_t dwOidLen, void *pValue,
-                                   size_t bufferSize, UINT32 dwFlags)
+UINT32 LIBNXSNMP_EXPORTABLE SnmpGet(int version, SNMP_Transport *transport,
+                                    const TCHAR *szOidStr, const UINT32 *oidBinary, size_t dwOidLen, void *pValue,
+                                    size_t bufferSize, UINT32 dwFlags)
 {
    if (version != transport->getSnmpVersion())
    {
       int v = transport->getSnmpVersion();
       transport->setSnmpVersion(version);
-      DbgPrintf(7, _T("SnmpGet: transport SNMP version %d changed to %d"), v, version);
       UINT32 rc = SnmpGetEx(transport, szOidStr, oidBinary, dwOidLen, pValue, bufferSize, dwFlags, NULL);
       transport->setSnmpVersion(v);
       return rc;
@@ -67,9 +104,9 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpGet(int version, SNMP_Transport *transport,
  * If SG_RAW_RESULT flag given and dataLen is not NULL actial data length will be stored there
  * Note: buffer size is in bytes
  */
-UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
-                                     const TCHAR *szOidStr, const UINT32 *oidBinary, size_t dwOidLen, void *pValue,
-                                     size_t bufferSize, UINT32 dwFlags, UINT32 *dataLen)
+UINT32 LIBNXSNMP_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
+                                      const TCHAR *szOidStr, const UINT32 *oidBinary, size_t dwOidLen, void *pValue,
+                                      size_t bufferSize, UINT32 dwFlags, UINT32 *dataLen)
 {
    SNMP_PDU *pRqPDU, *pRespPDU;
    UINT32 pdwVarName[MAX_OID_LEN], dwResult = SNMP_ERR_SUCCESS;
@@ -86,7 +123,8 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
       if (nameLength == 0)
       {
          InetAddress a = pTransport->getPeerIpAddress();
-         nxlog_write(MSG_OID_PARSE_ERROR, EVENTLOG_ERROR_TYPE, "ssA", szOidStr, _T("SnmpGet"), &a);
+         if (dwFlags & SG_VERBOSE)
+            nxlog_write(s_msgParseError, NXLOG_WARNING, "ssA", szOidStr, _T("SnmpGet"), &a);
          dwResult = SNMP_ERR_BAD_OID;
       }
    }
@@ -99,7 +137,7 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
    if (dwResult == SNMP_ERR_SUCCESS)   // Still no errors
    {
       pRqPDU->bindVariable(new SNMP_Variable(pdwVarName, nameLength));
-      dwResult = pTransport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+      dwResult = pTransport->doRequest(pRqPDU, &pRespPDU, s_snmpTimeout, 3);
 
       // Analyze response
       if (dwResult == SNMP_ERR_SUCCESS)
@@ -159,7 +197,7 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
                         dwResult = SNMP_ERR_NO_OBJECT;
                         break;
                      default:
-                        nxlog_write(MSG_SNMP_UNKNOWN_TYPE, NXLOG_WARNING, "x", pVar->getType());
+                        nxlog_write(s_msgTypeError, NXLOG_WARNING, "x", pVar->getType());
                         dwResult = SNMP_ERR_BAD_TYPE;
                         break;
                   }
@@ -182,7 +220,7 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
       else
       {
          if (dwFlags & SG_VERBOSE)
-            nxlog_write(MSG_SNMP_GET_ERROR, EVENTLOG_ERROR_TYPE, "d", dwResult);
+            nxlog_write(s_msgGetError, EVENTLOG_ERROR_TYPE, "d", dwResult);
       }
    }
 
@@ -193,9 +231,9 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpGetEx(SNMP_Transport *pTransport,
 /**
  * Enumerate multiple values by walking through MIB, starting at given root
  */
-UINT32 LIBNXSRV_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport, const TCHAR *szRootOid,
-                                   UINT32 (* pHandler)(UINT32, SNMP_Variable *, SNMP_Transport *, void *),
-                                   void *pUserArg, BOOL bVerbose)
+UINT32 LIBNXSNMP_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport, const TCHAR *szRootOid,
+                                     UINT32 (* pHandler)(UINT32, SNMP_Variable *, SNMP_Transport *, void *),
+                                     void *pUserArg, BOOL bVerbose)
 {
        if (pTransport == NULL)
                return SNMP_ERR_COMM;
@@ -206,7 +244,7 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport
    if (dwRootLen == 0)
    {
       InetAddress a = pTransport->getPeerIpAddress();
-      nxlog_write(MSG_OID_PARSE_ERROR, EVENTLOG_ERROR_TYPE, "ssA", szRootOid, _T("SnmpWalk"), &a);
+      nxlog_write(s_msgParseError, NXLOG_WARNING, "ssA", szRootOid, _T("SnmpWalk"), &a);
       return SNMP_ERR_BAD_OID;
    }
 
@@ -225,7 +263,7 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport
       SNMP_PDU *pRqPDU = new SNMP_PDU(SNMP_GET_NEXT_REQUEST, (UINT32)InterlockedIncrement(&s_requestId), dwVersion);
       pRqPDU->bindVariable(new SNMP_Variable(pdwName, nameLength));
           SNMP_PDU *pRespPDU;
-      dwResult = pTransport->doRequest(pRqPDU, &pRespPDU, g_snmpTimeout, 3);
+      dwResult = pTransport->doRequest(pRqPDU, &pRespPDU, s_snmpTimeout, 3);
 
       // Analyze response
       if (dwResult == SNMP_ERR_SUCCESS)
@@ -284,7 +322,7 @@ UINT32 LIBNXSRV_EXPORTABLE SnmpWalk(UINT32 dwVersion, SNMP_Transport *pTransport
       else
       {
          if (bVerbose)
-            nxlog_write(MSG_SNMP_GET_ERROR, EVENTLOG_ERROR_TYPE, "d", dwResult);
+            nxlog_write(s_msgGetError, EVENTLOG_ERROR_TYPE, "d", dwResult);
          bRunning = FALSE;
       }
       delete pRqPDU;