www.pudn.com > snmp.rar > servcomm.c
/*++
Copyright (c) 1992-1996 Microsoft Corporation
Module Name:
servcomm.c
Abstract:
Provides socket commmunications functionality for Proxy Agent.
Environment:
User Mode - Win32
Revision History:
10-May-1996 DonRyan
Removed banner from Technology Dynamics, Inc.
--*/
//--------------------------- WINDOWS DEPENDENCIES --------------------------
//--------------------------- STANDARD DEPENDENCIES -- #include ----
#include
#include
#include
#include
#include
#include
#include
#include
//--------------------------- MODULE DEPENDENCIES -- #include"xxxxx.h" ------
#include
#include
#include "regconf.h"
#include "..\common\wellknow.h"
#include "..\common\evtlog.h"
//--------------------------- SELF-DEPENDENCY -- ONE #include"module.h" -----
//--------------------------- PUBLIC VARIABLES --(same as in module.h file)--
DWORD timeZeroReference;
extern SERVICE_STATUS_HANDLE hService;
extern SERVICE_STATUS status;
extern BOOL noservice;
extern HANDLE g_hTerminationEvent;
extern HINSTANCE g_hInstance;
extern HWND hWnd;
//--------------------------- PRIVATE CONSTANTS -----------------------------
#define bzero(lp, size) (void)memset(lp, 0, size)
#define bcopy(slp, dlp, size) (void)memcpy(dlp, slp, size)
#define bcmp(slp, dlp, size) memcmp(dlp, slp, size)
#define CTAMTimeout ((DWORD)30000)
#define MAX_IPX_ADDR_LEN 64
//--------------------------- PRIVATE STRUCTS -------------------------------
typedef struct {
int family;
int type;
int protocol;
struct sockaddr localAddress;
} Session;
//--------------------------- PRIVATE VARIABLES -----------------------------
#define RECVBUFSIZE 4096
#define NPOLLFILE 2 // UDP and IPX
static SOCKET fdarray[NPOLLFILE];
static INT fdarrayLen;
CRITICAL_SECTION g_commThreadCritSec;
#define SNMP_AGENT_WND_CLASS "Microsoft SNMP Agent"
#define SNMP_AGENT_WND_MESSAGE (WM_USER+100)
static HWND g_hwndAgent;
static BYTE * g_recvBuf = NULL;
//--------------------------- PRIVATE PROTOTYPES ----------------------------
VOID trapThread(VOID *threadParam);
VOID agentCommThread(VOID *threadParam);
BOOL filtmgrs(struct sockaddr *source, INT sourceLen);
SNMPAPI SnmpServiceProcessMessage(
IN OUT BYTE **pBuf,
IN OUT UINT *length);
//--------------------------- PRIVATE PROCEDURES ----------------------------
LPSTR
AddrToString(
struct sockaddr * pSockAddr
)
{
static CHAR ipxAddr[MAX_IPX_ADDR_LEN];
// determine family
if (pSockAddr->sa_family == AF_INET) {
struct sockaddr_in * pSockAddrIn;
// obtain pointer to protocol specific structure
pSockAddrIn = (struct sockaddr_in * )pSockAddr;
// forward to winsock conversion function
return inet_ntoa(pSockAddrIn->sin_addr);
} else if (pSockAddr->sa_family == AF_IPX) {
struct sockaddr_ipx * pSockAddrIpx;
// obtain pointer to protocol specific structure
pSockAddrIpx = (struct sockaddr_ipx * )pSockAddr;
// transfer ipx address to static buffer
sprintf(ipxAddr,
"%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x",
(BYTE)pSockAddrIpx->sa_netnum[0],
(BYTE)pSockAddrIpx->sa_netnum[1],
(BYTE)pSockAddrIpx->sa_netnum[2],
(BYTE)pSockAddrIpx->sa_netnum[3],
(BYTE)pSockAddrIpx->sa_nodenum[0],
(BYTE)pSockAddrIpx->sa_nodenum[1],
(BYTE)pSockAddrIpx->sa_nodenum[2],
(BYTE)pSockAddrIpx->sa_nodenum[3],
(BYTE)pSockAddrIpx->sa_nodenum[4],
(BYTE)pSockAddrIpx->sa_nodenum[5]
);
// return addr
return ipxAddr;
}
// failure
return NULL;
}
LRESULT
CALLBACK
AgentWndProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
struct sockaddr source;
int sourceLen;
int length;
struct sockaddr_in *saddr;
SOCKET commSocket = (SOCKET)wParam;
BYTE * sendBuf;
// see if agent message specified
if (uMsg == SNMP_AGENT_WND_MESSAGE) {
// see if read event is signalled
if ((WSAGETSELECTERROR(lParam) == NOERROR) &&
(WSAGETSELECTEVENT(lParam) & FD_READ)) {
EnterCriticalSection(&g_commThreadCritSec);
sourceLen = sizeof(source);
if ((length = recvfrom(commSocket, g_recvBuf, RECVBUFSIZE,
0, &source, &sourceLen)) == -1)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: PDU: error on recvfrom %d.\n",GetLastError()));
LeaveCriticalSection(&g_commThreadCritSec);
return (1);
}
if (length == RECVBUFSIZE)
{
SNMPDBG((SNMP_LOG_TRACE,
"SNMP: PDU: recvfrom exceeded %d octets.\n", RECVBUFSIZE));
LeaveCriticalSection(&g_commThreadCritSec);
return (1);
}
// verify permittedManagers
if (!filtmgrs(&source, sourceLen))
{
LeaveCriticalSection(&g_commThreadCritSec);
return (1);
}
sendBuf = g_recvBuf;
saddr = (struct sockaddr_in *)&source;
SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: request received from %s (%d octets).\n",
AddrToString(&source), length));
if (!SnmpServiceProcessMessage(&sendBuf, &length))
{
SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: error on SnmpServiceProcessMessage %d\n",
GetLastError()));
LeaveCriticalSection(&g_commThreadCritSec);
return (1);
}
if ((length = sendto(commSocket, sendBuf, length,
0, &source, sizeof(source))) == -1)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: PDU: error %d sending response pdu.\n",
GetLastError()));
SnmpUtilMemFree(sendBuf);
LeaveCriticalSection(&g_commThreadCritSec);
return (1);
}
// receive send buffer
if (sendBuf != g_recvBuf) {
SnmpUtilMemFree(sendBuf);
}
SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: response sent to %s (%d octets).\n",
AddrToString(&source), length));
LeaveCriticalSection(&g_commThreadCritSec);
}
return (0);
} else if (uMsg == WM_DESTROY) {
PostQuitMessage(0);
return(0);
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
BOOL
RegisterAgentWndClass(
)
{
BOOL fOk;
WNDCLASS wc;
// initialize notification window class
wc.lpfnWndProc = (WNDPROC)AgentWndProc;
wc.lpszClassName = SNMP_AGENT_WND_CLASS;
wc.lpszMenuName = NULL;
wc.hInstance = g_hInstance;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.cbWndExtra = 0;
wc.cbClsExtra = 0;
wc.style = 0;
// register class
fOk = RegisterClass(&wc);
if (!fOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: INIT: RegisterClass returned %d.\n",
GetLastError()
));
}
return fOk;
}
BOOL
UnregisterAgentWndClass(
)
{
BOOL fOk;
// unregister notification window class
fOk = UnregisterClass(
SNMP_AGENT_WND_CLASS,
g_hInstance
);
if (!fOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: INIT: UnregisterClass returned %d.\n",
GetLastError()
));
}
return fOk;
}
BOOL
CreateAgentWnd(
)
{
BOOL fOk;
HWND hwnd;
// create notification window
hwnd = CreateWindow(
SNMP_AGENT_WND_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_hInstance,// handle to application instance
NULL // pointer to window-creation data
);
// validate window handle
if (hwnd != NULL) {
// transfer
g_hwndAgent = hwnd;
// success
fOk = TRUE;
} else {
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: INIT: CreateWindow returned %d.\n",
GetLastError()
));
// transfer
g_hwndAgent = NULL;
// failure
fOk = FALSE;
}
return fOk;
}
BOOL
DestroyAgentWnd(
)
{
BOOL fOk;
// validate handle
if (g_hwndAgent != NULL) {
// destroy notification window
fOk = DestroyWindow(g_hwndAgent);
if (!fOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: INIT: DestroyWindow returned %d.\n",
GetLastError()
));
}
}
return fOk;
}
//--------------------------- PUBLIC PROCEDURES -----------------------------
BOOL agentConfigInit(VOID)
{
Session session;
SOCKET sd;
DWORD threadId;
HANDLE hCommThread;
DWORD dwResult;
INT i;
WSADATA WSAData;
WORD wVersionRequested;
BOOL fSuccess;
INT pseudoAgentsLen;
INT j;
AsnObjectIdentifier tmpView;
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: initializing master agent.\n"));
wVersionRequested = MAKEWORD( 1, 1 );
if (i = WSAStartup(wVersionRequested, &WSAData))
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on WSAStartup %d\n", i));
return FALSE;
}
// initialize configuration from registry...
if (!regconf())
{
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: error on regconf %d\n", GetLastError()));
return FALSE;
}
if (!SnmpSvcGenerateColdStartTrap(0))
{
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: error on SnmpSvcGenerateColdStartTrap %d\n", GetLastError()));
//not serious error
}
timeZeroReference = SnmpSvcInitUptime() / 10;
pseudoAgentsLen = extAgentsLen;
for (i=0; i < extAgentsLen; i++)
{
extAgents[i].fInitedOk = TRUE;
// load extension DLL (if not already...
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: %s loading.\n", extAgents[i].pathName));
if ((extAgents[i].hExtension = GetModuleHandle(extAgents[i].pathName)) == NULL)
{
if ((extAgents[i].hExtension =
LoadLibrary(extAgents[i].pathName)) == NULL)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d loading %s\n", GetLastError(), extAgents[i].pathName));
SnmpSvcReportEvent(SNMP_EVENT_INVALID_EXTENSION_AGENT_DLL, 1, &extAgents[i].pathName, GetLastError());
extAgents[i].fInitedOk = FALSE;
}
}
if (extAgents[i].fInitedOk)
{
if ((extAgents[i].initAddr = GetProcAddress(extAgents[i].hExtension,"SnmpExtensionInit")) == NULL)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d resolving SnmpExtensionInit in %s\n", GetLastError(), extAgents[i].pathName));
SnmpSvcReportEvent(SNMP_EVENT_INVALID_EXTENSION_AGENT_DLL, 1, &extAgents[i].pathName, GetLastError());
extAgents[i].fInitedOk = FALSE;
}
else if ((extAgents[i].queryAddr =
GetProcAddress(extAgents[i].hExtension,"SnmpExtensionQuery")) == NULL)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d resolving SnmpExtensionQuery in %s\n", GetLastError(), extAgents[i].pathName));
SnmpSvcReportEvent(SNMP_EVENT_INVALID_EXTENSION_AGENT_DLL, 1, &extAgents[i].pathName, GetLastError());
extAgents[i].fInitedOk = FALSE;
}
else if ((extAgents[i].trapAddr =
GetProcAddress(extAgents[i].hExtension,"SnmpExtensionTrap")) == NULL)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d resolving SnmpExtensionTrap in %s\n", GetLastError(), extAgents[i].pathName));
SnmpSvcReportEvent(SNMP_EVENT_INVALID_EXTENSION_AGENT_DLL, 1, &extAgents[i].pathName, GetLastError());
extAgents[i].fInitedOk = FALSE;
}
else if (!(*extAgents[i].initAddr)(timeZeroReference,
&extAgents[i].hPollForTrapEvent,
&(extAgents[i].supportedView)))
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: SnmpExtensionInit failed in %s\n", extAgents[i].pathName));
SnmpSvcReportEvent(SNMP_EVENT_INVALID_EXTENSION_AGENT_DLL, 1, &extAgents[i].pathName, GetLastError());
extAgents[i].fInitedOk = FALSE;
}
else
{
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: %s supports %s.\n",
extAgents[i].pathName, SnmpUtilOidToA(&extAgents[i].supportedView)));
if ((extAgents[i].initAddrEx =
GetProcAddress(extAgents[i].hExtension,"SnmpExtensionInitEx")) != NULL)
{
j = 1;
while ((*extAgents[i].initAddrEx)(&tmpView))
{
pseudoAgentsLen++;
extAgents = (CfgExtensionAgents *) SnmpUtilMemReAlloc(extAgents,
(pseudoAgentsLen * sizeof(CfgExtensionAgents)));
extAgents[pseudoAgentsLen-1].supportedView.ids =
tmpView.ids;
extAgents[pseudoAgentsLen-1].supportedView.idLength =
tmpView.idLength;
extAgents[pseudoAgentsLen-1].initAddr =
extAgents[i].initAddr;
extAgents[pseudoAgentsLen-1].queryAddr =
extAgents[i].queryAddr;
extAgents[pseudoAgentsLen-1].trapAddr =
extAgents[i].trapAddr;
extAgents[pseudoAgentsLen-1].pathName =
extAgents[i].pathName;
extAgents[pseudoAgentsLen-1].hExtension =
extAgents[i].hExtension;
extAgents[pseudoAgentsLen-1].fInitedOk = TRUE;
extAgents[pseudoAgentsLen-1].hPollForTrapEvent = NULL;
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: %s supports %s.\n",
extAgents[pseudoAgentsLen-1].pathName, SnmpUtilOidToA(&tmpView)));
j++;
}
}
}
} // end if fIntedOk
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: %s loaded %s.\n",extAgents[i].pathName,
extAgents[i].fInitedOk ? "successfully" : "unsuccessfully"));
} // end for ()
extAgentsLen = pseudoAgentsLen;
fdarrayLen = 0;
{
struct sockaddr_in localAddress_in;
struct sockaddr_ipx localAddress_ipx;
struct servent *serv;
session.family = AF_INET;
session.type = SOCK_DGRAM;
session.protocol = 0;
localAddress_in.sin_family = AF_INET;
if ((serv = getservbyname( "snmp", "udp" )) == NULL) {
localAddress_in.sin_port =
htons(WKSN_UDP_GETSET /*extract address.TAddress*/ );
} else {
localAddress_in.sin_port = (SHORT)serv->s_port;
}
localAddress_in.sin_addr.s_addr = ntohl(INADDR_ANY);
bcopy(&localAddress_in,
&session.localAddress,
sizeof(localAddress_in));
fSuccess = FALSE;
if ((sd = socket(session.family, session.type,
session.protocol)) == (SOCKET)-1)
{
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: error %d creating udp socket.\n", GetLastError()));
}
else if (bind(sd, &session.localAddress,
sizeof(session.localAddress)) != 0)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d binding udp socket.\n", GetLastError()));
}
else // successfully opened an UDP socket
{
fdarray[fdarrayLen] = sd;
fdarrayLen += 1;
fSuccess = TRUE;
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: setup udp listen port.\n"));
}
// now setup IPX socket
session.family = PF_IPX;
session.type = SOCK_DGRAM;
session.protocol = NSPROTO_IPX;
bzero(&localAddress_ipx, sizeof(localAddress_ipx));
localAddress_ipx.sa_family = PF_IPX;
localAddress_ipx.sa_socket = htons(WKSN_IPX_GETSET);
bcopy(&localAddress_ipx, &session.localAddress,
sizeof(localAddress_ipx));
if ((sd = socket(session.family, session.type,
session.protocol)) == (SOCKET)-1)
{
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: error %d creating ipx socket.\n", GetLastError()));
}
else if (bind(sd, &session.localAddress,
sizeof(session.localAddress)) != 0)
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d binding ipx socket.\n", GetLastError()));
}
else
{
fdarray[fdarrayLen] = sd;
fdarrayLen += 1;
fSuccess = TRUE;
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: setup ipx listen port.\n"));
}
if (!fSuccess)
return FALSE; // can't open either socket
}
// --------- END: PROTOCOL SPECIFIC SOCKET CODE END. ---------------
// allocate receive buffer for incoming snmp messages
if ((g_recvBuf = (BYTE *)SnmpUtilMemAlloc(RECVBUFSIZE)) == NULL) {
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: could not allocate receive buffer.\n"));
SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
// initialize critical used with comm thread
InitializeCriticalSection(&g_commThreadCritSec);
// create communication thread
hCommThread = CreateThread(
NULL, // lpThreadAttributes
0, // dwStackSize
(LPTHREAD_START_ROUTINE)agentCommThread,
NULL, // lpParameters
0, // dwCreationFlags
&threadId
);
// validate thread handle
if (hCommThread == NULL) {
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d creating agentCommThread.\n", GetLastError()));
SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError());
goto cleanup;
}
if (!noservice) {
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: setting service status to running.\n"));
status.dwCurrentState = SERVICE_RUNNING;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
if (!SetServiceStatus(hService, &status))
{
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on SetServiceStatus %d\n", GetLastError()));
SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError());
goto cleanup;
}
else
{
SnmpSvcReportEvent(SNMP_EVENT_SERVICE_STARTED, 0, NULL, NO_ERROR);
}
}
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: agentTrapThread entered.\n"));
// become the trap thread...
trapThread(NULL);
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: agentTrapThread terminated.\n"));
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: waiting for agentCommThread to terminate.\n"));
cleanup:
// wait for threads to terminate
dwResult = WaitForSingleObject(
hCommThread,
CTAMTimeout // dwMilliseconds
);
// evaluate return status
if (dwResult == WAIT_FAILED) {
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d waiting for agentCommThread to terminate.\n", GetLastError()));
} else if (dwResult == WAIT_TIMEOUT) {
SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: timeout waiting for agentCommThread to terminate.\n"));
// continue, and try to terminate comm thread anyway
} else {
SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: agentCommThread terminated.\n"));
}
// shutdown
WSACleanup();
// initialize critical used with comm thread
DeleteCriticalSection(&g_commThreadCritSec);
return TRUE;
} // end agentConfigInit()
VOID agentCommThread(VOID *threadParam)
{
INT i;
SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: agentCommThread entered.\n"));
// register window class
RegisterAgentWndClass();
// create window
CreateAgentWnd();
// associate each socket with window
for (i = 0; i < fdarrayLen; i++) {
// associate event with comm thread socket
if (WSAAsyncSelect(fdarray[i],g_hwndAgent,SNMP_AGENT_WND_MESSAGE,FD_READ) == SOCKET_ERROR) {
SNMPDBG((SNMP_LOG_ERROR, "SNMP: PDU: error %d associating window with socket.\n",WSAGetLastError()));
SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, WSAGetLastError());
SetEvent(g_hTerminationEvent);
goto cleanup;
}
}
while(1) {
int nResult;
DWORD dwResult;
#define COMM_EVENT_TERMINATE 0
#define COMM_EVENT_GET_MESSAGE 1
// wait for termination or event
dwResult = MsgWaitForMultipleObjects(
1,
&g_hTerminationEvent,
FALSE, // bWaitAll
INFINITE, // dwMilliseconds
QS_ALLINPUT
);
// see if socket ready for reading
if (dwResult == COMM_EVENT_GET_MESSAGE) {
MSG msg;
// retrieve next item in thread message queue
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
// translate message
TranslateMessage(&msg);
// dispatch message
DispatchMessage(&msg);
}
} else if (dwResult == COMM_EVENT_TERMINATE) {
SNMPDBG((SNMP_LOG_ERROR, "SNMP: PDU: agentCommThread exiting.\n"));
break;
} else if (dwResult == WAIT_FAILED){
SNMPDBG((SNMP_LOG_ERROR, "SNMP: PDU: error %d waiting for socket.\n",dwResult));
SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, dwResult);
SetEvent(g_hTerminationEvent);
break;
}
}
cleanup:
// destroy window
DestroyAgentWnd();
// register window class
UnregisterAgentWndClass();
} // end agentCommThread()
//-------------------------------- END --------------------------------------