|
|
//***************************************************************************
//
// 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; }
|