📄 wsnmp_no.c
字号:
// wsnmp_no.c
//
// WinSNMP Notification Functions and helpers
// Copyright 1995-1997 ACE*COMM Corp
// Rleased to Microsoft under Contract
// Beta 1 version, 970228
// Bob Natale (bnatale@acecomm.com)
//
// 970310 - Added callback session support
// - Added v2 to v1 trap mapping
// - Refined v1 to v2 trap mapping
//
#include "winsnmp.inc"
//
BOOL DispatchTrap (LPSAS host, smiLPOCTETS community, LPPDUS pdu);
BOOL MapV1TrapV2 (LPPDUS pdu);
smiUINT32 ParsePduHdr (smiLPBYTE msgPtr, smiUINT32 msgLen, smiLPUINT32 version, smiLPINT type, smiLPUINT32 reqID);
BOOL SetPduType (smiLPBYTE msgPtr, smiUINT32 msgLen, int pduType);
THR_TYPE WINAPI thrNotify (LPVOID);
smiUINT32 sysUpTimeValue[9] = {1,3,6,1,2,1,1,3,0};
smiOID sysUpTimeName = {9, sysUpTimeValue};
smiUINT32 snmpTrapOidValue[11] = {1,3,6,1,6,3,1,1,4,1,0};
smiOID snmpTrapOidName = {11, snmpTrapOidValue};
smiUINT32 snmpTrapsValue[10] = {1,3,6,1,6,3,1,1,5,999};
smiOID snmpTrapsName = {10, snmpTrapsValue};
smiUINT32 snmpTrapEntValue[11] = {1,3,6,1,6,3,1,1,4,3,0};
smiOID snmpTrapEntName = {11, snmpTrapEntValue};
smiUINT32 snmpTrapAddrValue[7] = {1,3,6,1,3,1057,1};
smiOID snmpTrapAddrName = {7, snmpTrapAddrValue};
void MsgNotify (smiUINT32 msgType, smiLPBYTE msgAddr, smiUINT32 msgLen, smiUINT32 nAgent, LPSAS host)
{
DWORD nFound;
DWORD nMsg;
smiUINT32 version;
smiINT pduType;
smiUINT32 reqID;
LPSESSION pSession;
LPSNMPMSG pMsg;
nMsg = ParsePduHdr (msgAddr, msgLen, &version, &pduType, &reqID);
if (nMsg != 0) // ParsePduHdr returns 0 == no_error
{
if (msgAddr)
GlobalFree (msgAddr);
return;
}
switch (msgType)
{
case NP_TRAP:
if (TrapDescr.Used && // Discard traps if no registrations
(pduType == SNMP_PDU_INFORM ||
pduType == SNMP_PDU_TRAP ||
pduType == SNMP_PDU_V1TRAP))
{
smiLPOCTETS community;
LPPDUS pdu;
BOOL bConvert;
pdu = GlobalAlloc (GPTR, sizeof(PDUS));
if (pdu == NULL)
goto DONE_TRAP;
nMsg = ParseMessage (msgAddr, msgLen, &version, &community, pdu);
if (nMsg != 0) // ParseMessage returns 0 == no_error
goto DONE_PDU;
if (pduType == SNMP_PDU_INFORM)
{ // Send the Inform acknowledgment response
SOCKET s;
SetPduType (msgAddr, msgLen, SNMP_PDU_RESPONSE);
if (host->ipx.sa_family == AF_IPX)
s = TaskData.ipxSock;
else
s = TaskData.ipSock;
sendto (s, msgAddr, msgLen, 0, (LPSOCKADDR)host, sizeof(SOCKADDR));
SetPduType (msgAddr, msgLen, SNMP_PDU_INFORM);
}
bConvert = TRUE;
if (pduType == SNMP_PDU_V1TRAP) // If v1 trap...
bConvert = MapV1TrapV2 (pdu); // convert to v2 trap
if (bConvert)
DispatchTrap (host, community, pdu); // always v2 here
// Cleanup is the same regardless of success or failure
FreeVarBindList (pdu->VBL_addr); // Checks for NULL
FreeV1Trap (pdu->v1Trap); // ditto
FreeOctetString (community); // ditto
DONE_PDU:
GlobalFree (pdu);
} // end_if Trap_or_Inform PDU
DONE_TRAP:
GlobalFree (msgAddr);
return; // end_case NP_TRAP
case NP_RESPONSE:
if (pduType != SNMP_PDU_RESPONSE)
{
GlobalFree (msgAddr);
return;
}
EnterCriticalSection (&cs_MSG);
for (nFound=0, nMsg=0; nFound<MsgDescr.Used && nMsg<MsgDescr.Allocated; nMsg++)
{
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
if (!pMsg->Session)
continue;
nFound++;
if ((pMsg->Status == NP_SENT) && // Must have been sent!
(pMsg->dllReqId == reqID)) // Must match up!
{
pMsg->Status = NP_RCVD; // ResponsePDU!
// Release sent packet message
if (pMsg->Addr)
GlobalFree (pMsg->Addr);
// Point to received packet message
pMsg->Addr = msgAddr;
pMsg->Size = msgLen;
LeaveCriticalSection (&cs_MSG);
pSession = snmpGetTableEntry(&SessDescr, HandleToUlong(pMsg->Session) - 1);
if (pSession->fCallBack)
{ // callback session notification mode
EnterCriticalSection (&cs_SESSION);
if (pSession->thrHandle)
{
if (pSession->thrCount != 0xFFFFFFFF)
pSession->thrCount++;
SetEvent (pSession->thrEvent);
}
else
FreeMsg (nMsg);
LeaveCriticalSection (&cs_SESSION);
}
else
{ // window/message session notification mode
if (IsWindow(pSession->hWnd))
{
pMsg->Status = NP_READY;
PostMessage (pSession->hWnd,
pSession->wMsg,
0, pMsg->appReqId);
}
else
FreeMsg (nMsg);
}
return; // Matched response with request
} // end_if
} // end_for
// If we fall through the for loop without finding a match,
// this must be a spurious message from agent...discard
GlobalFree (msgAddr);
LeaveCriticalSection (&cs_MSG);
return; // end_case NP_RESPONSE
case NP_REQUEST:
// To allow for AgentX Master Agents and Mid-Level-Managers
// any type of PDU may be accepted on this channel - BobN 4/8/97
// Get a msg slot
EnterCriticalSection (&cs_MSG);
if (snmpAllocTableEntry(&MsgDescr, &nMsg) != SNMPAPI_SUCCESS)
{
LeaveCriticalSection(&cs_MSG);
return;
}
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
pMsg->Session = ((LPAGENT)snmpGetTableEntry(&AgentDescr, nAgent))->Session;
pMsg->Status = NP_RCVD; // In-bound request
pMsg->Type = pduType;
pMsg->Addr = msgAddr;
pMsg->Size = msgLen;
pMsg->appReqId = pMsg->dllReqId = reqID;
CopyMemory (&(pMsg->Host), host, sizeof(SAS));
LeaveCriticalSection (&cs_MSG);
pSession = snmpGetTableEntry(&SessDescr, HandleToUlong(pMsg->Session) - 1);
if (pSession->fCallBack)
{ // callback session notification mode
EnterCriticalSection (&cs_SESSION);
if (pSession->thrHandle)
{
if (pSession->thrCount != 0xFFFFFFFF)
pSession->thrCount++;
SetEvent (pSession->thrEvent);
}
else
{
FreeMsg (nMsg);
}
LeaveCriticalSection (&cs_SESSION);
}
else
{
if (IsWindow(pSession->hWnd))
{
pMsg->Status = NP_READY;
PostMessage (pSession->hWnd,
pSession->wMsg,
0, pMsg->appReqId);
}
else
FreeMsg (nMsg);
}
break;
default:
GlobalFree (msgAddr);
break;
} // end_switch msgType
return;
} // end_MsgNotify
THR_TYPE WINAPI thrNotify (LPVOID cbSessionSlot)
{
DWORD nSes = (DWORD)((DWORD_PTR)cbSessionSlot);
HSNMP_SESSION hSession = (HSNMP_SESSION)(nSes + 1);
DWORD nUsed, nMsg;
WPARAM wParam;
LPARAM lParam;
BOOL bFound, bWillBlock;
LPSESSION pSession;
LPSNMPMSG pMsg;
// pSession->thrCount counts the number of requests. External threads increment it
// each time they know something has changed in the message table (message expired or received)
// thrNotify decrements it each time it scans the message table.
do
{
EnterCriticalSection (&cs_SESSION);
pSession = snmpGetTableEntry(&SessDescr, nSes);
if (pSession->thrCount != 0xFFFFFFFF &&
pSession->thrCount != 0)
pSession->thrCount-- ;
bWillBlock = pSession->thrCount == 0;
LeaveCriticalSection (&cs_SESSION);
// The thread will block only if the pSession->thrCount was 0 (tested in critical
// section). It will be unblocked by external threads, from inside the same critical section.
if (bWillBlock)
WaitForSingleObject (pSession->thrEvent, INFINITE);
// termination is requested, just break the loop
if (pSession->thrCount == 0xFFFFFFFF)
break;
bFound = FALSE;
// Find a waiting Msg for this session to process
EnterCriticalSection (&cs_MSG);
for (nUsed=0, nMsg=0;
nUsed<MsgDescr.Used && nMsg<MsgDescr.Allocated;
nMsg++)
{
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
if (pMsg->Session == hSession &&
(pMsg->Status == NP_RCVD || pMsg->Status == NP_EXPIRED))
{
// the message was found. It might be already received, or it might
// be timed out. Either case, the notification function has to be called.
wParam = pMsg->Status == NP_RCVD ? 0 : SNMPAPI_TL_TIMEOUT ;
lParam = pMsg->appReqId;
if (wParam == SNMPAPI_TL_TIMEOUT)
FreeMsg(nMsg); // no more need for this expired bugger
else
pMsg->Status = NP_READY; // mark it for SnmpRecvMsg()
bFound = TRUE;
// as the message was found, no reason to loop further
break;
}
// update nFound to avoid searching more than the messages available
nUsed += (pMsg->Session != 0);
}
LeaveCriticalSection (&cs_MSG);
if (bFound)
{
//if a message was found for this session, call the notification function
(*(pSession->fCallBack)) (hSession,
pSession->hWnd,
pSession->wMsg,
wParam,
lParam,
pSession->lpClientData);
}
} while (TRUE);
_endthreadex(0);
return (0);
} // end_thrNotify
THR_TYPE WINAPI thrManager (LPVOID xSock)
{
DWORD iBytes;
int nSock;
fd_set readFDS;
SOCKET *pSock = (SOCKET*)xSock;
SOCKET tSock = *pSock;
SAS host;
smiLPBYTE rMsgPtr;
int fLen;
while (TRUE)
{
FD_ZERO (&readFDS);
// Note: strategy used in this block to assign a value
// to "fLen" is important for Solaris and benign for Win32
FD_SET (tSock, &readFDS);
fLen = (int)tSock;
fLen++;
// Must preserve value of fLen across loops
nSock = select (fLen, &readFDS, NULL, NULL, NULL);
if (nSock == SOCKET_ERROR || *pSock == INVALID_SOCKET)
goto DONE;
// Only one socket monitored per thread, hence
// FD_ISSET can be safely assumed at this point
nSock = ioctlsocket (tSock, FIONREAD, &iBytes);
if (nSock == SOCKET_ERROR || *pSock == INVALID_SOCKET)
goto DONE;
// Find the message buffer address...
rMsgPtr = GlobalAlloc (GPTR, iBytes);
if (rMsgPtr == NULL)
{ // No space error...throw away the message...
recvfrom (tSock, (LPSTR)&nSock, 1, 0, NULL, NULL);
if (*pSock == INVALID_SOCKET)
goto DONE;
// ...and call it quits.
continue;
}
nSock = sizeof(SAS);
// get the datagram and the address of the host that sent it
iBytes = recvfrom (tSock, rMsgPtr, iBytes, 0, (LPSOCKADDR)&host, &nSock);
if (iBytes != SOCKET_ERROR && *pSock != INVALID_SOCKET)
MsgNotify (NP_RESPONSE, rMsgPtr, iBytes, 0, &host);
} // end_while
DONE:
return (0);
} // end_thrManager
THR_TYPE WINAPI thrTimer (LPVOID nTask)
{ // Clean-up any timed-out messages
BOOL bFree;
DWORD lTicks, nMsg;
DWORD nFound;
SOCKET tSock;
LPSNMPMSG pMsg;
// This thread won't be needed immediately upon creation.
// It sleeps/suspends itself as appropriate.
// SnmpSendMsg() resumes it for each message sent
// SnmpCleanup() resumes it to signal termination.
while (TRUE)
{// Once per second granularity
#ifdef SOLARIS
sleep (1);
#else
Sleep (1000);
#endif // SOLARIS
// Check for termination request
if (TaskData.timerThread == NULL)
goto DONE;
// If no msgs, go back to sleep
if (MsgDescr.Used == 0)
continue;
EnterCriticalSection (&cs_MSG);
for (nMsg=0, nFound=0; nFound<MsgDescr.Used && nMsg<MsgDescr.Allocated; nMsg++)
{
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
if (!pMsg->Session) // Skip unused slots
continue;
nFound++; // Signal break when last used slot is processed
if (pMsg->Status != NP_SENT) // Skip pending and
continue; // received messages
lTicks = GetTickCount(); // update current time
// Following test revised on 10/18/96 by BobN
// Message "tick-time" rather than "TTL" now stored in MSG
// to enable test for Windows timer wrap (49.7 days)
if (pMsg->Wait + pMsg->Ticks > lTicks && // MSG TTL test
pMsg->Ticks <= lTicks) // Timer wrap test
continue; // Retain the message
bFree = TRUE; // Prepare to free the message slot
if (pMsg->nRetransmitMode)
{
if (pMsg->Tries)
{
//WriteSocket (nMsg);
// Determine which socket to use
if (pMsg->Host.ipx.sa_family == AF_IPX)
tSock = TaskData.ipxSock;
else
tSock = TaskData.ipSock;
// Send the data
sendto (tSock, pMsg->Addr, pMsg->Size,
0, (LPSOCKADDR)&(pMsg->Host), sizeof(SAS));
// Need to check for SOCKET_ERROR!
// end_WriteSocket
pMsg->Ticks = lTicks;
pMsg->Tries--; // Record the attempt
if (!pMsg->Tries) // No further retries?
{ // Release buffer space
GlobalFree (pMsg->Addr);
pMsg->Addr = NULL;
pMsg->Size = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -