I have implemented a SNMP agent by windows snmp api with reference to an article
How to develop a SNMP extension agent DLL[
^]. Several oids must be organized to be a SNMP table. I did it like this:
This class represent a oid.
class VeMIB_ENTRY
{
public:
AsnObjectIdentifier m_asnOid;
VeMIB_ENTRY* m_pMibNext;
VeMIB_ENTRY(VeMIB_ENTRY* pMibNext,UINT unLength,UINT asnOid,...)
{
m_asnOid.idLength = unLength;
m_asnOid.ids = new UINT[unLength];
memcpy(m_asnOid.ids,&asnOid,unLength*sizeof(UINT));
m_pMibNext = pMibNext;
}
VeMIB_ENTRY(VeMIB_ENTRY* pMibNext,UINT unLength,UINT asnOid[])
{
m_asnOid.idLength = unLength;
m_asnOid.ids = new UINT[unLength];
memcpy(m_asnOid.ids,asnOid,unLength*sizeof(UINT));
m_pMibNext = pMibNext;
}
virtual ~VeMIB_ENTRY()
{
delete[] m_asnOid.ids;
}
virtual int GetStorageValue( AsnAny* pasnValue ) {return SNMP_ERRORSTATUS_NOERROR;}
virtual int SetStorageValue( const AsnAny* pasnValue ) {return SNMP_ERRORSTATUS_READONLY;}
private:
VeMIB_ENTRY( const VeMIB_ENTRY& ) {};
VeMIB_ENTRY& operator=( const VeMIB_ENTRY& ) {};
};
class VeNullValue:
public VeMIB_ENTRY
{
public:
VeNullValue(VeMIB_ENTRY *pMibNext,UINT unLength,UINT asnOid,...)
:VeMIB_ENTRY(pMibNext,unLength,&asnOid)
{
}
virtual int GetStorageValue(AsnAny* pasnValue)
{
pasnValue->asnType = ASN_NULL;
return SNMP_ERRORSTATUS_NOERROR;
}
virtual int SetStorageValue( const AsnAny* pasnValue ) {return SNMP_ERRORSTATUS_NOERROR;}
};
class VeEntryValue:
public VeMIB_ENTRY
{
private:
const TCHAR* m_szMsg;
public:
VeEntryValue(VeMIB_ENTRY *pMibNext,UINT unLength,UINT asnOid,...)
:VeMIB_ENTRY(pMibNext,unLength,&asnOid)
{
m_szMsg = _T("entry");
}
virtual int GetStorageValue(AsnAny* pasnValue)
{
pasnValue->asnType = ASN_SEQUENCE;
pasnValue->asnValue.sequence.length = _tcslen(m_szMsg)*sizeof(TCHAR);
pasnValue->asnValue.sequence.stream
= (unsigned char*)SnmpUtilMemAlloc(pasnValue->asnValue.sequence.length);
memcpy(pasnValue->asnValue.string.stream,m_szMsg,pasnValue->asnValue.sequence.length);
pasnValue->asnValue.sequence.dynamic = TRUE;
return SNMP_ERRORSTATUS_NOERROR;
}
virtual int SetStorageValue( const AsnAny* pasnValue ) {return SNMP_ERRORSTATUS_NOERROR;}
};
MIB is organised like this.
UINT g_unMyOIDPrefix[] = {1, 3, 6, 1, 4, 1, 31492};
CMap<AsnObjectIdentifier*,AsnObjectIdentifier*,VeMIB_ENTRY*,VeMIB_ENTRY*> g_VeMIB;
void InitialVeMIB()
{
VeMIB_ENTRY *pMibEntry = NULL;
VeMIB_ENTRY *pMibEntryNext = NULL;
g_VeMIB.InitHashTable(100);
#define ADD_MIB_ITEM(type,length,...) \
pMibEntry = new type(pMibEntryNext,length,##__VA_ARGS__);\
g_VeMIB.SetAt(&(pMibEntry->m_asnOid),pMibEntry);\
pMibEntryNext = pMibEntry
ADD_MIB_ITEM(VeMIB_ENTRY ,7,3,1,1,1,10,1,5);
ADD_MIB_ITEM(VeMIB_ENTRY ,7,3,1,1,1,10,1,4);
ADD_MIB_ITEM(VeMIB_ENTRY ,7,3,1,1,1,10,1,3);
ADD_MIB_ITEM(VeMIB_ENTRY ,1,7,3,1,1,1,10,1,2);
ADD_MIB_ITEM(VeMIB_ENTRY ,7,3,1,1,1,10,1,1);
ADD_MIB_ITEM(VeEntryValue,6,3,1,1,1,10,1);
ADD_MIB_ITEM(VeNullValue,5,3,1,1,1,10);
}
If it is correctly implemented,one can use command line like
snmputil walk localhost public .1.3.6.1.4.1.31492.3.1.1.1.10 or
snmp4j -c -v 2c -Ot localhost .1.3.6.1.4.1.31492.3.1.1.1.10 to query the table. But now i can use command line
snmp4j -c -v 2c -Ot localhost .1.3.6.1.4.1.31492.3.1.1.1.10.1 query the table with an error number 2 returned.
It may also concerned with
SnmpExtensionQuery. Its source code provide as follow.
BOOL SNMP_FUNC_TYPE SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList, AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
{
int nRet = 0;
*pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
*pErrorIndex = 0;
for(UINT i=0;i<pVarBindList->len;i++)
{
*pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
VeMIB_ENTRY* pMIBItem = GetVeMIBItem(&pVarBindList->list[i]);
if (pMIBItem != NULL)
{
switch(bPduType)
{
case SNMP_PDU_GET: *pErrorStatus = pMIBItem->GetStorageValue(&(pVarBindList->list[i].value));
if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)
*pErrorIndex++;
break;
case SNMP_PDU_GETNEXT: *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
if(pMIBItem->m_pMibNext != NULL)
{
SnmpUtilOidFree(&pVarBindList->list[i].name);
SnmpUtilOidCpy(&pVarBindList->list[i].name, &MIB_OidPrefix);
SnmpUtilOidAppend(&pVarBindList->list[i].name, &pMIBItem->m_pMibNext->m_asnOid);
*pErrorStatus = pMIBItem->m_pMibNext->GetStorageValue(&(pVarBindList->list[i].value));
}
else
if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)
*pErrorIndex++;
break;
case SNMP_PDU_SET: *pErrorStatus = pMIBItem->SetStorageValue(&(pVarBindList->list[i].value));
if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)
*pErrorIndex++;
break;
default:
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
*pErrorIndex++;
};
}
else
{
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
*pErrorIndex++;
}
}
return SNMPAPI_NOERROR;
}
How it happens, How to implement an agent width Windows SNMP API for a MIB containing SNMP tables?