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.
 
 
 
 
 
 

1551 lines
46 KiB

// wsnmp_cf.c
//
// WinSNMP Communications Functions and helpers
// Copyright 1995-1998 ACE*COMM Corp
// Rleased to Microsoft under Contract
//
// Bob Natale ([email protected])
//
// 19980625 - Modified SnmpStartup() to allow for NULL
// output args and to check for IsBadWritePtr()
// when non-NULL
//
#include "winsnmp.inc"
#define SNMP_MAJOR_VERSION 2
#define SNMP_MINOR_VERSION 0
#define SNMP_SUPPORT_LEVEL SNMPAPI_V2_SUPPORT
LPPDUS MapV2TrapV1 (HSNMP_PDU hPdu);
THR_TYPE WINAPI thrManager (LPVOID);
THR_TYPE WINAPI thrTrap (LPVOID);
THR_TYPE WINAPI thrTimer (LPVOID);
THR_TYPE WINAPI thrAgent (LPVOID);
THR_TYPE WINAPI thrNotify (LPVOID);
void FreeRegister (DWORD nTrap)
{
LPTRAPNOTICE pTrap;
EnterCriticalSection (&cs_TRAP);
pTrap = snmpGetTableEntry(&TrapDescr, nTrap);
if (pTrap->ourEntity)
SnmpFreeEntity (pTrap->ourEntity);
if (pTrap->agentEntity)
SnmpFreeEntity (pTrap->agentEntity);
if (pTrap->Context)
SnmpFreeContext (pTrap->Context);
snmpFreeTableEntry(&TrapDescr, nTrap);
LeaveCriticalSection (&cs_TRAP);
return;
} // end_FreeRegister
// Exported Functions
// SnmpStartup
SNMPAPI_STATUS SNMPAPI_CALL
SnmpStartup (OUT smiLPUINT32 nMajorVersion,
OUT smiLPUINT32 nMinorVersion,
OUT smiLPUINT32 nLevel,
OUT smiLPUINT32 nTranslateMode,
OUT smiLPUINT32 nRetransmitMode)
{
WSADATA wsaData;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
HSNMP_SESSION hTask = (HSNMP_SESSION) ULongToPtr(GetCurrentProcessId());
//
//
if (nMajorVersion)
{
if (IsBadWritePtr (nMajorVersion, sizeof(smiUINT32)))
goto ARG_ERROR;
*nMajorVersion = SNMP_MAJOR_VERSION;
}
if (nMinorVersion)
{
if (IsBadWritePtr (nMinorVersion, sizeof(smiUINT32)))
goto ARG_ERROR;
*nMinorVersion = SNMP_MINOR_VERSION;
}
if (nLevel)
{
if (IsBadWritePtr (nLevel, sizeof(smiUINT32)))
goto ARG_ERROR;
*nLevel = SNMP_SUPPORT_LEVEL;
}
if (nTranslateMode)
{
if (IsBadWritePtr (nTranslateMode, sizeof(smiUINT32)))
goto ARG_ERROR;
*nTranslateMode = SNMPAPI_UNTRANSLATED_V1;
}
if (nRetransmitMode)
{
if (IsBadWritePtr (nRetransmitMode, sizeof(smiUINT32)))
goto ARG_ERROR;
*nRetransmitMode = SNMPAPI_ON;
}
goto ARGS_OK;
ARG_ERROR:
lError = SNMPAPI_ALLOC_ERROR;
goto ERROR_OUT;
ARGS_OK:
EnterCriticalSection (&cs_TASK);
TaskData.nRetransmitMode = SNMPAPI_ON;
TaskData.nTranslateMode = SNMPAPI_UNTRANSLATED_V1;
// 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.
TaskData.conveyAddress = SNMPAPI_ON;
// SnmpStartup is idempotent...
if (TaskData.hTask == hTask)
goto DONE; // ...already called
// New task starting up...get OS info
TaskData.sEnv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx (&TaskData.sEnv))
{
lError = SNMPAPI_OTHER_ERROR;
goto ERROR_PRECHECK;
}
// Start WinSock connection...should return 0
if (WSAStartup ((WORD)0x0101, &wsaData))
{
lError = SNMPAPI_TL_NOT_INITIALIZED;
goto ERROR_PRECHECK;
}
// Set trapPipe (used in NT case only)
TaskData.trapPipe = INVALID_HANDLE_VALUE;
// bug# 270672
// create non-signaled event to synchronize shutdown of thrTrap
TaskData.trapEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (NULL == TaskData.trapEvent)
{
lError = SNMPAPI_ALLOC_ERROR;
WSACleanup();
goto ERROR_PRECHECK;
}
// init the trapOl overlapped struct with manual reset non-signaled event
ZeroMemory(&TaskData.trapOl, sizeof(TaskData.trapOl));
TaskData.trapOl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == TaskData.trapOl.hEvent)
{
lError = SNMPAPI_ALLOC_ERROR;
CloseHandle(TaskData.trapEvent);
TaskData.trapEvent = NULL;
WSACleanup();
goto ERROR_PRECHECK;
}
// init TaskData.hExitEvent with manual reset non-signaled event to
// synchronize shutdown of thrManager
TaskData.hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == TaskData.hExitEvent)
{
lError = SNMPAPI_ALLOC_ERROR;
CloseHandle(TaskData.trapEvent);
TaskData.trapEvent = NULL;
CloseHandle(TaskData.trapOl.hEvent);
TaskData.trapOl.hEvent = NULL;
WSACleanup();
goto ERROR_PRECHECK;
}
// Set trapSock (used in Win95 case only)
TaskData.trapSock = INVALID_SOCKET;
// Set "manager" sockets (used at SnmpSendMsg() time)
TaskData.ipSock = TaskData.ipxSock = INVALID_SOCKET;
// Start timer thread
{
DWORD thrId;
TaskData.timerThread = (HANDLE)_beginthreadex (NULL, 0, thrTimer, NULL, 0, &thrId);
if (NULL == TaskData.timerThread)
{
lError = SNMPAPI_TL_RESOURCE_ERROR;
CloseHandle(TaskData.trapEvent);
TaskData.trapEvent = NULL;
CloseHandle(TaskData.trapOl.hEvent);
TaskData.trapOl.hEvent = NULL;
WSACleanup();
goto ERROR_PRECHECK;
}
}
//
DONE:
TaskData.hTask = hTask;
TaskData.nLastError = SNMPAPI_SUCCESS;
ERROR_PRECHECK:
LeaveCriticalSection (&cs_TASK);
if (lError == SNMPAPI_SUCCESS)
return (SNMPAPI_SUCCESS);
ERROR_OUT:
return (SaveError (0, lError));
} // end_SnmpStartup
// SnmpCleanup
SNMPAPI_STATUS SNMPAPI_CALL SnmpCleanup (void)
{
DWORD nSession;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
// Variables for threads not associated with a specific session
DWORD nHandles = 0;
HANDLE hTemp[4] = {NULL, NULL, NULL, NULL};
CONST HANDLE *hObjects = &hTemp[0];
//--------------------------------------------------------------
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
EnterCriticalSection (&cs_SESSION);
// Do all Forgotten Closes
if (SessDescr.Used)
{
for (nSession = 0; nSession < SessDescr.Allocated; nSession++)
if (((LPSESSION)snmpGetTableEntry(&SessDescr, nSession))->nTask)
SnmpClose ((HSNMP_SESSION) ULongToPtr(nSession + 1));
}
LeaveCriticalSection (&cs_SESSION);
EnterCriticalSection (&cs_TASK);
SetEvent(TaskData.hExitEvent); // askes thrManager to exit
// Terminate thrTimer
if (TaskData.timerThread)
{
hTemp[nHandles++] = TaskData.timerThread;
// NULL signals the timer thread to terminate itself
TaskData.timerThread = NULL;
}
// Close "Mgr" sockets and threads
if (TaskData.ipSock != INVALID_SOCKET)
{// UDP channel
// check thrManager code to understand the lines below:
SOCKET ipSock = TaskData.ipSock;
WaitForSingleObject (TaskData.ipThread, INFINITE);
TaskData.ipSock = INVALID_SOCKET;
closesocket (ipSock);
if (TaskData.ipThread)
hTemp[nHandles++] = TaskData.ipThread;
}
if (TaskData.ipxSock != INVALID_SOCKET)
{// IPX channel
// check thrManager code to understand the lines below:
SOCKET ipxSock = TaskData.ipxSock;
WaitForSingleObject (TaskData.ipxThread, INFINITE);
TaskData.ipxSock = INVALID_SOCKET;
closesocket (ipxSock);
if (TaskData.ipxThread)
hTemp[nHandles++] = TaskData.ipxThread;
}
// Terminate thrTrap
if (TaskData.trapThread)
{
if (TaskData.sEnv.dwPlatformId == VER_PLATFORM_WIN32_NT)
{ // NT-specific stuff
// set events to signal thrTrap to exit
SetEvent(TaskData.trapEvent);
// unblock thrTrap if necessary
SetEvent(TaskData.trapOl.hEvent);
}
hTemp[nHandles++] = TaskData.trapThread;
}
WaitForMultipleObjects (nHandles, hObjects, TRUE, 5000);
while (nHandles > 0)
{
nHandles--;
CloseHandle (hTemp[nHandles]);
}
if (TaskData.trapPipe != INVALID_HANDLE_VALUE)
CloseHandle (TaskData.trapPipe);
if (TaskData.trapEvent != NULL)
CloseHandle(TaskData.trapEvent);
if (TaskData.trapOl.hEvent != NULL)
CloseHandle(TaskData.trapOl.hEvent);
if (TaskData.hExitEvent)
CloseHandle(TaskData.hExitEvent);
// Do the main thing
ZeroMemory (&TaskData, sizeof(TASK));
LeaveCriticalSection (&cs_TASK);
// Close down WinSock connection
WSACleanup ();
//
//
return (SNMPAPI_SUCCESS);
ERROR_OUT:
return (SaveError (0, lError));
} // end_SnmpCleanup
// Open a session (v1 and v2)
HSNMP_SESSION SNMPAPI_CALL SnmpOpen (IN HWND hWnd, IN UINT wMsg)
{
return (SnmpCreateSession (hWnd, wMsg, NULL, NULL));
} // end_SnmpOpen
// Open a session, w/callback option (v2)
HSNMP_SESSION SNMPAPI_CALL
SnmpCreateSession (IN HWND hWnd, IN UINT wMsg,
IN SNMPAPI_CALLBACK fCallBack,
IN LPVOID lpClientData)
{
DWORD nSession;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
LPSESSION pSession;
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
// Check for window/message notification mode argument validity
if (fCallBack == NULL)
if (!IsWindow(hWnd))
{
lError = SNMPAPI_HWND_INVALID;
goto ERROR_OUT;
}
//
EnterCriticalSection (&cs_SESSION);
lError = snmpAllocTableEntry(&SessDescr, &nSession);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_PRECHECK;
pSession = snmpGetTableEntry(&SessDescr, nSession);
pSession->nTask = TaskData.hTask;
pSession->hWnd = hWnd;
pSession->wMsg = wMsg;
pSession->fCallBack = fCallBack;
pSession->lpClientData = lpClientData;
if (fCallBack)
{
DWORD thrId;
pSession->thrEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
if (NULL == pSession->thrEvent)
{
lError = SNMPAPI_ALLOC_ERROR;
snmpFreeTableEntry(&SessDescr, nSession);
goto ERROR_PRECHECK;
}
pSession->thrCount = 0;
pSession->thrHandle = (HANDLE)_beginthreadex
(NULL, 0, thrNotify, (LPVOID) ULongToPtr(nSession), 0, &thrId);
if (NULL == pSession->thrHandle)
{
lError = SNMPAPI_TL_RESOURCE_ERROR;
snmpFreeTableEntry(&SessDescr, nSession);
CloseHandle(pSession->thrEvent);
pSession->thrEvent = NULL;
goto ERROR_PRECHECK;
}
}
pSession->nLastError = SNMPAPI_SUCCESS;
ERROR_PRECHECK:
LeaveCriticalSection (&cs_SESSION);
if (lError == SNMPAPI_SUCCESS)
return ((HSNMP_SESSION) ULongToPtr(nSession+1));
ERROR_OUT:
return ((HSNMP_SESSION) ULongToPtr(SaveError (0, lError)));
} // end_SnmpOpen
// SnmpClose
SNMPAPI_STATUS SNMPAPI_CALL
SnmpClose (IN HSNMP_SESSION hSession)
{
HANDLE thrTemp;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
DWORD nSes = HandleToUlong(hSession) - 1;
DWORD i;
LPSESSION pSession;
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
if (!snmpValidTableEntry(&SessDescr, nSes))
{
lError = SNMPAPI_SESSION_INVALID;
goto ERROR_OUT;
}
pSession = snmpGetTableEntry(&SessDescr, nSes);
// Strategy:
// 1st: Stop notifications to session
// 2nd: Stop accepting new messages
// Traps
// Agents
// 3rd: Clear out pending messages
// 4th: Free up all other resources
//
// PART_1: Stop notifications to the closing Session
// Block window/message notification (in all cases!)
pSession->hWnd = NULL;
// Block callback notification (if required)
if (pSession->fCallBack != NULL)
{
// Save thrHandle for WaitForSingleObject call
EnterCriticalSection (&cs_SESSION);
thrTemp = pSession->thrHandle;
// If this is a callback session, must stop thrNotify instance
pSession->thrHandle = NULL;
// 0xFFFFFFFF signals thrNotify instance to terminate itself
pSession->thrCount = 0xFFFFFFFF;
// SetEvent signals thrNotify instance to run
SetEvent (pSession->thrEvent);
LeaveCriticalSection (&cs_SESSION);
// Wait for termination signal from thread handle
WaitForSingleObject (thrTemp, 30000);
// Close thrNotify instance handle
CloseHandle (thrTemp);
// Close thrNotify event handle
CloseHandle (pSession->thrEvent);
}
// PART_2: Stop accepting new messages for the closing Session
// Free Notifications registered by the closing Session
EnterCriticalSection (&cs_TRAP);
for (i = 0; i < TrapDescr.Allocated && TrapDescr.Used != 0; i++)
{
LPTRAPNOTICE pTrap = snmpGetTableEntry(&TrapDescr, i);
if (pTrap->Session == hSession)
FreeRegister (i);
} // end_for (Traps)
LeaveCriticalSection (&cs_TRAP);
// Free Agents registered by the closing Session
EnterCriticalSection (&cs_AGENT);
for (i = 0; i < AgentDescr.Allocated && AgentDescr.Used != 0; i++)
{
LPAGENT pAgent = snmpGetTableEntry(&AgentDescr, i);
if (pAgent->Session == hSession)
SnmpListen (pAgent->Entity, SNMPAPI_OFF);
}
LeaveCriticalSection (&cs_AGENT);
// PART_3: Free all pending messages for the closing Session
EnterCriticalSection (&cs_MSG);
for (i = 0; i < MsgDescr.Allocated && MsgDescr.Used != 0; i++)
{
LPSNMPMSG pMsg = snmpGetTableEntry(&MsgDescr, i);
if (pMsg->Session == hSession)
FreeMsg (i);
}
LeaveCriticalSection (&cs_MSG);
// PART_4: Free all other resources
// Free Entities allocated by the closing Session
EnterCriticalSection (&cs_ENTITY);
for (i = 0; i < EntsDescr.Allocated && EntsDescr.Used != 0; i++)
{
LPENTITY pEntity = snmpGetTableEntry(&EntsDescr, i);
if (pEntity->Session == hSession)
SnmpFreeEntity ((HSNMP_ENTITY) ULongToPtr(i+1));
}
LeaveCriticalSection (&cs_ENTITY);
// Free Contexts allocated by the closing Session
EnterCriticalSection (&cs_CONTEXT);
for (i = 0; i < CntxDescr.Allocated && CntxDescr.Used != 0; i++)
{
LPCTXT pCtxt = snmpGetTableEntry(&CntxDescr, i);
if (pCtxt->Session == hSession)
SnmpFreeContext ((HSNMP_CONTEXT) ULongToPtr(i+1));
}
LeaveCriticalSection (&cs_CONTEXT);
// Free VBLs allocated by the closing Session
EnterCriticalSection (&cs_VBL);
for (i = 0; i < VBLsDescr.Allocated && VBLsDescr.Used != 0; i++)
{
LPVBLS pVbl = snmpGetTableEntry(&VBLsDescr, i);
if (pVbl->Session == hSession)
SnmpFreeVbl ((HSNMP_VBL) ULongToPtr(i+1));
}
LeaveCriticalSection (&cs_VBL);
// Free PDUs allocated by the closing Session
EnterCriticalSection (&cs_PDU);
for (i = 0; i < PDUsDescr.Allocated && PDUsDescr.Used != 0; i++)
{
LPPDUS pPDU = snmpGetTableEntry(&PDUsDescr, i);
if (pPDU->Session == hSession)
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(i+1));
}
LeaveCriticalSection (&cs_PDU);
// Free the Session table entry used by the closing Session
EnterCriticalSection (&cs_SESSION);
snmpFreeTableEntry(&SessDescr, nSes);
LeaveCriticalSection (&cs_SESSION);
return (SNMPAPI_SUCCESS);
ERROR_OUT:
// As of 19980808 there are no error cases with a valid session
return (SaveError (0, lError));
} // end_SnmpClose
// SnmpSendMsg
SNMPAPI_STATUS SNMPAPI_CALL
SnmpSendMsg (IN HSNMP_SESSION hSession,
IN HSNMP_ENTITY hSrc,
IN HSNMP_ENTITY hDst,
IN HSNMP_CONTEXT hCtx,
IN HSNMP_PDU hPdu)
{
LPPDUS sendPdu;
BOOL fMsg;
DWORD nMsg;
DWORD pduType;
smiINT32 dllReqId;
smiOCTETS tmpContext;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
HSNMP_SESSION lSession = 0;
//
DWORD thrId;
SOCKET *pSock;
int tFamily;
SOCKADDR tAddr;
HANDLE *pThread;
//
DWORD nSrc;
DWORD nDst;
DWORD nCtx;
DWORD nPdu;
//
BOOL fBroadcast;
//
LPPDUS pPdu;
LPENTITY pEntSrc, pEntDst;
LPCTXT pCtxt;
LPSNMPMSG pMsg;
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
if (!snmpValidTableEntry(&SessDescr, HandleToUlong(hSession)-1))
{
lError = SNMPAPI_SESSION_INVALID;
goto ERROR_OUT;
}
// Save valid session for later error returns
lSession = hSession;
if (hSrc) // Allowed to be NULL
{
nSrc = HandleToUlong(hSrc) - 1;
if (!snmpValidTableEntry(&EntsDescr, nSrc))
{
lError = SNMPAPI_ENTITY_INVALID;
goto ERROR_OUT;
}
pEntSrc = snmpGetTableEntry(&EntsDescr, nSrc);
}
nDst = HandleToUlong(hDst) - 1;
if (!snmpValidTableEntry(&EntsDescr, nDst))
{
lError = SNMPAPI_ENTITY_INVALID;
goto ERROR_OUT;
}
pEntDst = snmpGetTableEntry(&EntsDescr, nDst);
nCtx = HandleToUlong(hCtx) - 1;
if (!snmpValidTableEntry(&CntxDescr, nCtx))
{
lError = SNMPAPI_CONTEXT_INVALID;
goto ERROR_OUT;
}
pCtxt = snmpGetTableEntry(&CntxDescr, nCtx);
nPdu = HandleToUlong(hPdu) - 1;
if (!snmpValidTableEntry(&PDUsDescr, nPdu))
{
lError = SNMPAPI_PDU_INVALID;
goto ERROR_OUT;
}
pPdu = snmpGetTableEntry(&PDUsDescr, nPdu);
if (!snmpValidTableEntry(&VBLsDescr, HandleToUlong(pPdu->VBL)-1))
{
lError = SNMPAPI_VBL_INVALID;
goto ERROR_OUT;
}
//--------------
tFamily = pEntDst->addr.inet.sin_family;
// enter the critical section for the TaskData structure to insure
// the atomicity of the Test&Set operation of the TaskData.[ip|ipx]Thread
EnterCriticalSection (&cs_TASK);
pThread = (tFamily==AF_IPX) ? &TaskData.ipxThread : &TaskData.ipThread;
pSock = (tFamily==AF_IPX) ? &TaskData.ipxSock : &TaskData.ipSock;
if (*pThread) // ASSERT(*pSock != INVALID_SOCKET)
{
LeaveCriticalSection(&cs_TASK);
goto CHANNEL_OPEN;
}
*pSock = socket (tFamily, SOCK_DGRAM, (tFamily==AF_IPX)?NSPROTO_IPX:0);
if (*pSock == INVALID_SOCKET)
{
LeaveCriticalSection(&cs_TASK);
lError = SNMPAPI_TL_NOT_SUPPORTED;
goto ERROR_OUT;
}
// try to set the socket for broadcasts. No matter the result
// a possible error will be caught later
// The following setsockopt call will be removed in Longhorn
fBroadcast = TRUE;
setsockopt (*pSock,
SOL_SOCKET,
SO_BROADCAST,
(CHAR *) &fBroadcast,
sizeof ( BOOL )
);
// Kludge for Win95 WinSock/IPX bug...have to "bind"
ZeroMemory (&tAddr, sizeof(SOCKADDR));
tAddr.sa_family = (USHORT)tFamily;
bind (*pSock, &tAddr, (tFamily==AF_IPX)?sizeof(SOCKADDR_IPX):sizeof(SOCKADDR_IN));
// Start "listener" and timer threads
*pThread = (HANDLE)_beginthreadex (NULL, 0, thrManager, (LPVOID)pSock, 0, &thrId);
if (*pThread == NULL)
{
closesocket (*pSock);
*pSock = INVALID_SOCKET;
lError = SNMPAPI_TL_RESOURCE_ERROR;
LeaveCriticalSection (&cs_TASK);
goto ERROR_OUT;
}
LeaveCriticalSection (&cs_TASK);
//---------------
CHANNEL_OPEN:
pduType = pPdu->type;
sendPdu = pPdu;
if (pEntDst->version == 1)
{ // Test for special v2 msg -> v1 dst operations
if (pduType == SNMP_PDU_TRAP)
{ // RFC 2089 v2 to v1 trap conversion
sendPdu = MapV2TrapV1 (hPdu);
if (sendPdu == NULL)
{
lError = SNMPAPI_OTHER_ERROR;
goto ERROR_OUT;
}
pduType = SNMP_PDU_V1TRAP;
}
else if (pduType == SNMP_PDU_INFORM)
{
lError = SNMPAPI_OPERATION_INVALID;
goto ERROR_OUT;
}
}
// Space check
EnterCriticalSection (&cs_MSG);
lError = snmpAllocTableEntry(&MsgDescr, &nMsg);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_PRECHECK;
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
// Now Build it
if (pduType == SNMP_PDU_RESPONSE || pduType == SNMP_PDU_TRAP)
dllReqId = pPdu->appReqId;
else
dllReqId = ++(TaskData.nLastReqId);
tmpContext.len = pCtxt->commLen;
tmpContext.ptr = pCtxt->commStr;
// Save BuildMessage status for later check
fMsg = BuildMessage (pEntDst->version-1, &tmpContext, sendPdu,
dllReqId, &(pMsg->Addr), &(pMsg->Size));
// If v2 to v1 trap conversion was required, then cleanup...
if (pduType == SNMP_PDU_V1TRAP)
{
FreeVarBindList (sendPdu->VBL_addr); // Checks for NULL
FreeV1Trap (sendPdu->v1Trap); // Checks for NULL
GlobalFree (sendPdu);
}
// If BuildMessage failed, that's all folks!
if (!fMsg)
{
snmpFreeTableEntry(&MsgDescr, nMsg);
lError = SNMPAPI_PDU_INVALID;
goto ERROR_PRECHECK;
}
pMsg->Session = hSession;
pMsg->Status = NP_SEND; // "send"
pMsg->Type = pduType;
pMsg->nRetransmitMode = TaskData.nRetransmitMode;
pMsg->dllReqId = dllReqId;
pMsg->appReqId = pPdu->appReqId;
pMsg->agentEntity = hDst;
pMsg->ourEntity = hSrc;
pMsg->Context = hCtx;
LeaveCriticalSection (&cs_MSG);
// Update reference counts for entities and contexts,
EnterCriticalSection (&cs_ENTITY);
if (hSrc)
pEntSrc->refCount++;
pEntDst->refCount++;
LeaveCriticalSection (&cs_ENTITY);
EnterCriticalSection (&cs_CONTEXT);
pCtxt->refCount++;
LeaveCriticalSection (&cs_CONTEXT);
// Prepare addressing info for traps
EnterCriticalSection (&cs_MSG);
CopyMemory (&(pMsg->Host), &pEntDst->addr, sizeof(SAS));
if (pduType == SNMP_PDU_V1TRAP ||
pduType == SNMP_PDU_TRAP ||
pduType == SNMP_PDU_INFORM)
{
if (tFamily == AF_IPX)
{
if (pMsg->Host.ipx.sa_socket == ntohs (IPX_SNMP_PORT))
pMsg->Host.ipx.sa_socket = htons (IPX_TRAP_PORT);
}
else // Assume AF_INET
{
if (pMsg->Host.inet.sin_port == ntohs (IP_SNMP_PORT))
pMsg->Host.inet.sin_port = htons(IP_TRAP_PORT);
}
}
// Send the packet
thrId = sendto (*pSock, pMsg->Addr, pMsg->Size,
0, (LPSOCKADDR)&(pMsg->Host), sizeof(SAS));
if (thrId == SOCKET_ERROR)
{
FreeMsg (nMsg);
lError = SNMPAPI_TL_OTHER;
goto ERROR_PRECHECK;
}
// Need to check for SOCKET_ERROR!
if (pduType == SNMP_PDU_TRAP ||
pduType == SNMP_PDU_V1TRAP ||
pduType == SNMP_PDU_RESPONSE)
{
FreeMsg (nMsg);
}
else
{
pMsg->Status = NP_SENT;
// Time entity's timeout value is stored as centiseconds in 32 bits
pMsg->Wait = pEntDst->nPolicyTimeout;
// Converting to milliseconds for timer operations could overflow
if (pMsg->Wait <= MAXCENTISECONDS) // So check first...if ok
pMsg->Wait *= 10; // Convert to milliseconds
else // eles...
pMsg->Wait = MAXMILLISECONDS; // Set to max milliseconds
pMsg->Tries = pMsg->PolicyTries = pEntDst->nPolicyRetry;
pMsg->Ticks = GetTickCount();
}
ERROR_PRECHECK:
LeaveCriticalSection (&cs_MSG);
if (lError == SNMPAPI_SUCCESS)
return (SNMPAPI_SUCCESS);
ERROR_OUT:
return (SaveError (lSession, lError));
} // end_SnmpSendMsg
// SnmpRecvMsg
SNMPAPI_STATUS SNMPAPI_CALL
SnmpRecvMsg (IN HSNMP_SESSION hSession,
OUT LPHSNMP_ENTITY srcEntity,
OUT LPHSNMP_ENTITY dstEntity,
OUT LPHSNMP_CONTEXT context,
OUT LPHSNMP_PDU pdu)
{
DWORD nMsg;
DWORD nPdu;
int pduType;
smiLPOCTETS community;
smiUINT32 version;
smiUINT32 nMode;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
HSNMP_SESSION lSession = 0;
DWORD nSes = HandleToUlong(hSession) - 1;
LPPDUS pPdu;
LPENTITY pEntity;
LPSNMPMSG pMsg;
DWORD lTime; // holds the local time for updating the nActualTimeout value
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
if (!snmpValidTableEntry(&SessDescr, nSes))
{
lError = SNMPAPI_SESSION_INVALID;
goto ERROR_OUT;
}
// Valid session...save for possible error return
lSession = hSession;
EnterCriticalSection (&cs_MSG);
// Find a message for the calling session
for (nMsg = 0; nMsg < MsgDescr.Allocated; nMsg++)
{
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
if (pMsg->Session == hSession &&
pMsg->Status == NP_READY)
break;
}
if (nMsg == MsgDescr.Allocated)
{
lError = SNMPAPI_NOOP;
goto ERROR_PRECHECK1;
}
if (!pMsg->Addr)
{
lError = SNMPAPI_MESSAGE_INVALID;
goto ERROR_PRECHECK1;
}
ERROR_PRECHECK1:
LeaveCriticalSection (&cs_MSG);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_OUT;
// Allocate a slot in PDU table
EnterCriticalSection (&cs_PDU);
lError = snmpAllocTableEntry(&PDUsDescr, &nPdu);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_PRECHECK2;
pPdu = snmpGetTableEntry(&PDUsDescr, nPdu);
nMode = ParseMessage (pMsg->Addr, pMsg->Size,
&version, &community, pPdu);
if (nMode != 0) // non-zero = error code
{
snmpFreeTableEntry(&PDUsDescr, nPdu);
FreeMsg (nMsg);
lError = SNMPAPI_PDU_INVALID;
goto ERROR_PRECHECK2;
}
pPdu->Session = hSession;
pPdu->appReqId = pMsg->appReqId;
ERROR_PRECHECK2:
LeaveCriticalSection (&cs_PDU);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_OUT;
pduType = pPdu->type;
EnterCriticalSection (&cs_ENTITY);
// for RESPONSE messages only, update the 'ActualRetry' and 'ActualTimeout' parameters
// for all the other messages, these params are meaningless
if (pduType == SNMP_PDU_RESPONSE)
{
// locate the agent (source) entity here
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->agentEntity)-1);
// update the nActualTimeout param of the agent (source) entity.
lTime = GetTickCount();
if (pMsg->Ticks > lTime)
// handle the time wrap case
// (~pMsg->Ticks + 1) is 2's complement of pMsg->Ticks
pEntity->nActualTimeout = (lTime + ~pMsg->Ticks + 1)/10;
else
pEntity->nActualTimeout = (lTime - pMsg->Ticks)/10;
// update the nActualRetry param of the agent (source) entity
pEntity->nActualRetry = pMsg->PolicyTries - pMsg->Tries;
}
if (srcEntity)
{
if (pduType == SNMP_PDU_TRAP ||
pduType == SNMP_PDU_INFORM ||
pduType != SNMP_PDU_RESPONSE)
{
int afType = pMsg->Host.ipx.sa_family;
char afHost[MAX_PATH+1];
afHost[MAX_PATH] = '\0';
EnterCriticalSection (&cs_XMODE);
SnmpGetTranslateMode (&nMode);
SnmpSetTranslateMode (SNMPAPI_UNTRANSLATED_V1);
if (afType == AF_IPX)
SnmpIpxAddressToStr (pMsg->Host.ipx.sa_netnum,
pMsg->Host.ipx.sa_nodenum,
afHost);
else // AF_INET
{
char * pszIpAddr;
pszIpAddr = inet_ntoa (pMsg->Host.inet.sin_addr);
if (NULL == pszIpAddr)
{
LeaveCriticalSection (&cs_XMODE);
lError = SNMPAPI_TL_OTHER;
goto ERROR_PRECHECK3;
}
strncpy (afHost, pszIpAddr, MAX_PATH);
}
if ((pMsg->agentEntity = SnmpStrToEntity (hSession, afHost)) == SNMPAPI_FAILURE)
{
LeaveCriticalSection (&cs_XMODE);
lError = SNMPAPI_OTHER_ERROR;
goto ERROR_PRECHECK3;
}
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->agentEntity)-1);
if (afType == AF_IPX)
pEntity->addr.ipx.sa_socket = pMsg->Host.ipx.sa_socket;
else // AF_INET
pEntity->addr.inet.sin_port = pMsg->Host.inet.sin_port;
SnmpSetTranslateMode (nMode);
LeaveCriticalSection (&cs_XMODE);
}
// Deliberate assignment...
if (*srcEntity = pMsg->agentEntity)
{
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->agentEntity)-1);
pEntity->refCount++;
}
}
if (dstEntity)
{ // Deliberate assignment...
if (*dstEntity = pMsg->ourEntity)
{
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->ourEntity)-1);
pEntity->refCount++;
}
}
ERROR_PRECHECK3:
LeaveCriticalSection (&cs_ENTITY);
if (lError != SNMPAPI_SUCCESS)
{
FreeOctetString (community);
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(nPdu+1));
FreeMsg (nMsg);
goto ERROR_OUT;
}
EnterCriticalSection (&cs_CONTEXT);
if (context)
{
if (pduType == SNMP_PDU_TRAP ||
pduType == SNMP_PDU_INFORM ||
pduType != SNMP_PDU_RESPONSE)
{
EnterCriticalSection (&cs_XMODE);
SnmpGetTranslateMode (&nMode);
SnmpSetTranslateMode (SNMPAPI_UNTRANSLATED_V1);
if ((pMsg->Context = SnmpStrToContext (hSession, community)) == SNMPAPI_FAILURE)
{
LeaveCriticalSection (&cs_XMODE);
lError = SNMPAPI_OTHER_ERROR;
goto ERROR_PRECHECK4;
}
SnmpSetTranslateMode (nMode);
LeaveCriticalSection (&cs_XMODE);
}
// Deliberate assignment...
if (*context = pMsg->Context)
((LPCTXT)snmpGetTableEntry(&CntxDescr, HandleToUlong(pMsg->Context)-1))->refCount++;
}
ERROR_PRECHECK4:
LeaveCriticalSection (&cs_CONTEXT);
if (lError != SNMPAPI_SUCCESS)
{
// rollback
if (context && *context)
{
SnmpFreeContext(*context);
*context = NULL;
}
if (dstEntity && *dstEntity)
{
SnmpFreeEntity(*dstEntity);
*dstEntity = NULL;
}
if (srcEntity && *srcEntity)
{
SnmpFreeEntity(*srcEntity);
*srcEntity = NULL;
}
FreeOctetString (community);
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(nPdu+1));
FreeMsg (nMsg);
goto ERROR_OUT;
}
FreeOctetString (community);
if (pdu)
*pdu = (HSNMP_PDU) ULongToPtr(nPdu+1);
else
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(nPdu+1));
// Mark SendRecv slot as free
FreeMsg (nMsg);
return (SNMPAPI_SUCCESS);
ERROR_OUT:
return (SaveError (lSession, lError));
} // end_SnmpRecvMsg
// Allocates a generic ACL to be used for the security descriptor of the SNMPTRAP service
PACL AllocGenericACL()
{
PACL pAcl;
PSID pSidAdmins, pSidUsers;
SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
DWORD dwAclLength;
pSidAdmins = pSidUsers = NULL;
if ( !AllocateAndInitializeSid( &Authority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pSidAdmins ) )
{
return NULL;
}
if ( !AllocateAndInitializeSid( &Authority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_USERS,
0, 0, 0, 0, 0, 0,
&pSidUsers ))
{
FreeSid(pSidAdmins);
return NULL;
}
dwAclLength = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) -
sizeof(ULONG) +
GetLengthSid(pSidAdmins) +
sizeof(ACCESS_ALLOWED_ACE) -
sizeof(ULONG) +
GetLengthSid(pSidUsers);
pAcl = GlobalAlloc (GPTR, dwAclLength);
if (pAcl != NULL)
{
if (!InitializeAcl( pAcl, dwAclLength, ACL_REVISION) ||
!AddAccessAllowedAce ( pAcl,
ACL_REVISION,
GENERIC_ALL,
pSidAdmins ) ||
!AddAccessAllowedAce ( pAcl,
ACL_REVISION,
GENERIC_READ | GENERIC_EXECUTE,
pSidUsers ))
{
GlobalFree(pAcl);
pAcl = NULL;
}
}
FreeSid(pSidAdmins);
FreeSid(pSidUsers);
return pAcl;
}
// frees a generic ACL
void FreeGenericACL( PACL pAcl)
{
if (pAcl != NULL)
GlobalFree(pAcl);
}
// SnmpRegister
SNMPAPI_STATUS SNMPAPI_CALL
SnmpRegister (IN HSNMP_SESSION hSession,
IN HSNMP_ENTITY hSrc,
IN HSNMP_ENTITY hDst,
IN HSNMP_CONTEXT hCtx,
IN smiLPCOID notification,
IN smiUINT32 status)
{
DWORD nNotice, nFound;
smiINT32 nCmp;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
HSNMP_SESSION lSession = 0;
DWORD nSes = HandleToUlong(hSession) - 1;
DWORD nSrc;
DWORD nDst;
DWORD nCtx;
LPENTITY pEntSrc, pEntDst;
LPCTXT pCtxt;
LPTRAPNOTICE pTrap;
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
if (status != SNMPAPI_OFF) status = SNMPAPI_ON;
if (status == SNMPAPI_ON)
{
if (!snmpValidTableEntry(&SessDescr, nSes))
{
lError = SNMPAPI_SESSION_INVALID;
goto ERROR_OUT;
}
else // Got a valid session...save for possible error return
lSession = hSession;
}
if (hSrc)
{
nSrc = HandleToUlong(hSrc) - 1;
if (!snmpValidTableEntry(&EntsDescr, nSrc))
{
lError = SNMPAPI_ENTITY_INVALID;
goto ERROR_OUT;
}
pEntSrc = snmpGetTableEntry(&EntsDescr, nSrc);
}
if (hDst)
{
nDst = HandleToUlong(hDst) - 1;
if (!snmpValidTableEntry(&EntsDescr, nDst))
{
lError = SNMPAPI_ENTITY_INVALID;
goto ERROR_OUT;
}
pEntDst = snmpGetTableEntry(&EntsDescr, nDst);
}
if (hCtx)
{
nCtx = HandleToUlong(hCtx) - 1;
if (!snmpValidTableEntry(&CntxDescr, nCtx))
{
lError = SNMPAPI_CONTEXT_INVALID;
goto ERROR_OUT;
}
pCtxt = snmpGetTableEntry(&CntxDescr, nCtx);
}
if (notification)
{
if ((!notification->len) || notification->len > MAXOBJIDSIZE)
{
lError = SNMPAPI_SIZE_INVALID;
goto ERROR_OUT;
}
if (!notification->ptr)
{
lError = SNMPAPI_OID_INVALID;
goto ERROR_OUT;
}
}
EnterCriticalSection (&cs_TRAP);
for (nNotice = 0, nFound = 0; nNotice < TrapDescr.Allocated &&
nFound < TrapDescr.Used; nNotice++)
{ // First, count now many we've tested
pTrap = snmpGetTableEntry(&TrapDescr, nNotice);
if (pTrap->Session) nFound++;
// then search for a parameter matches
if ((pTrap->Session == hSession) &&
(pTrap->ourEntity == hSrc) &&
(pTrap->agentEntity == hDst) &&
(pTrap->Context == hCtx))
{ // Ok, we found one
if (!notification)
// if the notification parameter is null, then we
// want to either turn on or turn off all notifications
// from this match...so clear any entries already in
// the table and we'll add this wildcard entry if the
// operation is SNMPAPI_ON at the end.
{
DWORD dwUsed = TrapDescr.Used;
FreeRegister (nNotice);
if (dwUsed == TrapDescr.Used+1)
{
// Adjustment to nFound because FreeRegister has just decremented
// TrapDescr.Used by 1
nFound--;
}
continue;
}
else // notification specified
{
if (!pTrap->notification.len)
{
// Redundant request (already wildcarded)
// Skip it and return!
goto ERROR_PRECHECK;
}
else // pTrap->notification
{
// compare OIDs
SnmpOidCompare (notification, &(pTrap->notification),
0, &nCmp);
if (nCmp) // no match
continue; // ...try the next one
else // !nCcmp
{ // got a match...
// if SNMPAPI_ON, redundant request...skip it and return
// if SNMPAPI_OFF, free the entry first
if (status != SNMPAPI_ON)
FreeRegister (nNotice); // SNMPAPI_OFF
goto ERROR_PRECHECK;
} // end_else_!nCmp
} // end_else_TrapTable[nNotice].notificatin
} // end_else_notification_specified
} // end_if_we_found_one
} // end_for
if (status == SNMPAPI_OFF)
{ // Found nothing to turn off...that's ok.
goto ERROR_PRECHECK;
}
//
// Special check for NT...is SNMPTRAP service running?
if (TaskData.trapThread == NULL &&
TaskData.sEnv.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
DWORD dwReturn = SNMPAPI_TL_NOT_INITIALIZED;
DWORD pMode = PIPE_WAIT | PIPE_READMODE_MESSAGE;
LPCTSTR svcName = "SNMPTRAP";
LPCTSTR svcDesc = "SNMP Trap Service";
LPCTSTR svcPath = "%SystemRoot%\\system32\\snmptrap.exe";
SC_HANDLE scmHandle = NULL;
SC_HANDLE svcHandle = NULL;
SERVICE_STATUS svcStatus;
BOOL fStatus;
// Minimal SCM connection, for case when SNMPTRAP is running
scmHandle = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
if (scmHandle == NULL)
goto DONE_SC;
svcHandle = OpenService (scmHandle, svcName, SERVICE_QUERY_STATUS);
if (svcHandle == NULL)
{
if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
goto DONE_SC;
else
{ // Must attempt to create service
PACL pAcl;
SECURITY_DESCRIPTOR S_Desc;
// Need new scmHandle with admin priv
CloseServiceHandle (scmHandle);
scmHandle = OpenSCManager (NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (scmHandle == NULL)
goto DONE_SC; // Could not open SCM with admin priv
// Bug# 179644 The SNMP trap service should not run in the LocalSystem account
// We create the service with LocalService account instead of LocalSystem.
svcHandle = CreateService (scmHandle, svcName, svcDesc,
WRITE_DAC|SERVICE_QUERY_STATUS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
svcPath,
NULL, NULL,
"TCPIP\0EventLog\0\0",
"NT AUTHORITY\\LocalService", NULL);
if (svcHandle == NULL)
goto DONE_SC; // Could not create service
if (!InitializeSecurityDescriptor (&S_Desc, SECURITY_DESCRIPTOR_REVISION))
{
goto DONE_SC;
}
if ((pAcl = AllocGenericACL()) == NULL ||
!SetSecurityDescriptorDacl (&S_Desc, TRUE, pAcl, FALSE))
{
FreeGenericACL(pAcl); // will free if necessary
goto DONE_SC;
}
if (!SetServiceObjectSecurity (svcHandle, DACL_SECURITY_INFORMATION, &S_Desc))
{
FreeGenericACL(pAcl);
goto DONE_SC;
}
FreeGenericACL(pAcl);
}
}
fStatus = QueryServiceStatus (svcHandle, &svcStatus);
while (fStatus)
{
switch (svcStatus.dwCurrentState)
{
case SERVICE_RUNNING:
dwReturn = SNMPAPI_SUCCESS;
goto DONE_SC;
case SERVICE_STOPPED:
// Start SNMPTRAP service if necessary
CloseServiceHandle (svcHandle);
svcHandle = OpenService (scmHandle, svcName, SERVICE_START|SERVICE_QUERY_STATUS);
if (svcHandle == NULL)
goto DONE_SC; // Could not start service
svcStatus.dwCurrentState = SERVICE_START_PENDING;
fStatus = StartService (svcHandle, 0, NULL);
break;
case SERVICE_STOP_PENDING:
case SERVICE_START_PENDING:
Sleep (MAX_PENDING_WAIT);
fStatus = QueryServiceStatus (svcHandle, &svcStatus);
break;
case SERVICE_PAUSED:
case SERVICE_PAUSE_PENDING:
case SERVICE_CONTINUE_PENDING:
default:
fStatus = FALSE; // Nothing to do about these
break;
}
}
DONE_SC:
if (scmHandle)
CloseServiceHandle (scmHandle);
if (svcHandle)
CloseServiceHandle (svcHandle);
if (dwReturn != SNMPAPI_SUCCESS)
{
ERROR_PRECHECK1:
lError = dwReturn;
goto ERROR_PRECHECK;
}
// Setup for pipe-oriented operations
dwReturn = SNMPAPI_TL_RESOURCE_ERROR;
// block on instance of server pipe becoming available
if (!WaitNamedPipe (SNMPTRAPPIPE, TRAPSERVERTIMEOUT))
goto ERROR_PRECHECK1;
TaskData.trapPipe =
// Bug# 270672 Change FILE_ATTRIBUTE_NORMAL to FILE_FLAG_OVERLAPPED
CreateFile (SNMPTRAPPIPE, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (TaskData.trapPipe == INVALID_HANDLE_VALUE)
goto ERROR_PRECHECK1;
if (!SetNamedPipeHandleState (TaskData.trapPipe, &pMode, NULL, NULL))
{
CloseHandle (TaskData.trapPipe);
TaskData.trapPipe = INVALID_HANDLE_VALUE;
goto ERROR_PRECHECK1;
}
} // end_NT check for SNMPTRAP service
//If we got this far, add it
lError = snmpAllocTableEntry(&TrapDescr, &nNotice);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_PRECHECK;
pTrap = snmpGetTableEntry(&TrapDescr, nNotice);
// add it
pTrap->Session = hSession;
// Deliberate assignments in next three if statements
if (pTrap->ourEntity = hSrc)
//EntityTable[nSrc-1].refCount++; -- was this a bug??? nSrc is already 0 based
pEntSrc->refCount++;
if (pTrap->agentEntity = hDst)
//EntityTable[nDst-1].refCount++; -- was this a bug??? nDst is already 0 based
pEntDst->refCount++;
if (pTrap->Context = hCtx)
//ContextTable[nCtx-1].refCount++; -- was this a bug?? nCtx is already 0 based
pCtxt->refCount++;
if (notification)
{ // Reproduce the OID
pTrap->notification.ptr = NULL;
// Deliberate assignment in next statement
if (pTrap->notification.len = notification->len)
{
if (pTrap->notification.len > MAXTRAPIDS)
pTrap->notification.len = MAXTRAPIDS;
if (notification->ptr)
{
// Deliberate assignment in next statement
pTrap->notification.ptr = &(pTrap->notificationValue[0]);
CopyMemory (pTrap->notification.ptr, notification->ptr,
pTrap->notification.len * sizeof(smiUINT32));
}
}
}
if (TaskData.trapThread == NULL)
{
DWORD thrId;
TaskData.trapThread = (HANDLE)_beginthreadex (NULL, 0, thrTrap, NULL, 0, &thrId);
if (TaskData.trapThread == NULL)
{
FreeRegister(nNotice);
lError = SNMPAPI_TL_RESOURCE_ERROR;
}
}
ERROR_PRECHECK:
LeaveCriticalSection (&cs_TRAP);
if (lError == SNMPAPI_SUCCESS)
return (SNMPAPI_SUCCESS);
ERROR_OUT:
return (SaveError (lSession, lError));
} // end_SnmpRegister
void FreeMsg (DWORD nMsg)
{
LPSNMPMSG pMsg;
EnterCriticalSection (&cs_MSG);
// Decrement reference counts
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
SnmpFreeEntity (pMsg->agentEntity);
SnmpFreeEntity (pMsg->ourEntity);
SnmpFreeContext (pMsg->Context);
if (pMsg->Addr)
GlobalFree (pMsg->Addr);
snmpFreeTableEntry(&MsgDescr, nMsg);
LeaveCriticalSection (&cs_MSG);
return;
} // end_FreeMsg
SNMPAPI_STATUS SNMPAPI_CALL
SnmpListen (IN HSNMP_ENTITY hEntity,
IN smiUINT32 status)
{
smiUINT32 nAgent = 0;
DWORD thrId;
DWORD nEntity = HandleToUlong(hEntity) - 1;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
HSNMP_SESSION lSession = 0;
LPENTITY pEntity;
LPAGENT pAgent;
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
if (!snmpValidTableEntry(&EntsDescr, nEntity))
{
lError = SNMPAPI_ENTITY_INVALID;
goto ERROR_OUT;
}
pEntity = snmpGetTableEntry(&EntsDescr, nEntity);
lSession = pEntity->Session;
if (status != SNMPAPI_ON && status != SNMPAPI_OFF)
{
lError = SNMPAPI_MODE_INVALID;
goto ERROR_OUT;
}
EnterCriticalSection (&cs_ENTITY);
EnterCriticalSection (&cs_AGENT);
if (status)
{ // status == SNMPAPI_ON
int nProto = IPPROTO_UDP;
int nSize = sizeof(SOCKADDR_IN);
int nFamily = pEntity->addr.inet.sin_family;
if (pEntity->Agent)
{ // Entity already running as agent
lError = SNMPAPI_NOOP;
goto ERROR_PRECHECK;
}
// Allocate a slot in AGENT table
lError = snmpAllocTableEntry(&AgentDescr, &nAgent);
if (lError != SNMPAPI_SUCCESS)
goto ERROR_PRECHECK;
pAgent = snmpGetTableEntry(&AgentDescr, nAgent);
// Agent table entry allocated...setup for agent thread
if (nFamily == AF_IPX)
{
nProto = NSPROTO_IPX;
nSize = sizeof(SOCKADDR_IPX);
}
pAgent->Socket = socket (nFamily, SOCK_DGRAM, nProto);
if (pAgent->Socket == INVALID_SOCKET)
{
snmpFreeTableEntry(&AgentDescr, nAgent);
lError = SNMPAPI_TL_RESOURCE_ERROR;
goto ERROR_PRECHECK;
}
if (bind (pAgent->Socket,
(LPSOCKADDR)&pEntity->addr, nSize)
== SOCKET_ERROR)
{
closesocket (pAgent->Socket);
snmpFreeTableEntry(&AgentDescr, nAgent);
lError = SNMPAPI_TL_OTHER;
goto ERROR_PRECHECK;
}
// Make Entity and Agent point to each other
pEntity->Agent = nAgent + 1;
pAgent->Entity = hEntity;
pAgent->Session = lSession;
// Create agent thread...needs error checking
pAgent->Thread = (HANDLE)_beginthreadex (NULL, 0, thrAgent, (LPVOID) ULongToPtr(nAgent), 0, &thrId);
if (pAgent->Thread == NULL)
{
closesocket(pAgent->Socket);
snmpFreeTableEntry(&AgentDescr, nAgent);
lError = SNMPAPI_TL_RESOURCE_ERROR;
goto ERROR_PRECHECK;
}
} // end_if status == SNMPAPI_ON
else
{ // status == SNMPAPI_OFF
if (!pEntity->Agent)
{ // Entity not running as agent
lError = SNMPAPI_NOOP;
goto ERROR_PRECHECK;
}
// Entity is running as agent
nAgent = pEntity->Agent - 1;
pAgent = snmpGetTableEntry(&AgentDescr, nAgent);
closesocket (pAgent->Socket);
WaitForSingleObject (pAgent->Thread, INFINITE);
CloseHandle (pAgent->Thread);
snmpFreeTableEntry(&AgentDescr, nAgent);
// Must terminate entity's agent status
pEntity->Agent = 0;
// Must terminate entity if nothing else was using it
if (pEntity->refCount == 0)
SnmpFreeEntity (hEntity);
} // end_else status == SNMPAPI_OFF
ERROR_PRECHECK:
LeaveCriticalSection (&cs_AGENT);
LeaveCriticalSection (&cs_ENTITY);
ERROR_OUT:
if (lError == SNMPAPI_SUCCESS)
return (SNMPAPI_SUCCESS);
else
return (SaveError (lSession, lError));
} // end_SnmpListen()
SNMPAPI_STATUS SNMPAPI_CALL
SnmpCancelMsg (HSNMP_SESSION hSession, smiINT32 nReqID)
{
DWORD nMsg = 0;
DWORD nFound = 0;
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
HSNMP_SESSION lSession = 0;
LPSNMPMSG pMsg;
if (TaskData.hTask == 0)
{
lError = SNMPAPI_NOT_INITIALIZED;
goto ERROR_OUT;
}
if (!snmpValidTableEntry(&SessDescr, HandleToUlong(hSession)-1))
{
lError = SNMPAPI_SESSION_INVALID;
goto ERROR_OUT;
}
lSession = hSession;
EnterCriticalSection (&cs_MSG);
while (nFound < MsgDescr.Used && nMsg < MsgDescr.Allocated)
{
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
// Deliberate assignement in next conditional
if (pMsg->Session)
{
nFound++;
if (pMsg->Session == hSession)
{
if (pMsg->Status == NP_SENT &&
pMsg->appReqId == (smiUINT32)nReqID)
{
FreeMsg (nMsg);
goto ERROR_PRECHECK;
}
}
}
nMsg++;
}
// Falied to find a MSG that matched the request
lError = SNMPAPI_PDU_INVALID;
ERROR_PRECHECK:
LeaveCriticalSection (&cs_MSG);
if (lError == SNMPAPI_SUCCESS)
return (SNMPAPI_SUCCESS);
// else...failure case
ERROR_OUT:
return (SaveError (lSession, lError));
} // end_SnmpCancelMsg