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.
 
 
 
 
 
 

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