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.
271 lines
7.8 KiB
271 lines
7.8 KiB
//***************************************************************************
|
|
|
|
//
|
|
|
|
// File:
|
|
|
|
//
|
|
|
|
// Module: MS SNMP Provider
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
/*---------------------------------------------------------
|
|
Filename: flow.cpp
|
|
Written By: B.Rajeev
|
|
----------------------------------------------------------*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "sync.h"
|
|
#include "flow.h"
|
|
#include "frame.h"
|
|
#include "message.h"
|
|
#include "vblist.h"
|
|
#include "sec.h"
|
|
#include "pdu.h"
|
|
|
|
#include "dummy.h"
|
|
#include "ssent.h"
|
|
#include "idmap.h"
|
|
#include "opreg.h"
|
|
|
|
#include "session.h"
|
|
|
|
// Add to the end of the queue.
|
|
void MessageStore::Enqueue( Message &new_message )
|
|
{
|
|
AddTail(&new_message);
|
|
}
|
|
|
|
|
|
// Remove and return the first element in the Store
|
|
Message* MessageStore::Dequeue(void)
|
|
{
|
|
if ( !IsEmpty() )
|
|
return RemoveHead();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// remove and return the message with the session_frame_id
|
|
// throws a GeneralException(Snmp_Error, Snmp_Local_Error) if not found
|
|
Message *MessageStore::DeleteMessage(SessionFrameId session_frame_id)
|
|
{
|
|
POSITION current = GetHeadPosition();
|
|
|
|
while ( current != NULL )
|
|
{
|
|
POSITION prev_current = current;
|
|
Message *message = GetNext(current);
|
|
|
|
// if a match is found
|
|
if ( message->GetSessionFrameId() == session_frame_id )
|
|
{
|
|
RemoveAt(prev_current);
|
|
return message;
|
|
}
|
|
}
|
|
|
|
// if not found, throw an exception
|
|
throw GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__);
|
|
|
|
// should never reach here;
|
|
return NULL;
|
|
}
|
|
|
|
// goes through the store and deletes all stored message ptrs
|
|
MessageStore::~MessageStore(void)
|
|
{
|
|
POSITION current = GetHeadPosition();
|
|
|
|
while ( current != NULL )
|
|
{
|
|
POSITION prev_current = current;
|
|
Message *message = GetNext(current);
|
|
|
|
delete message;
|
|
}
|
|
|
|
RemoveAll();
|
|
}
|
|
|
|
// obtains the session CriticalSection lock before calling TransmitMessage
|
|
void FlowControlMechanism::TransmitMessageUnderProtection(Message *message)
|
|
{
|
|
CriticalSectionLock access_lock(session->session_CriticalSection);
|
|
|
|
if ( !access_lock.GetLock(INFINITE) )
|
|
throw GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__);
|
|
|
|
TransmitMessage(message);
|
|
|
|
// access_lock.UnLock(); The lock may be released at this point
|
|
}
|
|
|
|
// create a waiting message
|
|
// register with the frame_registry and let it Transmit
|
|
void FlowControlMechanism::TransmitMessage(Message *message)
|
|
{
|
|
// create a waiting message
|
|
WaitingMessage *waiting_message =
|
|
new WaitingMessage(*session, *message);
|
|
|
|
// register with the frame registry
|
|
session->frame_registry.RegisterFrame(message->GetSessionFrameId(),
|
|
*waiting_message);
|
|
|
|
// increment the number of outstanding messages before transmission
|
|
// to avoid problems in case of callback due to a message receipt
|
|
outstanding_messages++;
|
|
|
|
// let the message transmit
|
|
waiting_message->Transmit();
|
|
|
|
// if the window closes give a FlowControlOn callback
|
|
// if an exception is raised in Transmit, this is never
|
|
// called
|
|
if ( outstanding_messages == window_size )
|
|
session->SessionFlowControlOn();
|
|
}
|
|
|
|
|
|
// transmits a message(if present) for each empty slot in the
|
|
// window.
|
|
void FlowControlMechanism::ClearMessageStore(void)
|
|
{
|
|
while (outstanding_messages < window_size)
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L" checking message store\n"
|
|
) ;
|
|
)
|
|
// if any message is waiting in the queue, deque it
|
|
Message *message = message_store.Dequeue();
|
|
|
|
// if there is a message, create waiting message, register it and xmit
|
|
// (since we are already within the system, no need to call
|
|
// TransmitMessageUnderProtection)
|
|
if ( message != NULL )
|
|
{
|
|
// all the exception handling has already been
|
|
// performed - nothing needs to be done here
|
|
try
|
|
{
|
|
TransmitMessage(message);
|
|
}
|
|
catch ( Heap_Exception e_He ) {}
|
|
catch(GeneralException exception) {}
|
|
}
|
|
else // no messages in queue
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// initializes the private variables
|
|
FlowControlMechanism::FlowControlMechanism(SnmpImpSession &session,
|
|
UINT window_size)
|
|
{
|
|
FlowControlMechanism::session = &session;
|
|
FlowControlMechanism::window_size = window_size;
|
|
outstanding_messages = 0;
|
|
}
|
|
|
|
|
|
// sends message if within the flow control window
|
|
// else queues it up
|
|
void FlowControlMechanism::SendMessage(Message &message)
|
|
{
|
|
// check to see if it may be transmitted immediately,
|
|
// create a waiting message
|
|
// register with the frame_registry and let it Transmit
|
|
if ( outstanding_messages < window_size )
|
|
TransmitMessageUnderProtection(&message);
|
|
else // else Enqueue onto the message store
|
|
message_store.Enqueue(message);
|
|
}
|
|
|
|
|
|
// It removes the frame from its message store and deletes it
|
|
void FlowControlMechanism::DeleteMessage(SessionFrameId session_frame_id)
|
|
{
|
|
Message *message = message_store.DeleteMessage(session_frame_id);
|
|
|
|
delete message;
|
|
}
|
|
|
|
|
|
// this is called by a waiting_message indicating arrival or
|
|
// a lack of it
|
|
void FlowControlMechanism::NotifyReceipt(WaitingMessage &waiting_message,
|
|
IN const SnmpPdu *snmp_pdu,
|
|
SnmpErrorReport &error_report)
|
|
{
|
|
smiOCTETS msg_buffer = {0,NULL};
|
|
|
|
// if this opens up the window, signal FlowControlOff
|
|
outstanding_messages--;
|
|
if ( (outstanding_messages+1) == window_size )
|
|
session->SessionFlowControlOff();
|
|
|
|
SessionFrameId session_frame_id = waiting_message.GetMessage()->GetSessionFrameId();
|
|
|
|
// in case of an error
|
|
// Note: NotifyOperation either posts a SENT_FRAME event to be processed
|
|
// later or sets the variables needed to inform the operation of the
|
|
// reply when the control returns to the session
|
|
if ( error_report.GetError() != Snmp_Success )
|
|
session->NotifyOperation(session_frame_id, SnmpPdu(), error_report);
|
|
else // if a reply is succesfully received
|
|
{
|
|
// pass the message to session->NotifyOperation
|
|
session->NotifyOperation(session_frame_id, *snmp_pdu, error_report);
|
|
}
|
|
|
|
// deregister the frame from the message registry
|
|
session->frame_registry.DeregisterFrame(session_frame_id);
|
|
|
|
// destroy waiting message
|
|
delete &waiting_message;
|
|
|
|
// transmits messages in message store as long as the
|
|
// flow control window is open
|
|
ClearMessageStore();
|
|
}
|
|
|
|
|
|
// this is called when, although the session does
|
|
// not need to be informed, the flow control window
|
|
// must advance (such as frame cancellation)
|
|
// also destroys the waiting_message
|
|
void FlowControlMechanism::AdvanceWindow(WaitingMessage &waiting_message)
|
|
{
|
|
// remove the session_frame_id from the frame_registry
|
|
session->frame_registry.DeregisterFrame(
|
|
waiting_message.GetMessage()->GetSessionFrameId());
|
|
|
|
// if the flow control window opens up, signal FlowControlOff
|
|
outstanding_messages--;
|
|
if ( (outstanding_messages+1) == window_size )
|
|
session->SessionFlowControlOff();
|
|
|
|
// transmits messages in message store as long as the
|
|
// flow control window is open
|
|
ClearMessageStore();
|
|
|
|
// delete the waiting message
|
|
delete &waiting_message;
|
|
}
|