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.
606 lines
16 KiB
606 lines
16 KiB
//***************************************************************************
|
|
|
|
//
|
|
|
|
// File:
|
|
|
|
//
|
|
|
|
// Module: MS SNMP Provider
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
/*---------------------------------------------------------
|
|
Filename: session.cpp
|
|
Written By: B.Rajeev
|
|
----------------------------------------------------------*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "sync.h"
|
|
#include "dummy.h"
|
|
#include "flow.h"
|
|
#include "reg.h"
|
|
#include "frame.h"
|
|
#include "timer.h"
|
|
#include "message.h"
|
|
#include "tsent.h"
|
|
|
|
#include "transp.h"
|
|
#include "vblist.h"
|
|
#include "sec.h"
|
|
#include "pdu.h"
|
|
#include "ssent.h"
|
|
#include "idmap.h"
|
|
#include "opreg.h"
|
|
|
|
#include "session.h"
|
|
#include "pseudo.h"
|
|
#include "fs_reg.h"
|
|
#include "ophelp.h"
|
|
#include "op.h"
|
|
#include <winsock.h>
|
|
#include "trap.h"
|
|
|
|
SnmpSession::SnmpSession (
|
|
IN SnmpTransport &transportProtocol,
|
|
IN SnmpSecurity &security,
|
|
IN SnmpEncodeDecode &a_SnmpEncodeDecode ,
|
|
IN const ULONG retryCount,
|
|
IN const ULONG retryTimeout,
|
|
IN const ULONG varbindsPerPdu,
|
|
IN const ULONG flowControlWindow
|
|
)
|
|
{
|
|
retry_count = retryCount;
|
|
retry_timeout = retryTimeout;
|
|
varbinds_per_pdu = varbindsPerPdu;
|
|
flow_control_window = flowControlWindow;
|
|
}
|
|
|
|
#pragma warning (disable:4355)
|
|
|
|
SnmpImpSession::SnmpImpSession (
|
|
IN SnmpTransport &transportProtocol,
|
|
IN SnmpSecurity &security,
|
|
IN SnmpEncodeDecode &a_SnmpEncodeDecode ,
|
|
IN const ULONG retryCount,
|
|
IN const ULONG retryTimeout,
|
|
IN const ULONG varbindsPerPdu,
|
|
IN const ULONG flowControlWindow)
|
|
: SnmpSession(transportProtocol, security, a_SnmpEncodeDecode,
|
|
RetryCount(retryCount),
|
|
RetryTimeout(retryTimeout),
|
|
VarbindsPerPdu(varbindsPerPdu),
|
|
WindowSize(flowControlWindow)),
|
|
m_SessionWindow(*this),
|
|
transport(transportProtocol),
|
|
security(security),
|
|
m_EncodeDecode(a_SnmpEncodeDecode) ,
|
|
flow_control(*this, SnmpImpSession :: WindowSize ( GetFlowControlWindow() ) ),
|
|
message_registry(*this),
|
|
frame_registry(*this),
|
|
timer(*this)
|
|
{
|
|
is_valid = FALSE;
|
|
|
|
if ( !transport() || !security() || !m_SessionWindow() )
|
|
return;
|
|
|
|
received_session_frame_id = ILLEGAL_SESSION_FRAME_ID;
|
|
destroy_self = FALSE;
|
|
|
|
strobe_count = 1 ;
|
|
|
|
// generate timer_event_id and register with the timer
|
|
timer_event_id = timer.SetTimerEvent(MIN(100,retry_timeout/10));
|
|
|
|
is_valid = TRUE;
|
|
}
|
|
|
|
#pragma warning (default:4355)
|
|
|
|
ULONG SnmpImpSession::RetryCount(IN const ULONG retry_count)
|
|
{
|
|
return retry_count ;
|
|
}
|
|
|
|
|
|
ULONG SnmpImpSession::RetryTimeout(IN const ULONG retry_timeout)
|
|
{
|
|
return ( (retry_timeout==0)?
|
|
DEF_RETRY_TIMEOUT: retry_timeout);
|
|
}
|
|
|
|
|
|
ULONG SnmpImpSession::VarbindsPerPdu(IN const ULONG varbinds_per_pdu)
|
|
{
|
|
return ( (varbinds_per_pdu==0)?
|
|
DEF_VARBINDS_PER_PDU: varbinds_per_pdu);
|
|
}
|
|
|
|
|
|
ULONG SnmpImpSession::WindowSize(IN const ULONG window_size)
|
|
{
|
|
return ( (window_size==0)? DEF_WINDOW_SIZE: window_size);
|
|
}
|
|
|
|
|
|
void SnmpImpSession::RegisterOperation(IN SnmpOperation &operation)
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return;
|
|
|
|
operation_registry.Register(operation);
|
|
|
|
// access_lock.UnLock(); The lock may be released at this point
|
|
}
|
|
|
|
// updates the number of operations currently registered
|
|
// when the count goes to 0 and the destroy_self flag is set,
|
|
// it posts the WinSnmpSession :: g_DeleteSessionEvent message.
|
|
void SnmpImpSession::DeregisterOperation(IN SnmpOperation &operation)
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return;
|
|
|
|
operation_registry.Deregister(operation);
|
|
|
|
if ( (destroy_self == TRUE) &&
|
|
(operation_registry.GetNumRegistered() == 0) )
|
|
m_SessionWindow.PostMessage(Window :: g_DeleteSessionEvent, 0, 0);
|
|
|
|
// access_lock.UnLock(); The lock may be released at this point
|
|
}
|
|
|
|
|
|
// when the WinSnmpSession :: g_DeleteSessionEvent is received, the session deletes itself
|
|
// no locks are obtained since our assumption is that no other objects would be
|
|
// accessing the session at this time
|
|
void SnmpImpSession::HandleDeletionEvent()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
// the session posts a message to destroy self if the number of registered
|
|
// sessions is 0. otherwise the session is flagged for the same action when
|
|
// the number of registered operations drops to 0.
|
|
BOOL SnmpImpSession::DestroySession()
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return FALSE;
|
|
|
|
if ( operation_registry.GetNumRegistered() == 0 )
|
|
{
|
|
m_SessionWindow.PostMessage(Window :: g_DeleteSessionEvent, 0, 0);
|
|
return TRUE;
|
|
}
|
|
else
|
|
destroy_self = TRUE; // flag self for destruction
|
|
|
|
access_lock.UnLock();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void SnmpImpSession::SessionSendFrame
|
|
(
|
|
IN SnmpOperation &operation,
|
|
OUT SessionFrameId &session_frame_id,
|
|
IN SnmpPdu &snmpPdu
|
|
)
|
|
{
|
|
SessionSendFrame(operation, session_frame_id, snmpPdu, security);
|
|
}
|
|
|
|
|
|
void SnmpImpSession::SessionSendFrame
|
|
(
|
|
IN SnmpOperation &operation,
|
|
OUT SessionFrameId &session_frame_id,
|
|
IN SnmpPdu &snmpPdu,
|
|
IN SnmpSecurity &snmp_security
|
|
)
|
|
{
|
|
try
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return;
|
|
|
|
if ( !is_valid )
|
|
return;
|
|
|
|
session_frame_id = frame_registry.GenerateSessionFrameId();
|
|
|
|
SnmpErrorReport error_report = snmp_security.Secure (
|
|
|
|
m_EncodeDecode,
|
|
snmpPdu
|
|
);
|
|
|
|
// if already errored, register the error report in the sent state
|
|
if ( error_report.GetError() != Snmp_Success )
|
|
{
|
|
delete & snmpPdu;
|
|
|
|
PostSentFrameEvent(
|
|
|
|
session_frame_id,
|
|
operation,
|
|
SnmpErrorReport(Snmp_Error, Snmp_Local_Error)
|
|
) ;
|
|
|
|
return;
|
|
}
|
|
|
|
Message *message = new Message(session_frame_id, snmpPdu, operation);
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"new message(id%d,op%d)\n",session_frame_id, &(message->GetOperation())
|
|
) ;
|
|
)
|
|
flow_control.SendMessage(*message);
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
PostSentFrameEvent(
|
|
|
|
session_frame_id,
|
|
operation,
|
|
SnmpErrorReport(Snmp_Error, Snmp_Local_Error)
|
|
);
|
|
|
|
return;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
PostSentFrameEvent(
|
|
|
|
session_frame_id,
|
|
operation,
|
|
SnmpErrorReport(exception.GetError(), exception.GetStatus())
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
void SnmpImpSession::PostSentFrameEvent (
|
|
|
|
SessionFrameId session_frame_id ,
|
|
SnmpOperation &operation,
|
|
SnmpErrorReport errorReport
|
|
)
|
|
{
|
|
try
|
|
{
|
|
store.Register (
|
|
|
|
session_frame_id,
|
|
operation,
|
|
errorReport
|
|
) ;
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
}
|
|
catch ( GeneralException exception )
|
|
{
|
|
}
|
|
|
|
m_SessionWindow.PostMessage ( Window :: g_SentFrameEvent, session_frame_id, (LPARAM)&operation);
|
|
}
|
|
|
|
void SnmpImpSession::HandleSentFrame (
|
|
|
|
IN SessionFrameId session_frame_id ,
|
|
IN SnmpOperation *operation
|
|
)
|
|
{
|
|
SnmpOperation *tmp_operation;
|
|
SnmpErrorReport error_report = store.Remove(session_frame_id, tmp_operation);
|
|
|
|
if ( tmp_operation == NULL )
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"HandleSentFrame could not locate sent message error in store(id%d,op%lx)\n",session_frame_id, operation
|
|
) ;
|
|
)
|
|
}
|
|
|
|
// ignore it if no corresponding operation
|
|
if ( operation == NULL )
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"HandleSentFrame received null operation(id%d)\n",session_frame_id
|
|
) ;
|
|
)
|
|
return;
|
|
}
|
|
|
|
operation->SentFrame(session_frame_id, error_report);
|
|
}
|
|
|
|
SnmpOperation *SnmpImpSession::GetOperation(IN const SessionFrameId session_frame_id)
|
|
{
|
|
WaitingMessage *waiting_message = frame_registry.GetWaitingMessage(session_frame_id);
|
|
|
|
if (waiting_message == NULL)
|
|
return NULL;
|
|
|
|
return &(waiting_message->GetMessage()->GetOperation());
|
|
}
|
|
|
|
void SnmpImpSession::SessionSentFrame
|
|
(
|
|
IN TransportFrameId transport_frame_id,
|
|
IN SnmpErrorReport &errorReport
|
|
)
|
|
{
|
|
try
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return;
|
|
|
|
// obtain and remove the session frame id
|
|
// obtain corresponding operation and inform it
|
|
SessionFrameId session_frame_id = id_mapping.DisassociateTransportFrameId(transport_frame_id);
|
|
|
|
// determine corresponding waiting message
|
|
WaitingMessage *waiting_message = frame_registry.GetWaitingMessage(session_frame_id);
|
|
|
|
// ignore if no such waiting message
|
|
if (waiting_message == NULL)
|
|
return;
|
|
|
|
// if the error report shows an error during transport,
|
|
// wrap up the waiting message and return
|
|
if ( errorReport.GetError() != Snmp_Success )
|
|
{
|
|
waiting_message->WrapUp(SnmpErrorReport(errorReport));
|
|
return;
|
|
}
|
|
|
|
// inform the waiting message of the sent message processing event
|
|
waiting_message->SetSentMessageProcessed();
|
|
|
|
// determine the corresponding operation
|
|
SnmpOperation *operation = &(waiting_message->GetMessage()->GetOperation());
|
|
|
|
access_lock.UnLock();
|
|
|
|
// call to the operation is made outside the lock
|
|
operation->SentFrame(session_frame_id, errorReport);
|
|
|
|
// obtain the lock again to process the corresponding buffered
|
|
// waiting message, if any
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return;
|
|
|
|
// if no such buffered snmp pdu, return
|
|
if ( !waiting_message->ReplyBuffered() )
|
|
return;
|
|
|
|
SnmpPdu *snmp_pdu = waiting_message->GetBufferedReply();
|
|
|
|
// set the state information for processing the buffered message
|
|
received_session_frame_id = ILLEGAL_SESSION_FRAME_ID;
|
|
|
|
// proceed with processing the snmp_pdu
|
|
waiting_message->ReceiveReply(snmp_pdu);
|
|
|
|
// save the information needed to notify the targeted operation
|
|
// before releasing the lock
|
|
SessionFrameId target_session_frame_id = received_session_frame_id;
|
|
SnmpOperation *target_operation = operation_to_notify;
|
|
|
|
access_lock.UnLock();
|
|
|
|
// inform the target operation of the frame receipt
|
|
if ( target_session_frame_id != ILLEGAL_SESSION_FRAME_ID )
|
|
{
|
|
target_operation->ReceiveFrame(target_session_frame_id, *snmp_pdu,
|
|
SnmpErrorReport(Snmp_Success, Snmp_No_Error));
|
|
}
|
|
|
|
delete & snmp_pdu->GetVarbindList () ;
|
|
delete snmp_pdu;
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
return;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
void SnmpImpSession::SessionReceiveFrame (
|
|
|
|
IN SnmpPdu &snmpPdu,
|
|
IN SnmpErrorReport &errorReport
|
|
)
|
|
{
|
|
try
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return;
|
|
|
|
// set the state information for processing the buffered message
|
|
received_session_frame_id = ILLEGAL_SESSION_FRAME_ID;
|
|
|
|
// proceed with processing the snmp_pdu
|
|
message_registry.MessageArrivalNotification(snmpPdu);
|
|
|
|
// save the information needed to notify the targeted operation
|
|
// before releasing the lock
|
|
SessionFrameId target_session_frame_id = received_session_frame_id;
|
|
SnmpOperation *target_operation = operation_to_notify;
|
|
|
|
access_lock.UnLock();
|
|
|
|
// inform the target operation of the frame receipt
|
|
if ( target_session_frame_id != ILLEGAL_SESSION_FRAME_ID )
|
|
target_operation->ReceiveFrame(target_session_frame_id, snmpPdu,
|
|
errorReport);
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
return ;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
void SnmpImpSession::NotifyOperation (
|
|
|
|
IN const SessionFrameId session_frame_id,
|
|
IN const SnmpPdu &snmp_pdu,
|
|
IN const SnmpErrorReport &error_report
|
|
)
|
|
{
|
|
// determine the corresponding operation and
|
|
// call its SessionReceiveFrame
|
|
SnmpOperation *operation = GetOperation(session_frame_id);
|
|
|
|
if ( error_report.GetError() != Snmp_Success )
|
|
{
|
|
PostSentFrameEvent(
|
|
|
|
session_frame_id,
|
|
*operation,
|
|
error_report
|
|
) ;
|
|
}
|
|
else
|
|
{
|
|
received_session_frame_id = session_frame_id;
|
|
operation_to_notify = operation;
|
|
}
|
|
}
|
|
|
|
|
|
SnmpErrorReport SnmpImpSession::SessionCancelFrame (
|
|
|
|
IN const SessionFrameId session_frame_id
|
|
)
|
|
{
|
|
if ( !is_valid )
|
|
return SnmpErrorReport(Snmp_Error, Snmp_Local_Error);
|
|
|
|
try
|
|
{
|
|
CriticalSectionLock access_lock(session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
return SnmpErrorReport(Snmp_Error, Snmp_Local_Error);
|
|
|
|
frame_registry.CancelFrameNotification(session_frame_id);
|
|
|
|
access_lock.UnLock();
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
return SnmpErrorReport(Snmp_Error, Snmp_Local_Error);
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
return exception;
|
|
}
|
|
|
|
// if we have reached this place, we must have succeeded
|
|
return SnmpErrorReport(Snmp_Success, Snmp_No_Error);
|
|
}
|
|
|
|
|
|
SnmpImpSession::~SnmpImpSession(void)
|
|
{
|
|
// if required, cancels timer event
|
|
if ( timer_event_id != ILLEGAL_TIMER_EVENT_ID )
|
|
{
|
|
timer.CancelTimer(timer_event_id);
|
|
timer_event_id = ILLEGAL_TIMER_EVENT_ID;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void * SnmpV1OverIp::operator()(void) const
|
|
{
|
|
if ( (SnmpUdpIpImp::operator()() == NULL) ||
|
|
(SnmpV1EncodeDecode::operator()() == NULL) ||
|
|
(SnmpCommunityBasedSecurity::operator()() == NULL) ||
|
|
(SnmpImpSession::operator()() == NULL) )
|
|
return NULL;
|
|
else
|
|
return (void *)this;
|
|
}
|
|
|
|
void * SnmpV1OverIpx::operator()(void) const
|
|
{
|
|
if ( (SnmpIpxImp::operator()() == NULL) ||
|
|
(SnmpV1EncodeDecode::operator()() == NULL) ||
|
|
(SnmpCommunityBasedSecurity::operator()() == NULL) ||
|
|
(SnmpImpSession::operator()() == NULL) )
|
|
return NULL;
|
|
else
|
|
return (void *)this;
|
|
}
|
|
|
|
void * SnmpV2COverIp::operator()(void) const
|
|
{
|
|
if ( (SnmpUdpIpImp::operator()() == NULL) ||
|
|
(SnmpV2CEncodeDecode::operator()() == NULL) ||
|
|
(SnmpCommunityBasedSecurity::operator()() == NULL) ||
|
|
(SnmpImpSession::operator()() == NULL) )
|
|
return NULL;
|
|
else
|
|
return (void *)this;
|
|
}
|
|
|
|
void * SnmpV2COverIpx::operator()(void) const
|
|
{
|
|
if ( (SnmpIpxImp::operator()() == NULL) ||
|
|
(SnmpV2CEncodeDecode::operator()() == NULL) ||
|
|
(SnmpCommunityBasedSecurity::operator()() == NULL) ||
|
|
(SnmpImpSession::operator()() == NULL) )
|
|
return NULL;
|
|
else
|
|
return (void *)this;
|
|
}
|