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.
 
 
 
 
 
 

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