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