Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3882 lines
94 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
mgmtapi.c
Abstract:
SNMP Management API (wrapped around WinSNMP API).
Environment:
User Mode - Win32
Revision History:
05-Feb-1997 DonRyan
Rewrote functions to be wrappers around WinSNMP.
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include Files //
// //
///////////////////////////////////////////////////////////////////////////////
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <wsipx.h>
#include <winsnmp.h>
#include <mgmtapi.h>
#include <oidconv.h>
#include <snmputil.h>
///////////////////////////////////////////////////////////////////////////////
// //
// Private Definitions //
// //
///////////////////////////////////////////////////////////////////////////////
typedef struct _SNMP_MGR_SESSION {
SOCKET UnusedSocket; // WARNING: Previous versions of the
struct sockaddr UnusedDestAddr; // MGMTAPI.H header file exposed the
LPSTR UnusedCommunity; // SNMP_MGR_SESSION structure which
INT UnusedTimeout; // unfortunately encouraged people to
INT UnusedNumRetries; // muck with it. Since this structure
AsnInteger UnusedRequestId; // has now changed we must protect it.
CRITICAL_SECTION SessionLock; // multiple threads may share session
HSNMP_SESSION hSnmpSession; // handle to winsnmp session
HSNMP_ENTITY hAgentEntity; // handle to agent entity
HSNMP_ENTITY hManagerEntity; // handle to manager entity
HSNMP_CONTEXT hViewContext; // handle to view context
HSNMP_PDU hPdu; // handle to snmp pdu
HSNMP_VBL hVbl; // handle to snmp pdu
HWND hWnd; // handle to window
smiINT32 nPduType; // current pdu type
smiINT32 nRequestId; // current request id
smiINT32 nErrorIndex; // error index from pdu
smiINT32 nErrorStatus; // error status from pdu
smiINT32 nLastError; // last system error
SnmpVarBindList * pVarBindList; // pointer to varbind list
} SNMP_MGR_SESSION, *PSNMP_MGR_SESSION;
typedef struct _TRAP_LIST_ENTRY {
LIST_ENTRY Link; // linked-list link
AsnObjectIdentifier EnterpriseOID; // generating enterprise
AsnNetworkAddress AgentAddress; // generating agent addr
AsnNetworkAddress SourceAddress; // generating network addr
AsnInteger nGenericTrap; // generic trap type
AsnInteger nSpecificTrap; // enterprise specific type
AsnOctetString Community; // generating community
AsnTimeticks TimeStamp; // time stamp
SnmpVarBindList VarBindList; // variable bindings
} TRAP_LIST_ENTRY, * PTRAP_LIST_ENTRY;
#define IPADDRLEN 4
#define IPXADDRLEN 10
#define MAXENTITYSTRLEN 128
#define MINVARBINDLEN 2
#define SYSUPTIMEINDEX 0
#define SNMPTRAPOIDINDEX 1
#define DEFAULT_ADDRESS_IP "127.0.0.1"
#define DEFAULT_ADDRESS_IPX "00000000.000000000000"
#define NOTIFICATION_CLASS "MGMTAPI Notification Class"
#define WM_WSNMP_INCOMING (WM_USER + 1)
#define WM_WSNMP_DONE (WM_USER + 2)
#define WSNMP_FAILED(s) ((s) == SNMPAPI_FAILURE)
#define WSNMP_SUCCEEDED(s) ((s) != SNMPAPI_FAILURE)
#define WSNMP_ASSERT(s) ASSERT((s))
///////////////////////////////////////////////////////////////////////////////
// //
// Global Variables //
// //
///////////////////////////////////////////////////////////////////////////////
HINSTANCE g_hDll; // module handle
HANDLE g_hTrapEvent = NULL; // trap event handle
HANDLE g_hTrapThread = NULL; // trap thread handle
HANDLE g_hTrapRegisterdEvent = NULL; // event to sync. SnmpMgrTrapListen
BOOL g_fIsSnmpStarted = FALSE; // indicates winsnmp inited
BOOL g_fIsSnmpListening = FALSE; // indicates trap thread on
BOOL g_fIsTrapRegistered = FALSE; // indicates trap registered
DWORD g_dwRequestId = 1; // unique pdu request id
LIST_ENTRY g_IncomingTraps; // incoming trap queue
CRITICAL_SECTION g_GlobalLock; // process resource lock
SNMP_MGR_SESSION g_TrapSMS; // process trap session
DWORD g_cSnmpMgmtRef = 0; // ref. count on using mgmtapi
///////////////////////////////////////////////////////////////////////////////
// //
// Private Procedures //
// //
///////////////////////////////////////////////////////////////////////////////
DWORD
GetRequestId(
)
/*++
Routine Description:
Retrieve next global request id.
Arguments:
None.
Return Values:
Returns request id.
--*/
{
DWORD dwRequestId;
// obtain exclusive access to request id
EnterCriticalSection(&g_GlobalLock);
// obtain copy of request id
dwRequestId = g_dwRequestId++;
// obtain exclusive access to request id
LeaveCriticalSection(&g_GlobalLock);
return dwRequestId;
}
BOOL
TransferVb(
PSNMP_MGR_SESSION pSMS,
SnmpVarBind * pVarBind
)
/*++
Routine Description:
Transfer VarBind structure to WinSNMP structure.
Arguments:
pSMS - pointer to mgmtapi session structure.
pVarBind - pointer to varbind to transfer.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
SNMPAPI_STATUS status;
smiVALUE tmpValue;
smiOID tmpOID;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// validate pointers
if ((pVarBind != NULL) &&
(pVarBind->name.ids != NULL) &&
(pVarBind->name.idLength != 0)) {
// re-init
fOk = TRUE;
// transfer oid information
tmpOID.len = pVarBind->name.idLength;
tmpOID.ptr = pVarBind->name.ids;
// only initialize value if set
if (pSMS->nPduType == SNMP_PDU_SET) {
// syntax values are equivalent
tmpValue.syntax = (smiINT32)(BYTE)pVarBind->value.asnType;
// determine type
switch (pVarBind->value.asnType) {
case ASN_INTEGER32:
// transfer signed int
tmpValue.value.sNumber = pVarBind->value.asnValue.number;
break;
case ASN_UNSIGNED32:
case ASN_COUNTER32:
case ASN_GAUGE32:
case ASN_TIMETICKS:
// transfer unsigned int
tmpValue.value.uNumber = pVarBind->value.asnValue.unsigned32;
break;
case ASN_COUNTER64:
// transfer 64-bit counter
tmpValue.value.hNumber.lopart =
pVarBind->value.asnValue.counter64.LowPart;
tmpValue.value.hNumber.hipart =
pVarBind->value.asnValue.counter64.HighPart;
break;
case ASN_OPAQUE:
case ASN_IPADDRESS:
case ASN_OCTETSTRING:
case ASN_BITS:
// transfer octet string
tmpValue.value.string.len =
pVarBind->value.asnValue.string.length;
tmpValue.value.string.ptr =
pVarBind->value.asnValue.string.stream;
break;
case ASN_OBJECTIDENTIFIER:
// transfer object id
tmpValue.value.oid.len =
pVarBind->value.asnValue.object.idLength;
tmpValue.value.oid.ptr =
pVarBind->value.asnValue.object.ids;
break;
case ASN_NULL:
case SNMP_EXCEPTION_NOSUCHOBJECT:
case SNMP_EXCEPTION_NOSUCHINSTANCE:
case SNMP_EXCEPTION_ENDOFMIBVIEW:
// initialize empty byte
tmpValue.value.empty = 0;
break;
default:
// failure
fOk = FALSE;
break;
}
}
if (fOk) {
// register varbind
status = SnmpSetVb(
pSMS->hVbl,
0, // index
&tmpOID,
(pSMS->nPduType == SNMP_PDU_SET)
? &tmpValue
: NULL
);
// validate return code
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetVb returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// failure
fOk = FALSE;
}
}
}
return fOk;
}
BOOL
AllocateVbl(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Transfer VarBindList structure to WinSNMP structure.
Arguments:
pSMS - pointer to mgmtapi session structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
SNMPAPI_STATUS status;
SnmpVarBind * pVarBind;
DWORD cVarBind;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// validate parameters
WSNMP_ASSERT(pSMS->pVarBindList != NULL);
WSNMP_ASSERT(pSMS->pVarBindList->len != 0);
WSNMP_ASSERT(pSMS->pVarBindList->list != NULL);
// allocate resources for variable bindings list
pSMS->hVbl = SnmpCreateVbl(pSMS->hSnmpSession, NULL, NULL);
// validate varbind handle
if (WSNMP_SUCCEEDED(pSMS->hVbl)) {
// re-init
fOk = TRUE;
// initialize varbind pointer
pVarBind = pSMS->pVarBindList->list;
// initialize varbind count
cVarBind = pSMS->pVarBindList->len;
// process each varbind
while (fOk && cVarBind--) {
// transfer variable binding
fOk = TransferVb(pSMS, pVarBind++);
}
if (!fOk) {
// release varbind list handle
status = SnmpFreeVbl(pSMS->hVbl);
// validate return code
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpFreeVbl returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
}
// re-initialize
pSMS->hVbl = (HSNMP_VBL)NULL;
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpCreateVbl returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
}
return fOk;
}
BOOL
FreeVbl(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Cleanup VarBind resources from WinSNMP structure.
Arguments:
pSMS - pointer to mgmtapi session structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = TRUE;
SNMPAPI_STATUS status;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// validate handle
if (pSMS->hVbl != (HSNMP_VBL)NULL) {
// actually release vbl handle
status = SnmpFreeVbl(pSMS->hVbl);
// validate return code
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpFreeVbl returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// failure
fOk = FALSE;
}
// re-initialize handle
pSMS->hVbl = (HSNMP_VBL)NULL;
}
return fOk;
}
BOOL
AllocatePdu(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Initialize session structure for sending request.
Arguments:
pSMS - pointer to mgmtapi session structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// transfer varbinds
if (AllocateVbl(pSMS)) {
// grab next shared request id
pSMS->nRequestId = GetRequestId();
// create request pdu
pSMS->hPdu = SnmpCreatePdu(
pSMS->hSnmpSession,
pSMS->nPduType,
pSMS->nRequestId,
0, // errorStatus
0, // errorIndex
pSMS->hVbl
);
// validate return status
if (WSNMP_SUCCEEDED(pSMS->hPdu)) {
// success
fOk = TRUE;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpCreatePdu returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// free resources
FreeVbl(pSMS);
}
}
return fOk;
}
BOOL
FreePdu(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Cleanup session structure after processing response.
Arguments:
pSMS - pointer to mgmtapi session structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = TRUE;
SNMPAPI_STATUS status;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// validate handle
if (pSMS->hPdu != (HSNMP_PDU)NULL) {
// free vbl
FreeVbl(pSMS);
// actually release pdu handle
status = SnmpFreePdu(pSMS->hPdu);
// validate return code
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpFreePdu returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// failure
fOk = FALSE;
}
// re-initialize handle
pSMS->hPdu = (HSNMP_PDU)NULL;
}
return fOk;
}
BOOL
CopyOid(
AsnObjectIdentifier * pDstOID,
smiLPOID pSrcOID
)
/*++
Routine Description:
Copies object identifier from WinSNMP format to MGMTAPI format.
Arguments:
pDstOID - points to MGMTAPI structure to receive OID.
pSrcOID - points to WinSNMP structure to copy.
Return Values:
Returns true if successful.
Note: if pSrcOID is valid, its contents will be freed regardless of
return value
--*/
{
BOOL fOk = FALSE;
// validate pointers
WSNMP_ASSERT(pDstOID != NULL);
WSNMP_ASSERT(pSrcOID != NULL);
WSNMP_ASSERT(pSrcOID->len != 0);
WSNMP_ASSERT(pSrcOID->ptr != NULL);
// store the number of subids
pDstOID->idLength = pSrcOID->len;
// allocate memory for subidentifiers
pDstOID->ids = SnmpUtilMemAlloc(pDstOID->idLength * sizeof(DWORD));
// validate pointer
if (pDstOID->ids != NULL) {
// transfer memory
memcpy(pDstOID->ids,
pSrcOID->ptr,
pDstOID->idLength * sizeof(DWORD)
);
// success
fOk = TRUE;
}
// now release memory for original oid
SnmpFreeDescriptor(SNMP_SYNTAX_OID, (smiLPOPAQUE)pSrcOID);
return fOk;
}
BOOL
CopyOctets(
AsnOctetString * pDstOctets,
smiLPOCTETS pSrcOctets
)
/*++
Routine Description:
Copies octet string from WinSNMP format to MGMTAPI format.
Arguments:
pDstOctets - points to MGMTAPI structure to receive octets.
pSrcOctets - points to WinSNMP structure to copy.
Return Values:
Returns true if successful.
Note: if pSrcOctets is valid, its contents will be freed regardless of
return value
--*/
{
BOOL fOk = FALSE;
SNMPAPI_STATUS status;
// validate pointers
WSNMP_ASSERT(pDstOctets != NULL);
WSNMP_ASSERT(pSrcOctets != NULL);
// it is legitimate that
// 1. pSrcOctets->len == 0
// 2. pSrcOctets->ptr == NULL
if (pSrcOctets->len == 0 || pSrcOctets->ptr == NULL)
{
pDstOctets->dynamic = FALSE;
pDstOctets->length = 0;
pDstOctets->stream = NULL;
fOk = TRUE;
}
else
{
// allocate memory for octet string
pDstOctets->stream = SnmpUtilMemAlloc(pSrcOctets->len);
// validate pointer
if (pDstOctets->stream != NULL) {
// octet string allocated
pDstOctets->dynamic = TRUE;
// store the number of bytes
pDstOctets->length = pSrcOctets->len;
// transfer memory
memcpy(pDstOctets->stream,
pSrcOctets->ptr,
pDstOctets->length
);
// success
fOk = TRUE;
}
}
// now release memory for original string
SnmpFreeDescriptor(SNMP_SYNTAX_OCTETS, (smiLPOPAQUE)pSrcOctets);
return fOk;
}
CopyVb(
PSNMP_MGR_SESSION pSMS,
DWORD iVarBind,
SnmpVarBind * pVarBind
)
/*++
Routine Description:
Copy variable binding from WinSNMP structure to MGMTAPI structure.
Arguments:
pSMS - pointer to mgmtapi session structure.
iVarBind - index of varbind structure to copy.
pVarBind - pointer to varbind structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
SNMPAPI_STATUS status;
smiOID tmpOID;
smiVALUE tmpValue;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
WSNMP_ASSERT(pVarBind != NULL);
// attempt to retrieve varbind data from winsnmp structure
status = SnmpGetVb(pSMS->hVbl, iVarBind, &tmpOID, &tmpValue);
// validate return code
if (WSNMP_SUCCEEDED(status)) {
// transfer object identifier value
fOk = CopyOid(&pVarBind->name, &tmpOID);
// syntax values are equivalent
pVarBind->value.asnType = (BYTE)(smiINT32)tmpValue.syntax;
// determine syntax
switch (tmpValue.syntax) {
case SNMP_SYNTAX_INT32:
// transfer signed int
pVarBind->value.asnValue.number = tmpValue.value.sNumber;
break;
case SNMP_SYNTAX_UINT32:
case SNMP_SYNTAX_CNTR32:
case SNMP_SYNTAX_GAUGE32:
case SNMP_SYNTAX_TIMETICKS:
// transfer unsigned int
pVarBind->value.asnValue.unsigned32 = tmpValue.value.uNumber;
break;
case SNMP_SYNTAX_CNTR64:
// transfer 64-bit counter
pVarBind->value.asnValue.counter64.LowPart =
tmpValue.value.hNumber.lopart;
pVarBind->value.asnValue.counter64.HighPart =
tmpValue.value.hNumber.hipart;
break;
case SNMP_SYNTAX_OPAQUE:
case SNMP_SYNTAX_IPADDR:
case SNMP_SYNTAX_OCTETS:
case SNMP_SYNTAX_BITS:
// transfer octet string
if (!CopyOctets(&pVarBind->value.asnValue.string,
&tmpValue.value.string)) {
// re-initialize
pVarBind->value.asnType = ASN_NULL;
// failure
fOk = FALSE;
}
break;
case SNMP_SYNTAX_OID:
// transfer object identifier
if (!CopyOid(&pVarBind->value.asnValue.object,
&tmpValue.value.oid)) {
// re-initialize
pVarBind->value.asnType = ASN_NULL;
// failure
fOk = FALSE;
}
break;
case SNMP_SYNTAX_NULL:
case SNMP_SYNTAX_NOSUCHOBJECT:
case SNMP_SYNTAX_NOSUCHINSTANCE:
case SNMP_SYNTAX_ENDOFMIBVIEW:
break; // do nothing...
default:
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpGetVb returned invalid type.\n"
));
// re-initialize
pVarBind->value.asnType = ASN_NULL;
// failure
fOk = FALSE;
break;
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpGetVb returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
}
return fOk;
}
BOOL
CopyVbl(
PSNMP_MGR_SESSION pSMS,
SnmpVarBindList * pVarBindList
)
/*++
Routine Description:
Copy variable bindings from WinSNMP structure to MGMTAPI structure.
Arguments:
pSMS - pointer to mgmtapi session structure.
pVarBindList - pointer to varbind list structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = TRUE;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
WSNMP_ASSERT(pVarBindList != NULL);
// initialize
pVarBindList->len = 0;
pVarBindList->list = NULL;
// validate varbind list handle
if (pSMS->hVbl != (HSNMP_VBL)NULL) {
// determine number of varbinds
pVarBindList->len = SnmpCountVbl(pSMS->hVbl);
// validate number of varbinds
if (WSNMP_SUCCEEDED(pVarBindList->len)) {
// allocate memory for varbinds
pVarBindList->list = SnmpUtilMemAlloc(
pVarBindList->len *
sizeof(SnmpVarBind)
);
// validate pointer
if (pVarBindList->list != NULL) {
DWORD cVarBind = 1;
SnmpVarBind * pVarBind;
// save pointer to varbinds
pVarBind = pVarBindList->list;
// process varbinds in the list
while (fOk && (cVarBind <= pVarBindList->len)) {
// copy varbind from winsnmp to mgmtapi
fOk = CopyVb(pSMS, cVarBind++, pVarBind++);
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Could not allocate VBL.\n"
));
// re-initialize
pVarBindList->len = 0;
// failure
fOk = FALSE;
}
} else if (SnmpGetLastError(pSMS->hSnmpSession) != SNMPAPI_NOOP) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpCountVbl returned %s.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// re-initialize
pVarBindList->len = 0;
// failure
fOk = FALSE;
}
}
if (!fOk) {
// cleanup any varbinds allocated
SnmpUtilVarBindListFree(pVarBindList);
}
return fOk;
}
BOOL
ParseVbl(
PSNMP_MGR_SESSION pSMS,
PTRAP_LIST_ENTRY pTLE
)
/*++
Routine Description:
Parse varbind list for trap-related varbinds.
Arguments:
pSMS - pointer to MGMTAPI session structure.
pTLE - pointer to trap list entry.
Return Values:
Returns true if successful.
--*/
{
SnmpVarBind * pVarBind;
AsnObjectIdentifier * pOID;
AsnNetworkAddress * pAgentAddress = NULL;
AsnObjectIdentifier * pEnterpriseOID = NULL;
// object identifiers to convert snmpv2 trap format
static UINT _sysUpTime[] = { 1, 3, 6, 1, 2, 1, 1, 3 };
static UINT _snmpTrapOID[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1 };
static UINT _snmpAddress[] = { 1, 3, 6, 1, 3, 1057, 1 };
static UINT _snmpTrapEnterprise[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 3 };
static UINT _snmpTraps[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
static AsnObjectIdentifier sysUpTime = DEFINE_OID(_sysUpTime);
static AsnObjectIdentifier snmpTrapOID = DEFINE_OID(_snmpTrapOID);
static AsnObjectIdentifier snmpAddress = DEFINE_OID(_snmpAddress);
static AsnObjectIdentifier snmpTrapEnterprise = DEFINE_OID(_snmpTrapEnterprise);
static AsnObjectIdentifier snmpTraps = DEFINE_OID(_snmpTraps);
// validate pointers
WSNMP_ASSERT(pSMS != NULL);
WSNMP_ASSERT(pTLE != NULL);
// validate vbl have minimum entries
if (pTLE->VarBindList.len >= MINVARBINDLEN) {
// point to sysUpTime varbind structure
pVarBind = &pTLE->VarBindList.list[SYSUPTIMEINDEX];
// verify variable is sysUpTime
if ((pVarBind->value.asnType == ASN_TIMETICKS) &&
!SnmpUtilOidNCmp(&pVarBind->name,
&sysUpTime,
sysUpTime.idLength)) {
// transfer sysUpTime value to trap entry
pTLE->TimeStamp = pVarBind->value.asnValue.ticks;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Could not find sysUpTime.\n"
));
goto cleanup; // bail...
}
// see if any additional varbinds present
if (pTLE->VarBindList.len > MINVARBINDLEN) {
// point to snmpTrapEnterprise varbind structure (maybe)
pVarBind = &pTLE->VarBindList.list[pTLE->VarBindList.len - 1];
// verify variable is snmpTrapEnterprise
if ((pVarBind->value.asnType == ASN_OBJECTIDENTIFIER) &&
!SnmpUtilOidNCmp(&pVarBind->name,
&snmpTrapEnterprise,
snmpTrapEnterprise.idLength)) {
// transfer enterprise oid to list entry
pTLE->EnterpriseOID = pVarBind->value.asnValue.object;
// store enterprise oid for later
pEnterpriseOID = &pTLE->EnterpriseOID;
// modify type to avoid deallocation
pVarBind->value.asnType = ASN_NULL;
} else {
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: Could not find snmpTrapEnterprise.\n"
));
}
}
// see if the agent address is present
if (pTLE->VarBindList.len > MINVARBINDLEN+1) {
// point to snmpAddress varbind structure (maybe)
pVarBind = &pTLE->VarBindList.list[pTLE->VarBindList.len - 2];
// verify variable is snmpAddress
if ((pVarBind->value.asnType == SNMP_SYNTAX_IPADDR) &&
!SnmpUtilOidNCmp(&pVarBind->name,
&snmpAddress,
snmpAddress.idLength)) {
// transfer agent address oid to list entry
pTLE->AgentAddress = pVarBind->value.asnValue.address;
// store agent address for later
pAgentAddress = &pTLE->AgentAddress;
// modify type to avoid deallocation
pVarBind->value.asnType = ASN_NULL;
} else {
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: Could not find snmpAddress.\n"
));
}
}
// point to snmpTrapOID varbind structure
pVarBind = &pTLE->VarBindList.list[SNMPTRAPOIDINDEX];
// verify variable is snmpTrapOID
if ((pVarBind->value.asnType == ASN_OBJECTIDENTIFIER) &&
!SnmpUtilOidNCmp(&pVarBind->name,
&snmpTrapOID,
snmpTrapOID.idLength)) {
// retrieve pointer to oid
pOID = &pVarBind->value.asnValue.object;
// check for generic trap
if (!SnmpUtilOidNCmp(pOID,
&snmpTraps,
snmpTraps.idLength)) {
// validate size is one greater than root
if (pOID->idLength == (snmpTraps.idLength + 1)) {
// retrieve trap id
// --ft:10/01/98 (bug #231344): WINSNMP gives up the V2 syntax => pOID->ids[snmpTraps.idLength] = [1..6]
// --ft:10/01/98 (bug #231344): as MGMTAPI turns back to V1, we need to decrement this value.
pTLE->nGenericTrap = (pOID->ids[snmpTraps.idLength])-1;
// re-initialize
pTLE->nSpecificTrap = 0;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Invalid snmpTrapOID.\n"
));
goto cleanup; // bail...
}
// check for specific trap
} else if ((pEnterpriseOID != NULL) &&
!SnmpUtilOidNCmp(pOID,
pEnterpriseOID,
pEnterpriseOID->idLength)) {
// validate size is two greater than root
if (pOID->idLength == (pEnterpriseOID->idLength + 2)) {
// validate separator sub-identifier
WSNMP_ASSERT(pOID->ids[pEnterpriseOID->idLength] == 0);
// retrieve trap id
pTLE->nSpecificTrap = pOID->ids[pEnterpriseOID->idLength + 1];
// re-initialize
pTLE->nGenericTrap = SNMP_GENERICTRAP_ENTERSPECIFIC;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Invalid snmpTrapOID.\n"
));
goto cleanup; // bail...
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Could not identify snmpTrapOID.\n"
));
goto cleanup; // bail...
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Could not find snmpTrapOID.\n"
));
goto cleanup; // bail...
}
// check for enterprise oid
if (pEnterpriseOID != NULL) {
// release snmpTrapEnterprise varbind structure
SnmpUtilVarBindFree(&pTLE->VarBindList.list[pTLE->VarBindList.len - 1]);
// decrement the list length as the last varbind was freed
pTLE->VarBindList.len--;
}
// check for agent address
if (pAgentAddress != NULL) {
// release snmpAgentAddress varbind structure
SnmpUtilVarBindFree(&pTLE->VarBindList.list[pTLE->VarBindList.len - 1]);
// decrement the list length as the last varbind was again freed
pTLE->VarBindList.len--;
}
// release sysUpTime varbind structure
SnmpUtilVarBindFree(&pTLE->VarBindList.list[SYSUPTIMEINDEX]);
// release snmpTrapOID varbind structure
SnmpUtilVarBindFree(&pTLE->VarBindList.list[SNMPTRAPOIDINDEX]);
// subtract released varbinds
pTLE->VarBindList.len -= MINVARBINDLEN;
// check if all varbinds freed
if (pTLE->VarBindList.len == 0) {
// release memory for list
SnmpUtilMemFree(pTLE->VarBindList.list);
// re-initialize
pTLE->VarBindList.list = NULL;
} else {
// shift varbind list up two spaces
memmove((LPBYTE)(pTLE->VarBindList.list),
(LPBYTE)(pTLE->VarBindList.list + MINVARBINDLEN),
(pTLE->VarBindList.len * sizeof(SnmpVarBind))
);
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Too few subidentifiers.\n"
));
}
// success
return TRUE;
cleanup:
// failure
return FALSE;
}
BOOL
FreeTle(
PTRAP_LIST_ENTRY pTLE
)
/*++
Routine Description:
Release memory used for trap entry.
Arguments:
pTLE - pointer to trap list entry.
Return Values:
Returns true if successful.
--*/
{
// validate pointer
WSNMP_ASSERT(pTLE != NULL);
// release memory for enterprise oid if necessary
SnmpUtilOidFree(&pTLE->EnterpriseOID);
// release memory for AgentAddress if necessary
SnmpUtilOctetsFree(&pTLE->AgentAddress); // AgentAddress is a AsnOctetString type
// release memory for SourceAddress if necessary
SnmpUtilOctetsFree(&pTLE->SourceAddress); // SourceAddress is a AsnOctetString type
// release memory for community string if necessary
SnmpUtilMemFree(pTLE->Community.stream);
// release memory used in varbind list if necessary
SnmpUtilVarBindListFree(&pTLE->VarBindList);
// release list entry
SnmpUtilMemFree(pTLE);
return TRUE;
}
BOOL
AllocateTle(
PSNMP_MGR_SESSION pSMS,
PTRAP_LIST_ENTRY * ppTLE,
HSNMP_ENTITY hAgentEntity,
HSNMP_CONTEXT hViewContext
)
/*++
Routine Description:
Allocate memory for trap entry.
Arguments:
pSMS - pointer to MGMTAPI session structure.
ppTLE - pointer to pointer to trap list entry.
hAgentEntity - handle to agent sending trap.
hViewContext - handle to view context of trap.
Return Values:
Returns true if successful.
--*/
{
PTRAP_LIST_ENTRY pTLE;
SNMPAPI_STATUS status;
smiOCTETS CommunityStr;
CHAR SourceStrAddr[MAXENTITYSTRLEN+1];
struct sockaddr SourceSockAddr;
// validate pointers
WSNMP_ASSERT(pSMS != NULL);
WSNMP_ASSERT(ppTLE != NULL);
// allocate memory from list entry
pTLE = SnmpUtilMemAlloc(sizeof(TRAP_LIST_ENTRY));
// validate pointer
if (pTLE == NULL) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Could not allocate trap entry.\n"
));
return FALSE; // bail...
}
// initialize
*ppTLE = NULL;
// copy varbinds to trap list entry
if (!CopyVbl(pSMS, &pTLE->VarBindList)) {
goto cleanup; // bail...
}
// parse trap-related varbinds
if (!ParseVbl(pSMS, pTLE)) {
goto cleanup; // bail...
}
// check if source address is specified
if (hAgentEntity != (HSNMP_ENTITY)NULL) {
// convert addr to string
status = SnmpEntityToStr(
hAgentEntity,
sizeof(SourceStrAddr),
SourceStrAddr
);
// validate error code
if (WSNMP_SUCCEEDED(status)) {
DWORD AddrLen = 0;
LPBYTE AddrPtr = NULL;
// convert string to socket address structure
if (! SnmpSvcAddrToSocket(SourceStrAddr, &SourceSockAddr))
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Ignoring invalid address.\n"
));
goto cleanup; // bail...
}
// validate address family
if (SourceSockAddr.sa_family == AF_INET) {
// assign ip values
AddrLen = IPADDRLEN;
AddrPtr = (LPBYTE)&(((struct sockaddr_in *)
(&SourceSockAddr))->sin_addr);
} else if (SourceSockAddr.sa_family == AF_IPX) {
// assign ipx values
AddrLen = IPXADDRLEN;
AddrPtr = (LPBYTE)&(((struct sockaddr_ipx *)
(&SourceSockAddr))->sa_netnum);
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Ignoring invalid address.\n"
));
goto cleanup; // bail...
}
// allocate address to return (if specified)
pTLE->SourceAddress.stream = SnmpUtilMemAlloc(AddrLen);
// validate pointer
if (pTLE->SourceAddress.stream != NULL) {
// initialize length values
pTLE->SourceAddress.length = AddrLen;
pTLE->SourceAddress.dynamic = TRUE;
// transfer agent address information
memcpy(pTLE->SourceAddress.stream, AddrPtr, AddrLen);
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpEntityToStr returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
goto cleanup; // bail...
}
}
// check if community specified
if (hViewContext != (HSNMP_CONTEXT)NULL) {
// convert agent entity to string
status = SnmpContextToStr(hViewContext, &CommunityStr);
// validate error code
if (WSNMP_SUCCEEDED(status)) {
// copy octet string, memory allocated in CommunityStr is also freed
CopyOctets(&pTLE->Community, &CommunityStr);
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpContextToStr returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
goto cleanup; // bail...
}
}
// transfer
*ppTLE = pTLE;
// success
return TRUE;
cleanup:
// release
FreeTle(pTLE);
// failure
return FALSE;
}
BOOL
NotificationCallback(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Callback for processing notification messages.
Arguments:
pSMS - pointer to mgmtapi session structure.
Return Values:
Returns true if processing finished.
--*/
{
BOOL fDone = TRUE;
SNMPAPI_STATUS status;
HSNMP_ENTITY hAgentEntity = (HSNMP_ENTITY)NULL;
HSNMP_ENTITY hManagerEntity = (HSNMP_ENTITY)NULL;
HSNMP_CONTEXT hViewContext = (HSNMP_CONTEXT)NULL;
smiINT32 nPduType;
smiINT32 nRequestId;
// validate pointer
WSNMP_ASSERT(pSMS != NULL);
// retrieve message
status = SnmpRecvMsg(
pSMS->hSnmpSession,
&hAgentEntity,
&hManagerEntity,
&hViewContext,
&pSMS->hPdu
);
// validate return code
if (WSNMP_SUCCEEDED(status)) {
// retrieve pdu data
status = SnmpGetPduData(
pSMS->hPdu,
&nPduType,
&nRequestId,
&pSMS->nErrorStatus,
&pSMS->nErrorIndex,
&pSMS->hVbl
);
// validate return code
if (WSNMP_SUCCEEDED(status)) {
// process reponse to request
if (nPduType == SNMP_PDU_RESPONSE) {
// validate context information
if ((pSMS->nRequestId == nRequestId) &&
(pSMS->hViewContext == hViewContext) &&
(pSMS->hAgentEntity == hAgentEntity) &&
(pSMS->hManagerEntity == hManagerEntity)) {
// validate returned error status
if (pSMS->nErrorStatus == SNMP_ERROR_NOERROR) {
SnmpVarBindList VarBindList;
// copy variable binding list
if (CopyVbl(pSMS, &VarBindList)) {
// release existing varbind list
SnmpUtilVarBindListFree(pSMS->pVarBindList);
// manually copy new varbind list
*pSMS->pVarBindList = VarBindList;
} else {
// modify last error status
pSMS->nLastError = SNMPAPI_ALLOC_ERROR;
}
}
} else {
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: Ignoring invalid context.\n"
));
// continue
fDone = FALSE;
}
} else if (nPduType == SNMP_PDU_TRAP) {
PTRAP_LIST_ENTRY pTLE;
// allocate trap list entry (transfers varbinds etc.)
if (AllocateTle(pSMS, &pTLE, hAgentEntity, hViewContext)) {
// obtain exclusive access
EnterCriticalSection(&g_GlobalLock);
// insert new trap into the incoming queue
InsertTailList(&g_IncomingTraps, &pTLE->Link);
// alert user
SetEvent(g_hTrapEvent);
// release exclusive access
LeaveCriticalSection(&g_GlobalLock);
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Ignoring invalid pdu type %d.\n",
nPduType
));
// continue
fDone = FALSE;
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpGetPduData returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// retrieve last error status from winsnmp
pSMS->nLastError = SnmpGetLastError(pSMS->hSnmpSession);
}
// release temporary entity
SnmpFreeEntity(hAgentEntity);
// release temporary entity
SnmpFreeEntity(hManagerEntity);
// release temporary context
SnmpFreeContext(hViewContext);
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpRecvMsg returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// retrieve last error status from winsnmp
pSMS->nLastError = SnmpGetLastError(pSMS->hSnmpSession);
}
// release pdu
FreePdu(pSMS);
return fDone;
}
LRESULT
CALLBACK
NotificationWndProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
Callback that processes WinSNMP notifications.
Arguments:
hWnd - window handle.
uMsg - message identifier.
wParam - first message parameter.
lParam - second message parameter.
Return Values:
The return value is the result of the message processing and
depends on the message sent.
--*/
{
// check for winsnmp notification and transport timeout
if (uMsg == WM_WSNMP_INCOMING && wParam == SNMPAPI_TL_TIMEOUT) {
PSNMP_MGR_SESSION pSMS;
// retrieve mgmtapi session pointer from window
pSMS = (PSNMP_MGR_SESSION)GetWindowLongPtr(hWnd, 0);
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// translate winsnmp error to mgmtapi error
pSMS->nLastError = SNMP_MGMTAPI_TIMEOUT;
// post message to break out of message pump
PostMessage(pSMS->hWnd, WM_WSNMP_DONE, (WPARAM)0, (LPARAM)0);
return (LRESULT)0;
}
// check for winsnmp notification
else if (uMsg == WM_WSNMP_INCOMING) {
PSNMP_MGR_SESSION pSMS;
// retrieve mgmtapi session pointer from window
pSMS = (PSNMP_MGR_SESSION)GetWindowLongPtr(hWnd, 0);
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// process notification message
if (NotificationCallback(pSMS)) {
// post message to break out of message pump
PostMessage(pSMS->hWnd, WM_WSNMP_DONE, (WPARAM)0, (LPARAM)0);
}
return (LRESULT)0;
} else {
// forward all other messages to windows
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
BOOL
RegisterNotificationClass(
)
/*++
Routine Description:
Register notification class for sessions.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk;
WNDCLASS wc;
// initialize notification window class
wc.lpfnWndProc = NotificationWndProc;
wc.lpszClassName = NOTIFICATION_CLASS;
wc.lpszMenuName = NULL;
wc.hInstance = g_hDll;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.cbWndExtra = sizeof(PSNMP_MGR_SESSION);
wc.cbClsExtra = 0;
wc.style = 0;
// register class
fOk = RegisterClass(&wc);
if (!fOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: RegisterClass returned %d.\n",
GetLastError()
));
}
return fOk;
}
BOOL
UnregisterNotificationClass(
)
/*++
Routine Description:
Unregister notification class.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk;
// unergister notification window class
fOk = UnregisterClass(NOTIFICATION_CLASS, g_hDll);
if (!fOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: UnregisterClass returned %d.\n",
GetLastError()
));
}
return fOk;
}
BOOL
StartSnmpIfNecessary(
)
/*++
Routine Description:
Initialize WinSNMP DLL if necessary.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk;
// serialize access to startup code
EnterCriticalSection(&g_GlobalLock);
// see if already started
if (g_fIsSnmpStarted != TRUE) {
SNMPAPI_STATUS status;
// initialize start params
smiUINT32 nMajorVersion = 0;
smiUINT32 nMinorVersion = 0;
smiUINT32 nLevel = 0;
smiUINT32 nTranslateMode = 0;
smiUINT32 nRetransmitMode = 0;
// start winsnmp
status = SnmpStartup(
&nMajorVersion,
&nMinorVersion,
&nLevel,
&nTranslateMode,
&nRetransmitMode
);
// validate return code
if (WSNMP_SUCCEEDED(status)) {
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: SnmpStartup succeeded:\n"
"MGMTAPI:\tnMajorVersion = %d\n"
"MGMTAPI:\tnMinorVersion = %d\n"
"MGMTAPI:\tnLevel = %d\n"
"MGMTAPI:\tnTranslateMode = %d\n"
"MGMTAPI:\tnRetransmitMode = %d\n",
nMajorVersion,
nMinorVersion,
nLevel,
nTranslateMode,
nRetransmitMode
));
// allocate global trap available event
if ((g_hTrapEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: CreateEvent returned %d.\n",
GetLastError()
));
// failure
goto cleanup;
}
// allocate global event to sync. SnmpMgrTrapListen
if ((g_hTrapRegisterdEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) ==NULL)
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: CreateEvent returned %d.\n",
GetLastError()
));
// failure
goto cleanup;
}
// make sure translate mode is snmp v1
status = SnmpSetTranslateMode(SNMPAPI_UNTRANSLATED_V1);
if (WSNMP_FAILED(status))
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetTranslateMode returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure
goto cleanup;
}
// make sure retransmit mode is on
status = SnmpSetRetransmitMode(SNMPAPI_ON);
if (WSNMP_FAILED(status))
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetRetransmitMode returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure
goto cleanup;
}
// register notification class
if (!RegisterNotificationClass())
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: RegisterNotificationClass returned %d.\n",
GetLastError()
));
// failure
goto cleanup;
}
// save new status
g_fIsSnmpStarted = TRUE;
// success
fOk = TRUE;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpStartup returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure, but no need to cleanup
fOk = FALSE;
}
} else {
fOk = TRUE;
}
// serialize access to startup code
LeaveCriticalSection(&g_GlobalLock);
return fOk;
cleanup:
// cleanup if necessary
SnmpCleanup(); // ignore any return status at this stage
if (g_hTrapEvent)
{
CloseHandle(g_hTrapEvent);
g_hTrapEvent = NULL;
}
if (g_hTrapRegisterdEvent)
{
CloseHandle(g_hTrapRegisterdEvent);
g_hTrapRegisterdEvent = NULL;
}
LeaveCriticalSection(&g_GlobalLock);
return FALSE;
}
BOOL
CleanupIfNecessary(
)
/*++
Routine Description:
Cleanup WinSNMP DLL if necessary.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = TRUE;
// serialize access to startup code
EnterCriticalSection(&g_GlobalLock);
// see if already started
if (g_fIsSnmpStarted == TRUE) {
SNMPAPI_STATUS status;
// shutdown winsnmp
status = SnmpCleanup();
// validate return code
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpCleanup returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure
fOk = FALSE;
}
// unregister notification class
UnregisterNotificationClass();
// save new status
g_fIsSnmpStarted = FALSE;
}
// check trap handle
if (g_hTrapEvent != NULL) {
// close trap handle
CloseHandle(g_hTrapEvent);
// re-initialize
g_hTrapEvent = NULL;
}
// check event that syncs SnmpMgrTrapListen
if (g_hTrapRegisterdEvent != NULL)
{
// close trap handle
CloseHandle(g_hTrapRegisterdEvent);
// re-initialize
g_hTrapRegisterdEvent = NULL;
}
// serialize access to startup code
LeaveCriticalSection(&g_GlobalLock);
return fOk;
}
DWORD AddMgmtRef()
/*++
Routine Description:
Increment the reference count on using the mgmtapi.dll module.
Arguments:
none
Return Values:
Returns the reference count value after the increment is done.
--*/
{
EnterCriticalSection(&g_GlobalLock);
++g_cSnmpMgmtRef;
LeaveCriticalSection(&g_GlobalLock);
return g_cSnmpMgmtRef;
}
DWORD ReleaseMgmtRef()
/*++
Routine Description:
Decrement the reference count if it is greater than zero.
Call CleanupIfNecessary if the reference count on using mgmtapi.dll becomes
zero after the decrement.
Arguments:
none
Return Values:
Returns the final reference count value.
--*/
{
EnterCriticalSection(&g_GlobalLock);
if (g_cSnmpMgmtRef)
{
--g_cSnmpMgmtRef;
if (g_cSnmpMgmtRef == 0)
{
CleanupIfNecessary();
}
}
LeaveCriticalSection(&g_GlobalLock);
return g_cSnmpMgmtRef;
}
BOOL
CreateNotificationWindow(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Create notification window for session.
Arguments:
pSMS - pointer to MGMTAPI session structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// create notification window
pSMS->hWnd = CreateWindow(
NOTIFICATION_CLASS,
NULL, // pointer to window name
0, // window style
0, // horizontal position of window
0, // vertical position of window
0, // window width
0, // window height
NULL, // handle to parent or owner window
NULL, // handle to menu or child-window identifier
g_hDll, // handle to application instance
NULL // pointer to window-creation data
);
// validate window handle
if (pSMS->hWnd != NULL) {
// store pointer to session in window
SetWindowLongPtr(pSMS->hWnd, 0, (LONG_PTR)pSMS);
// success
fOk = TRUE;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: CreateWindow returned %d.\n",
GetLastError()
));
// failure
fOk = FALSE;
}
return fOk;
}
BOOL
DestroyNotificationWindow(
HWND hWnd
)
/*++
Routine Description:
Destroy notification window for session.
Arguments:
hWnd - window handle for session.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk;
// destroy notification window
fOk = DestroyWindow(hWnd);
if (!fOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: DestroyWindow returned %d.\n",
GetLastError()
));
}
return fOk;
}
BOOL
CloseSession(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Close WinSNMP session associated with MGMTAPI session.
Arguments:
pSMS - pointer to MGMTAPI session structure.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = TRUE;
SNMPAPI_STATUS status;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// check if window opened
if (pSMS->hWnd != (HWND)NULL) {
// destroy notification window
fOk = DestroyNotificationWindow(pSMS->hWnd);
}
// check if agent entity allocated
if (pSMS->hAgentEntity != (HSNMP_ENTITY)NULL) {
// close the entity handle
status = SnmpFreeEntity(pSMS->hAgentEntity);
// validate status
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpFreeEntity returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure
fOk = FALSE;
}
// re-initialize
pSMS->hAgentEntity = (HSNMP_ENTITY)NULL;
}
// check if manager entity allocated
if (pSMS->hManagerEntity != (HSNMP_ENTITY)NULL) {
// close the entity handle
status = SnmpFreeEntity(pSMS->hManagerEntity);
// validate status
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpFreeEntity returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure
fOk = FALSE;
}
// re-initialize
pSMS->hManagerEntity = (HSNMP_ENTITY)NULL;
}
// check if session allocated
if (pSMS->hSnmpSession != (HSNMP_SESSION)NULL) {
// close the winsnmp session
status = SnmpClose(pSMS->hSnmpSession);
// validate status
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpClose returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// failure
fOk = FALSE;
}
// re-initialize
pSMS->hSnmpSession = (HSNMP_SESSION)NULL;
}
return fOk;
}
//SNMPAPI_STATUS SNMPAPI_CALL
// SnmpConveyAgentAddress (SNMPAPI_STATUS mode);
BOOL
OpenSession(
PSNMP_MGR_SESSION pSMS,
LPSTR pAgentAddress,
LPSTR pAgentCommunity,
INT nTimeOut,
INT nRetries
)
/*++
Routine Description:
Open WinSNMP session and associate with MGMTAPI session.
Arguments:
pSMS - pointer to MGMTAPI session structure.
pAgentAddress - points to a null-terminated string specifying either a
dotted-decimal IP address or a host name that can be resolved to an
IP address, an IPX address (in 8.12 notation), or an ethernet address.
pAgentCommunity - points to a null-terminated string specifying the
SNMP community name used when communicating with the agent specified
in the lpAgentAddress parameter
nTimeOut - specifies the communications time-out in milliseconds.
nRetries - specifies the communications retry count.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk;
struct sockaddr AgentSockAddr;
CHAR AgentStrAddr[MAXENTITYSTRLEN+1];
smiOCTETS smiCommunity;
SNMPAPI_STATUS status;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// initialize notification window
if (!CreateNotificationWindow(pSMS)) {
return FALSE; // bail...
}
// open a winsnmp session which corresponds to mgmtapi session
pSMS->hSnmpSession = SnmpOpen(pSMS->hWnd, WM_WSNMP_INCOMING);
// --ft
// we need to turn this on in order to have WINSNMP to pass back not
// only the entity standing for the source Ip address but also the
// agent address as it was sent into the V1 Trap Pdu. Without it,
// SnmpMgrGetTrapEx() will return a NULL address for the pSourceAddress
// paramter. However, SnmpMgrGetTrapEx() is not documented!!!
//SnmpConveyAgentAddress(SNMPAPI_ON); // Move this into wsnmp_cf.c:SnmpStartup
// to avoid missing entry point problem when wsnmp32.dll is from other vendors
// validate session handle returned
if (WSNMP_FAILED(pSMS->hSnmpSession)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpOpen returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
// re-initialize
pSMS->hSnmpSession = (HSNMP_SESSION)NULL;
goto cleanup; // bail...
}
// validate pointer
if (pAgentAddress != NULL) {
AgentStrAddr[MAXENTITYSTRLEN] = '\0';
// use snmpapi.dll to do convert to sockets structure
if (!SnmpSvcAddrToSocket(pAgentAddress, &AgentSockAddr)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Ignoring invalid address.\n"
));
goto cleanup; // bail...
}
// check address family of agent
if (AgentSockAddr.sa_family == AF_INET) {
LPSTR pAgentStrAddr;
struct sockaddr_in * pAgentSockAddr;
// cast generic socket address structure to inet
pAgentSockAddr = (struct sockaddr_in *)&AgentSockAddr;
// obtain exclusive access to api
EnterCriticalSection(&g_GlobalLock);
// attempt to convert address into string
pAgentStrAddr = inet_ntoa(pAgentSockAddr->sin_addr);
// copy to stack variable
strncpy(AgentStrAddr, pAgentStrAddr, MAXENTITYSTRLEN);
// release exclusive access to api
LeaveCriticalSection(&g_GlobalLock);
} else if (AgentSockAddr.sa_family == AF_IPX) {
// simply copy original string
strncpy(AgentStrAddr, pAgentAddress, MAXENTITYSTRLEN);
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Incorrect address family.\n"
));
goto cleanup; // bail...
}
// create remote agent entity
pSMS->hAgentEntity = SnmpStrToEntity(
pSMS->hSnmpSession,
AgentStrAddr
);
// validate agent entity returned
if (WSNMP_FAILED(pSMS->hAgentEntity)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpStrToEntity returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// re-initialize
pSMS->hAgentEntity = (HSNMP_ENTITY)NULL;
goto cleanup; // bail...
}
// attach timeout specified with agent
status = SnmpSetTimeout(pSMS->hAgentEntity, nTimeOut / 10);
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetTimeout returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
goto cleanup; // bail...
}
// attach retries specified with agent
status = SnmpSetRetry(pSMS->hAgentEntity, nRetries);
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetRetry returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
goto cleanup; // bail...
}
// create local manager entity
pSMS->hManagerEntity = SnmpStrToEntity(
pSMS->hSnmpSession,
(AgentSockAddr.sa_family == AF_INET)
? DEFAULT_ADDRESS_IP
: DEFAULT_ADDRESS_IPX
);
// validate manager entity returned
if (WSNMP_FAILED(pSMS->hManagerEntity)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpStrToEntity returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// re-initialize
pSMS->hManagerEntity = (HSNMP_ENTITY)NULL;
goto cleanup; // bail...
}
// attach timeout specified with manager
status = SnmpSetTimeout(pSMS->hManagerEntity, nTimeOut / 10);
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetTimeout returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
goto cleanup; // bail...
}
// attach retries specified with manager
status = SnmpSetRetry(pSMS->hManagerEntity, nRetries);
if (WSNMP_FAILED(status)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSetRetry returned %d.\n",
SnmpGetLastError((HSNMP_SESSION)NULL)
));
goto cleanup; // bail...
}
}
// validate pointer
if (pAgentCommunity != NULL) {
// transfer community string
smiCommunity.ptr = (smiLPBYTE)pAgentCommunity;
smiCommunity.len = pAgentCommunity ? lstrlen(pAgentCommunity) : 0;
// obtain context from community string
pSMS->hViewContext = SnmpStrToContext(
pSMS->hSnmpSession,
&smiCommunity
);
// validate context handle
if (WSNMP_FAILED(pSMS->hViewContext)) {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpStrToContext returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// re-initialize
pSMS->hViewContext = (HSNMP_CONTEXT)NULL;
goto cleanup; // bail...
}
}
// success
return TRUE;
cleanup:
// cleanup resources
CloseSession(pSMS);
// failure
return FALSE;
}
BOOL
AllocateSession(
PSNMP_MGR_SESSION * ppSMS
)
/*++
Routine Description:
Allocate mgmtapi session structure.
Arguments:
ppSMS - pointer to session pointer to return.
Return Values:
Returns true if successful.
--*/
{
PSNMP_MGR_SESSION pSMS = NULL;
__try
{
// allocate new session table entry
pSMS = SnmpUtilMemAlloc(sizeof(SNMP_MGR_SESSION));
// validate pointer
if (pSMS != NULL) {
// initialize session level lock
InitializeCriticalSection(&pSMS->SessionLock);
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Could not allocate session.\n"
));
// notify application of error
SetLastError(SNMP_MEM_ALLOC_ERROR);
}
// transfer
*ppSMS = pSMS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if (pSMS != NULL)
{
SnmpUtilMemFree(pSMS);
pSMS = NULL;
}
}
// return status
return (pSMS != NULL);
}
VOID
FreeSession(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Frees mgmtapi session structure.
Arguments:
pSMS - pointer to mgmtapi session structure.
Return Values:
None.
--*/
{
// is session valid?
if (pSMS != NULL) {
// destroy the session level lock
DeleteCriticalSection(&pSMS->SessionLock);
// free session object
SnmpUtilMemFree(pSMS);
}
}
BOOL
ProcessAgentResponse(
PSNMP_MGR_SESSION pSMS
)
/*++
Routine Description:
Message pump for notification window.
Arguments:
pSMS - pointer to MGMTAPI session structure.
Return Values:
Returns true if agent responded.
--*/
{
MSG msg;
BOOL fOk = FALSE;
BOOL fRet;
// validate session ptr
WSNMP_ASSERT(pSMS != NULL);
// get the next message for this session
while ((fRet = GetMessage(&msg, pSMS->hWnd, 0, 0))) {
if (fRet == -1) {
// If there is an error, GetMessage returns -1
pSMS->nLastError = SNMPAPI_OTHER_ERROR;
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: ProcessAgentResponse: GetMessage returns -1.\n"
));
break;
}
// check for private message
if (msg.message != WM_WSNMP_DONE) {
// translate message
TranslateMessage(&msg);
// dispatch message
DispatchMessage(&msg);
} else {
// success
fOk = TRUE;
break;
}
}
return fOk;
}
DWORD
WINAPI
TrapThreadProc(
LPVOID lpParam
)
/*++
Routine Description:
Trap processing procedure.
Arguments:
lpParam - unused thread parameter.
Return Values:
Returns NOERROR if successful.
--*/
{
SNMPAPI_STATUS status;
PSNMP_MGR_SESSION pSMS;
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: Trap thread starting...\n"
));
// obtain pointer
pSMS = &g_TrapSMS;
// re-initialize
ZeroMemory(&g_TrapSMS, sizeof(g_TrapSMS));
g_fIsTrapRegistered = FALSE; // init to failure. Note that there will
// be only 1 instance of this thread
// initialize winsnmp trap session
if (OpenSession(pSMS, NULL, NULL, 0, 0))
{
// register
status = SnmpRegister(
pSMS->hSnmpSession,
(HSNMP_ENTITY)NULL, // hAgentEntity
(HSNMP_ENTITY)NULL, // hManagerEntity
(HSNMP_CONTEXT)NULL, // hViewContext
(smiLPCOID)NULL, // notification
SNMPAPI_ON
);
// validate return code
if (WSNMP_SUCCEEDED(status))
{
// signal main thread that Trap has been registered with WinSNMP
g_fIsTrapRegistered = TRUE;
SetEvent(g_hTrapRegisterdEvent);
// loop processing responses
while (ProcessAgentResponse(pSMS))
{
//
// processing done in window procedure...
//
}
}
else
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpRegister returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
// transfer last error to global structure
pSMS->nLastError = SnmpGetLastError(pSMS->hSnmpSession);
// signal main thread that there is an error
// in registering Trap with WinSNMP
SetEvent(g_hTrapRegisterdEvent);
}
}
else
{
// transfer last error to global structure
pSMS->nLastError = SnmpGetLastError((HSNMP_SESSION)NULL);
// signal main thread that there is an error
// in registering Trap with WinSNMP
SetEvent(g_hTrapRegisterdEvent);
goto ERROR_OUT;
}
if (g_fIsTrapRegistered)
{
// unregister WinSNMP notification reception
status = SnmpRegister(
pSMS->hSnmpSession,
(HSNMP_ENTITY)NULL, // hAgentEntity
(HSNMP_ENTITY)NULL, // hManagerEntity
(HSNMP_CONTEXT)NULL, // hViewContext
(smiLPCOID)NULL, // notification
SNMPAPI_OFF
);
// validate return code
if (WSNMP_FAILED(status))
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpRegister SNMPAPI_OFF returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
}
}
// free session
CloseSession(pSMS);
ERROR_OUT:
// obtain exclusive access
EnterCriticalSection(&g_GlobalLock);
// signal this thread has gone
g_fIsSnmpListening = FALSE;
// release exclusive access
LeaveCriticalSection(&g_GlobalLock);
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: Trap thread exiting...\n"
));
// success
return NOERROR;
}
BOOL
StartTrapsIfNecessary(
HANDLE * phTrapAvailable
)
/*++
Routine Description:
Initializes global structures for trap listening.
Arguments:
phTrapAvailable - pointer to event for signalling traps.
Return Values:
Returns true if successful (must be called only once).
--*/
{
BOOL fOk = FALSE;
DWORD dwTrapThreadId;
DWORD dwWaitTrapRegisterd;
// validate pointer
if (phTrapAvailable != NULL)
{
// obtain exclusive access
EnterCriticalSection(&g_GlobalLock);
// transfer trap event to app
*phTrapAvailable = g_hTrapEvent;
// only start listening once
if (g_fIsSnmpListening == FALSE)
{
// spawn client trap thread
g_hTrapThread = CreateThread(
NULL, // lpThreadAttributes
0, // dwStackSize
TrapThreadProc,
NULL, // lpParameter
0, // dwCreationFlags
&dwTrapThreadId
);
if (g_hTrapThread != NULL)
{
// signal successful start
g_fIsSnmpListening = TRUE;
// release exclusive access
LeaveCriticalSection(&g_GlobalLock);
// WinSE bug 6182
// wait for TrapThreadProc to signal sucessful or failure
dwWaitTrapRegisterd = WaitForSingleObject(g_hTrapRegisterdEvent, INFINITE);
if (dwWaitTrapRegisterd == WAIT_OBJECT_0)
{
if (g_fIsTrapRegistered == TRUE)
fOk = TRUE; // success
else
{
CloseHandle(g_hTrapThread);
g_hTrapThread = NULL;
SetLastError(SNMP_MGMTAPI_TRAP_ERRORS);
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Traps are not accessible.\n"
));
}
}
else
{
CloseHandle(g_hTrapThread);
g_hTrapThread = NULL;
SetLastError(SNMP_MGMTAPI_TRAP_ERRORS);
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Traps are not accessible.\n"
));
}
// In case where fOk == TRUE, g_hTrapThread will be closed when
// - new app calls SnmpMgrClose(NULL)
// OR
// - DLL_PROCESS_DETACH in DllMain is called for legacy app.
}
else
{
// release exclusive access
LeaveCriticalSection(&g_GlobalLock);
SetLastError(SNMP_MGMTAPI_TRAP_ERRORS);
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: CreateThread TrapThreadProc failed %d.\n",
GetLastError()
));
}
}
else
{
// whine about having called this before
SetLastError(SNMP_MGMTAPI_TRAP_DUPINIT);
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: Duplicate registration detected.\n"
));
// release exclusive access
LeaveCriticalSection(&g_GlobalLock);
}
}
return fOk;
}
///////////////////////////////////////////////////////////////////////////////
// //
// Dll Entry Point //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL
DllMain(
HANDLE hDll,
DWORD dwReason,
LPVOID lpReserved
)
/*++
Routine Description:
Dll entry point.
Arguments:
hDll - module handle.
dwReason - reason DllMain is being called.
lpReserved - unused.
Return Values:
None.
--*/
{
BOOL bOk = TRUE;
__try
{
// determine reason for being called
if (dwReason == DLL_PROCESS_ATTACH)
{
// initialize startup critical section
InitializeCriticalSection(&g_GlobalLock);
// initialize list of incoming traps
InitializeListHead(&g_IncomingTraps);
// optimize thread startup
DisableThreadLibraryCalls(hDll);
// save handle
g_hDll = hDll;
}
else if (dwReason == DLL_PROCESS_DETACH)
{
if (g_hTrapThread)
{
CloseHandle(g_hTrapThread);
}
// cleanup winsnmp
CleanupIfNecessary();
// nuke startup critical section
DeleteCriticalSection(&g_GlobalLock);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bOk = FALSE;
}
return bOk;
}
///////////////////////////////////////////////////////////////////////////////
// //
// Public Procedures //
// //
///////////////////////////////////////////////////////////////////////////////
LPSNMP_MGR_SESSION
SNMP_FUNC_TYPE
SnmpMgrOpen(
LPSTR pAgentAddress,
LPSTR pAgentCommunity,
INT nTimeOut,
INT nRetries
)
/*++
Routine Description:
Initializes resources necessary for communication with specified agent.
Arguments:
pAgentAddress - points to a null-terminated string specifying either a
dotted-decimal IP address or a host name that can be resolved to an
IP address, an IPX address (in 8.12 notation), or an ethernet address.
pAgentCommunity - points to a null-terminated string specifying the
SNMP community name used when communicating with the agent specified
in the lpAgentAddress parameter
nTimeOut - specifies the communications time-out in milliseconds.
nRetries - specifies the communications retry count.
Return Values:
Returns session handle if successful.
--*/
{
PSNMP_MGR_SESSION pSMS = NULL;
// initialize winsnmp
if (StartSnmpIfNecessary()) {
// allocate mgmtapi session
if (AllocateSession(&pSMS)) {
// open session
if (!OpenSession(
pSMS,
pAgentAddress,
pAgentCommunity,
nTimeOut,
nRetries)) {
// free session
FreeSession(pSMS);
// reset
pSMS = NULL;
}
else
{
// add ref
AddMgmtRef();
}
}
}
// return opaque pointer
return (LPSNMP_MGR_SESSION)pSMS;
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrCtl(
LPSNMP_MGR_SESSION session, // pointer to the MGMTAPI session
DWORD dwCtlCode, // control code for the command requested
LPVOID lpvInBuffer, // buffer with the input parameters for the operation
DWORD cbInBuffer, // size of lpvInBuffer in bytes
LPVOID lpvOUTBuffer, // buffer for all the output parameters of the command
DWORD cbOUTBuffer, // size of lpvOUTBuffer
LPDWORD lpcbBytesReturned // space used from lpvOutBuffer
)
/*++
Routine Description:
Operates several control operations over the MGMTAPI session
Arguments:
pSession - pointer to the session to
Return Values:
--*/
{
BOOL bOk = FALSE;
PSNMP_MGR_SESSION pSMS = (PSNMP_MGR_SESSION)session;
switch(dwCtlCode)
{
case MGMCTL_SETAGENTPORT:
if (pSMS == NULL)
SetLastError(SNMP_MGMTAPI_INVALID_SESSION);
else if (lpvInBuffer == NULL || cbInBuffer < sizeof(UINT))
SetLastError(SNMP_MGMTAPI_INVALID_BUFFER);
else if (WSNMP_FAILED(SnmpSetPort(pSMS->hAgentEntity, *(UINT*)lpvInBuffer)))
SetLastError(SnmpGetLastError(pSMS->hSnmpSession));
else
bOk = TRUE;
break;
default:
SetLastError(SNMP_MGMTAPI_INVALID_CTL);
break;
}
return bOk;
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrClose(
LPSNMP_MGR_SESSION session
)
/*++
Routine Description:
Cleanups resources needed for communication with specified agent.
Arguments:
session - points to an internal structure that specifies
which session to close.
Return Values:
Returns true if successful.
Notes:
BUG: 585652
-Cleanup WinSNMP resources if reference count on using mgmtapi.dll reaches 0
-SnmpMgrClose(NULL) is used to cleanup resources created by SnmpMgrTrapListen
--*/
{
BOOL fOk = TRUE;
DWORD dwWaitResult;
PSNMP_MGR_SESSION pSMS = (PSNMP_MGR_SESSION)session;
// validate pointer
if (pSMS != NULL) {
// close session
CloseSession(pSMS);
// free session
FreeSession(pSMS);
// release ref
ReleaseMgmtRef();
}
else if (g_fIsSnmpListening && g_TrapSMS.hWnd && g_hTrapThread)
{
if (PostMessage(g_TrapSMS.hWnd, WM_QUIT, (WPARAM)0, (LPARAM)0))
{
// block until TrapThreadProc has gone
dwWaitResult = WaitForSingleObject(g_hTrapThread, INFINITE);
switch (dwWaitResult)
{
case WAIT_OBJECT_0 :
SNMPDBG((
SNMP_LOG_TRACE,
"MGMTAPI: SnmpMgrClose: TrapThreadProc exited.\n"
));
break;
case WAIT_FAILED:
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpMgrClose: WaitForSingleObject returned WAIT_FAILED %u.\n",
GetLastError()
));
break;
default :
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpMgrClose: WaitForSingleObject returned %u.\n",
dwWaitResult
));
break;
}
}
else
{
fOk = FALSE;
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpMgrClose: PostMessage returned %u.\n",
GetLastError()
));
}
if (! CloseHandle(g_hTrapThread))
{
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpMgrClose: CloseHandle on %u returned %u.\n",
g_hTrapThread, GetLastError()
));
}
g_hTrapThread = NULL;
// release ref
ReleaseMgmtRef();
}
return fOk;
}
SNMPAPI
SNMP_FUNC_TYPE
SnmpMgrRequest(
LPSNMP_MGR_SESSION session,
BYTE requestType,
SnmpVarBindList * pVarBindList,
AsnInteger * pErrorStatus,
AsnInteger * pErrorIndex
)
/*++
Routine Description:
Requests the specified operation be performed with the specified agent.
Arguments:
session - points to an internal structure that specifies the session
that will perform the request.
requestType - specifies the SNMP request type.
pVarBindList - points to the variable bindings list
pErrorStatus - points to a variable in which the error status result
will be returned.
pErrorIndex - points to a variable in which the error index result
will be returned.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
SNMPAPI_STATUS status;
PSNMP_MGR_SESSION pSMS = (PSNMP_MGR_SESSION)session;
// validate pointers
if ((pSMS != NULL) &&
(pErrorIndex != NULL) &&
(pErrorStatus != NULL) &&
(pVarBindList != NULL) &&
(pVarBindList->len != 0) &&
(pVarBindList->list != NULL)) {
// obtain exclusive access to session
EnterCriticalSection(&pSMS->SessionLock);
// initialize session structure
pSMS->pVarBindList = pVarBindList;
pSMS->nPduType = (smiINT32)(BYTE)requestType;
pSMS->hVbl = (HSNMP_VBL)NULL;
pSMS->hPdu = (HSNMP_PDU)NULL;
pSMS->nErrorStatus = 0;
pSMS->nErrorIndex = 0;
pSMS->nLastError = 0;
// allocate resources
if (AllocatePdu(pSMS)) {
// actually send
status = SnmpSendMsg(
pSMS->hSnmpSession,
pSMS->hManagerEntity,
pSMS->hAgentEntity,
pSMS->hViewContext,
pSMS->hPdu
);
// release now
FreePdu(pSMS);
// validate return code
if (WSNMP_SUCCEEDED(status)) {
// process agent response
if (ProcessAgentResponse(pSMS) &&
(pSMS->nLastError == SNMP_ERROR_NOERROR)) {
// update error status and index
*pErrorStatus = pSMS->nErrorStatus;
*pErrorIndex = pSMS->nErrorIndex;
// success
fOk = TRUE;
} else {
// set error to winsnmp error
SetLastError(pSMS->nLastError);
// failure
fOk = FALSE;
}
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"MGMTAPI: SnmpSendMsg returned %d.\n",
SnmpGetLastError(pSMS->hSnmpSession)
));
}
}
// release exclusive access to session
LeaveCriticalSection(&pSMS->SessionLock);
}
return fOk;
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrStrToOid(
LPSTR pString,
AsnObjectIdentifier * pOID
)
/*++
Routine Description:
Converts a string object identifier or object descriptor representation
to an internal object identifier.
Arguments:
pString - points to a null-terminated string to be converted.
pOID - points to an object identifier variable that will receive the
converted value.
Return Values:
Returns true if successful.
--*/
{
// validate pointer to oid and string
if ((pOID != NULL) && (pString != NULL)) {
// forward to mibcc code for now
return SnmpMgrText2Oid(pString, pOID);
}
return FALSE;
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrOidToStr(
AsnObjectIdentifier * pOID,
LPSTR * ppString
)
/*++
Routine Description:
Converts an internal object identifier to a string object identifier or
object descriptor representation.
Arguments:
pOID - pointers to object identifier to be converted.
ppString - points to string pointer to receive converted value.
Return Values:
Returns true if successful.
--*/
{
// validate pointer to oid and string
if ((pOID != NULL) && (ppString != NULL)) {
// forward to mibcc code for now
return SnmpMgrOid2Text(pOID, ppString);
}
return FALSE;
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrTrapListen(
HANDLE * phTrapAvailable
)
/*++
Routine Description:
Registers the ability of a manager application to receive SNMP traps.
Arguments:
phTrapAvailable - points to an event handle that will be used to indicate
that there are traps available
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
// startup winsnmp
if (StartSnmpIfNecessary()) {
// spawn only one trap client thread
if (StartTrapsIfNecessary(phTrapAvailable)) {
// success
fOk = TRUE;
// add ref
AddMgmtRef();
}
}
return fOk;
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrGetTrap(
AsnObjectIdentifier * pEnterpriseOID,
AsnNetworkAddress * pAgentAddress,
AsnInteger * pGenericTrap,
AsnInteger * pSpecificTrap,
AsnTimeticks * pTimeStamp,
SnmpVarBindList * pVarBindList
)
/*++
Routine Description:
Returns outstanding trap data that the caller has not received if
trap reception is enabled.
Arguments:
pEnterpriseOID - points to an object identifier that specifies the
enterprise that generated the SNMP trap
pAgentAddress - points to the address of the agent that generated the
SNMP trap (retrieved from PDU).
pGenericTrap - points to an indicator of the generic trap id.
pSpecificTrap - points to an indicator of the specific trap id.
pTimeStamp - points to a variable to receive the time stamp.
pVarBindList - points to the associated variable bindings.
Return Values:
Returns true if successful.
--*/
{
// forward to new api
return SnmpMgrGetTrapEx(
pEnterpriseOID,
pAgentAddress,
NULL,
pGenericTrap,
pSpecificTrap,
NULL,
pTimeStamp,
pVarBindList
);
}
BOOL
SNMP_FUNC_TYPE
SnmpMgrGetTrapEx(
AsnObjectIdentifier * pEnterpriseOID,
AsnNetworkAddress * pAgentAddress,
AsnNetworkAddress * pSourceAddress,
AsnInteger * pGenericTrap,
AsnInteger * pSpecificTrap,
AsnOctetString * pCommunity,
AsnTimeticks * pTimeStamp,
SnmpVarBindList * pVarBindList
)
/*++
Routine Description:
Returns outstanding trap data that the caller has not received if
trap reception is enabled.
Arguments:
pEnterpriseOID - points to an object identifier that specifies the
enterprise that generated the SNMP trap
pAgentAddress - points to the address of the agent that generated the
SNMP trap (retrieved from PDU).
pSourceAddress - points to the address of the agent that generated the
SNMP trap (retrieved from network transport).
pGenericTrap - points to an indicator of the generic trap id.
pSpecificTrap - points to an indicator of the specific trap id.
pCommunity - points to structure to receive community string.
pTimeStamp - points to a variable to receive the time stamp.
pVarBindList - points to the associated variable bindings.
Return Values:
Returns true if successful.
--*/
{
BOOL fOk = FALSE;
PLIST_ENTRY pLE = NULL;
PTRAP_LIST_ENTRY pTLE = NULL;
smiINT32 nLastError;
// obtain exclusive access
EnterCriticalSection(&g_GlobalLock);
// make sure list has entries
if (!IsListEmpty(&g_IncomingTraps)) {
// remove first item from list
pLE = RemoveHeadList(&g_IncomingTraps);
} else {
// check for trap thread failure
nLastError = g_TrapSMS.nLastError;
}
// release exclusive access
LeaveCriticalSection(&g_GlobalLock);
// validate pointer
if (pLE != NULL) {
// retrieve pointer to trap list entry
pTLE = CONTAINING_RECORD(pLE, TRAP_LIST_ENTRY, Link);
// validate pointer
if (pEnterpriseOID != NULL) {
// manually copy enterprise oid
*pEnterpriseOID = pTLE->EnterpriseOID;
// re-initialize list entry
pTLE->EnterpriseOID.ids = NULL;
pTLE->EnterpriseOID.idLength = 0;
}
// validate pointer
if (pCommunity != NULL) {
// transfer string info
*pCommunity = pTLE->Community;
// re-initialize list entry
pTLE->Community.length = 0;
pTLE->Community.stream = NULL;
pTLE->Community.dynamic = FALSE;
}
// validate pointer
if (pVarBindList != NULL) {
// transfer varbindlist
*pVarBindList = pTLE->VarBindList;
// re-initialize list entry
pTLE->VarBindList.len = 0;
pTLE->VarBindList.list = NULL;
}
// validate pointer
if (pAgentAddress != NULL) {
// copy structure
*pAgentAddress = pTLE->AgentAddress;
// remove our reference
pTLE->AgentAddress.length = 0;
pTLE->AgentAddress.stream = NULL;
pTLE->AgentAddress.dynamic = FALSE;
}
// validate pointer
if (pSourceAddress != NULL) {
// copy structure
*pSourceAddress = pTLE->SourceAddress;
// remove our reference
pTLE->SourceAddress.length = 0;
pTLE->SourceAddress.stream = NULL;
pTLE->SourceAddress.dynamic = FALSE;
}
// validate pointer
if (pGenericTrap != NULL) {
// transfer generic trap info
*pGenericTrap = pTLE->nGenericTrap;
}
// validate pointer
if (pSpecificTrap != NULL) {
// transfer generic trap info
*pSpecificTrap = pTLE->nSpecificTrap;
}
// validate pointer
if (pTimeStamp != NULL) {
// transfer time info
*pTimeStamp = pTLE->TimeStamp;
}
// release
FreeTle(pTLE);
// success
fOk = TRUE;
} else if (nLastError != NOERROR) {
// indicate there was an thread error
SetLastError(SNMP_MGMTAPI_TRAP_ERRORS);
} else {
// indicate there are no traps
SetLastError(SNMP_MGMTAPI_NOTRAPS);
}
return fOk;
}