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.
482 lines
14 KiB
482 lines
14 KiB
//***************************************************************************
|
|
|
|
//
|
|
|
|
// File:
|
|
|
|
//
|
|
|
|
// Module: MS SNMP Provider
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
/*---------------------------------------------------------
|
|
Filename: message.cpp
|
|
Written By: B.Rajeev
|
|
----------------------------------------------------------*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "sync.h"
|
|
#include "message.h"
|
|
#include "idmap.h"
|
|
#include "dummy.h"
|
|
#include "flow.h"
|
|
#include "vblist.h"
|
|
#include "sec.h"
|
|
#include "pdu.h"
|
|
|
|
#include "frame.h"
|
|
#include "opreg.h"
|
|
#include "ssent.h"
|
|
|
|
#include "session.h"
|
|
|
|
#define ILLEGAL_PDU_HANDLE 100000
|
|
#define ILLEGAL_VBL_HANDLE 100000
|
|
|
|
Message::Message(IN const SessionFrameId session_frame_id, IN SnmpPdu &snmp_pdu,
|
|
SnmpOperation &snmp_operation
|
|
) : snmp_pdu(&snmp_pdu), operation(snmp_operation)
|
|
{
|
|
Message::session_frame_id = session_frame_id;
|
|
}
|
|
|
|
SessionFrameId Message::GetSessionFrameId(void) const
|
|
{
|
|
return session_frame_id;
|
|
}
|
|
|
|
SnmpOperation &Message::GetOperation(void) const
|
|
{
|
|
return operation;
|
|
}
|
|
|
|
SnmpPdu &Message::GetSnmpPdu(void) const
|
|
{
|
|
return *snmp_pdu;
|
|
}
|
|
|
|
void Message::SetSnmpPdu(IN SnmpPdu &new_snmp_pdu)
|
|
{
|
|
delete snmp_pdu;
|
|
snmp_pdu = &new_snmp_pdu;
|
|
}
|
|
|
|
Message::~Message(void)
|
|
{
|
|
delete snmp_pdu;
|
|
}
|
|
|
|
|
|
// deregisters the waiting message from the message registry
|
|
// for each request id stored in the RequestIdList
|
|
void WaitingMessage::DeregisterRequestIds()
|
|
{
|
|
for( UINT request_ids_left = request_id_list.GetCount();
|
|
request_ids_left > 0;
|
|
request_id_list.RemoveHead(), request_ids_left--)
|
|
{
|
|
RequestId request_id = request_id_list.GetHead();
|
|
session->message_registry.RemoveMessage(request_id);
|
|
}
|
|
}
|
|
|
|
// an exit fn - prepares an error report and calls
|
|
// ReceiveReply to signal a non-receipt
|
|
void WaitingMessage::WrapUp(IN SnmpErrorReport &error_report)
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: WrapUp () session_id(%d), frame_id(%d)\n" ,message->GetSessionFrameId(), last_transport_frame_id
|
|
) ;
|
|
)
|
|
|
|
try // ignore any exceptions arising during the ReceiveReply
|
|
{
|
|
// no reply to receive
|
|
ReceiveReply(NULL, error_report);
|
|
}
|
|
catch ( Heap_Exception e_He ) {}
|
|
catch(GeneralException exception) {}
|
|
}
|
|
|
|
|
|
// initializes the private variables
|
|
WaitingMessage::WaitingMessage(IN SnmpImpSession &session,
|
|
IN Message &message) : session ( NULL ) , message ( NULL ), reply_snmp_pdu ( NULL )
|
|
{
|
|
WaitingMessage::session = &session;
|
|
|
|
// the message ptr must be deleted by the waiting message
|
|
WaitingMessage::message = &message;
|
|
|
|
// sent message has not been processed yet
|
|
sent_message_processed = FALSE;
|
|
|
|
// set illegal values for last_transport_frame_id
|
|
last_transport_frame_id = ILLEGAL_TRANSPORT_FRAME_ID;
|
|
|
|
// these values are currently obtained from the
|
|
// session, but may be specified per message later
|
|
max_rexns = SnmpImpSession :: RetryCount ( session.GetRetryCount() ) ;
|
|
rexns_left = max_rexns;
|
|
strobes = 0 ;
|
|
|
|
active = FALSE;
|
|
}
|
|
|
|
|
|
// sends the message. involves request_id generation,
|
|
// registering with the message_registry, decoding the
|
|
// message and updating the pdu and registering a timer
|
|
// event
|
|
void WaitingMessage::Transmit()
|
|
{
|
|
try
|
|
{
|
|
// generate request_id and register with the registry
|
|
RequestId request_id =
|
|
session->message_registry.GenerateRequestId(*this);
|
|
|
|
// insert the request id into the message
|
|
// if unsuccessful, the exception handler gets called
|
|
session->m_EncodeDecode.SetRequestId(
|
|
|
|
message->GetSnmpPdu(),
|
|
request_id
|
|
|
|
);
|
|
|
|
last_transport_frame_id = request_id ;
|
|
|
|
// append the request id to the request id list
|
|
request_id_list.AddTail(request_id);
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: Transmit - About to transmit (session (%d), frame_id(%d))\n", message->GetSessionFrameId(), request_id
|
|
) ;
|
|
)
|
|
|
|
// save the previous value of active and set the active
|
|
// flag. This is needed to check on returning whether the
|
|
// waiting message needs to be destroyed
|
|
BOOL prev_active_state = active;
|
|
active = TRUE;
|
|
strobes = GetTickCount () ;
|
|
|
|
// send message
|
|
|
|
session->transport.TransportSendFrame(last_transport_frame_id, message->GetSnmpPdu());
|
|
|
|
session->id_mapping.Associate(last_transport_frame_id, message->GetSessionFrameId());
|
|
|
|
// if asked to destroy self, well, do it (and return)
|
|
if ( !active )
|
|
{
|
|
delete this;
|
|
return;
|
|
}
|
|
|
|
// restore the previous value of "active"
|
|
active = prev_active_state;
|
|
|
|
// generate timer_event_id and register with the timer
|
|
session->timer.SetMessageTimerEvent(*this);
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: Transmit - Transmitted session_id(%d),frame_id(%d))\n",message->GetSessionFrameId(), request_id
|
|
) ;
|
|
)
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
WrapUp(GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__));
|
|
|
|
throw;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
WrapUp(exception);
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// used by the timer to notify the waiting message of
|
|
// a timer event. if need, the message is retransmitted.
|
|
// when all rexns are exhausted, ReceiveReply is called
|
|
void WaitingMessage::TimerNotification()
|
|
{
|
|
DWORD t_Ticks = GetTickCount () ;
|
|
if ( strobes > t_Ticks )
|
|
{
|
|
strobes = t_Ticks ; // Take hit on clock overflow
|
|
return ;
|
|
}
|
|
|
|
if ( ( t_Ticks - strobes ) >= SnmpImpSession :: RetryTimeout ( session->GetRetryTimeout () ) )
|
|
{
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: TimerNotification - timed out after (%ld)" , ( t_Ticks - strobes )
|
|
) ;
|
|
)
|
|
|
|
// if any rexns left, update rexns_left, send message
|
|
if ( rexns_left > 0 )
|
|
{
|
|
// generate request_id and register with the registry
|
|
RequestId request_id = session->message_registry.GenerateRequestId(*this);
|
|
|
|
// insert the request id into the message
|
|
// if unsuccessful, the exception handler gets called
|
|
try
|
|
{
|
|
session->m_EncodeDecode.SetRequestId(
|
|
|
|
message->GetSnmpPdu() ,
|
|
request_id
|
|
);
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
WrapUp(GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__));
|
|
|
|
return ;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
WrapUp(exception);
|
|
return;
|
|
}
|
|
|
|
last_transport_frame_id = request_id ;
|
|
|
|
// append the request id to the request id list
|
|
request_id_list.AddTail(request_id);
|
|
|
|
BOOL prev_active_state = active;
|
|
active = TRUE;
|
|
|
|
strobes = GetTickCount () ;
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: TimerNotification - Resend %d.%d, req_id(%d), this(%d) at time (%d)\n",message->GetSessionFrameId(), rexns_left, request_id, this, strobes
|
|
) ;
|
|
)
|
|
|
|
session->id_mapping.DisassociateTransportFrameId(last_transport_frame_id);
|
|
|
|
// send message
|
|
session->transport.TransportSendFrame(last_transport_frame_id, message->GetSnmpPdu());
|
|
|
|
// associate the last transport frame id with the session frame id
|
|
session->id_mapping.Associate(last_transport_frame_id, message->GetSessionFrameId());
|
|
|
|
// if asked to destroy self, well, do it (and return)
|
|
if ( !active )
|
|
{
|
|
delete this;
|
|
return;
|
|
}
|
|
|
|
// restore the previous value of "active"
|
|
active = prev_active_state;
|
|
|
|
rexns_left--;
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: TimerNotification - Retransmitted session_id(%d),frame_id(%d))\n",message->GetSessionFrameId(), last_transport_frame_id
|
|
) ;
|
|
)
|
|
|
|
}
|
|
else
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: TimerNotification - No response session_id(%d),frame_id(%d))\n",message->GetSessionFrameId(), last_transport_frame_id
|
|
) ;
|
|
)
|
|
|
|
// else wrap up as no response has been received
|
|
WrapUp(SnmpErrorReport(Snmp_Error, Snmp_No_Response));
|
|
|
|
return; // since the waiting_message would have been destroyed
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
// A call to this function signifies that state corresponding to the
|
|
// waiting_message need not be kept any further
|
|
// if required, it cancels the timer event and
|
|
// deregisters with the message registry
|
|
// it notifies the flow control mechanism of the termination
|
|
// which destroys the waiting_message
|
|
void WaitingMessage::ReceiveReply(IN const SnmpPdu *snmp_pdu, IN SnmpErrorReport &error_report)
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: ReceiveReply (this(%d), session_id(%d),frame_id(%d),error(%d), status(%d))\n",this, message->GetSessionFrameId(), last_transport_frame_id,error_report.GetError(), error_report.GetStatus()
|
|
) ;
|
|
)
|
|
|
|
// cancels registrations with message registry
|
|
DeregisterRequestIds();
|
|
|
|
// cancels timer event
|
|
session->timer.CancelMessageTimer(*this,session->timer_event_id);
|
|
|
|
|
|
// if required (the corresponding SENT event has not been signaled
|
|
// yet), cancel the association with the last transport frame id
|
|
if ( last_transport_frame_id != ILLEGAL_TRANSPORT_FRAME_ID )
|
|
{
|
|
session->id_mapping.DisassociateTransportFrameId(last_transport_frame_id);
|
|
last_transport_frame_id = ILLEGAL_TRANSPORT_FRAME_ID;
|
|
}
|
|
|
|
// call fc_mech.NotifyReceipt(this,pdu,error_report)
|
|
// which should destroy the waiting message
|
|
session->flow_control.NotifyReceipt(*this, snmp_pdu, error_report);
|
|
}
|
|
|
|
|
|
// buffers the snmp pdu received as a reply
|
|
void WaitingMessage::BufferReply(IN const SnmpPdu &reply_snmp_pdu)
|
|
{
|
|
if ( WaitingMessage::reply_snmp_pdu == NULL )
|
|
{
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"WaitingMessage :: Buffering reply %d, %d, this(%d)\n",message->GetSessionFrameId(), rexns_left, this
|
|
) ;
|
|
)
|
|
WaitingMessage::reply_snmp_pdu = new SnmpPdu((SnmpPdu&)reply_snmp_pdu);
|
|
}
|
|
}
|
|
|
|
// returns TRUE if a reply has been buffered
|
|
BOOL WaitingMessage::ReplyBuffered()
|
|
{
|
|
return (reply_snmp_pdu != NULL);
|
|
}
|
|
|
|
// returns a ptr to the buffered reply pdu, if buffered
|
|
// otherwise a null ptr is returned
|
|
// IMPORTANT: it sets the reply_snmp_pdu to NULL, so that it may not
|
|
// be deleted when the waiting message is destroyed
|
|
SnmpPdu *WaitingMessage::GetBufferedReply()
|
|
{
|
|
SnmpPdu *to_return = reply_snmp_pdu;
|
|
reply_snmp_pdu = NULL;
|
|
|
|
return to_return;
|
|
}
|
|
|
|
// informs the waiting message that a sent message has been
|
|
// processed
|
|
void WaitingMessage::SetSentMessageProcessed()
|
|
{
|
|
sent_message_processed = TRUE;
|
|
}
|
|
|
|
// if a sent message has been processed, it returns TRUE, else FALSE
|
|
BOOL WaitingMessage::GetSentMessageProcessed()
|
|
{
|
|
return sent_message_processed;
|
|
}
|
|
|
|
void WaitingMessage::SelfDestruct(void)
|
|
{
|
|
if ( !active )
|
|
{
|
|
delete this;
|
|
return;
|
|
}
|
|
else // else, set the active flag to FALSE
|
|
// when this is detected, it'll self destruct
|
|
active = FALSE;
|
|
}
|
|
|
|
TimerEventId WaitingMessage::GetTimerEventId ()
|
|
{
|
|
return m_TimerEventId ;
|
|
}
|
|
|
|
void WaitingMessage::SetTimerEventId ( TimerEventId a_TimerEventId )
|
|
{
|
|
m_TimerEventId = a_TimerEventId ;
|
|
}
|
|
|
|
// if required, it cancels registration with the message_registry and
|
|
// the timer event with the timer.
|
|
WaitingMessage::~WaitingMessage(void)
|
|
{
|
|
// if required, cancel registrations with message registry
|
|
if ( !request_id_list.IsEmpty() )
|
|
DeregisterRequestIds();
|
|
|
|
session->timer.CancelMessageTimer(*this,session->timer_event_id);
|
|
|
|
// if required (the corresponding SENT event has not been signaled
|
|
// yet), cancel the association with the last transport frame id
|
|
if ( last_transport_frame_id != ILLEGAL_TRANSPORT_FRAME_ID )
|
|
session->id_mapping.DisassociateTransportFrameId(last_transport_frame_id);
|
|
|
|
// if a reply pdu has been buffered, destroy it
|
|
if ( reply_snmp_pdu != NULL )
|
|
{
|
|
delete &reply_snmp_pdu->GetVarbindList () ;
|
|
delete reply_snmp_pdu;
|
|
}
|
|
|
|
// deletes the message ptr
|
|
delete message;
|
|
}
|