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

  1. //***************************************************************************
  2. //
  3. // File:
  4. //
  5. // Module: MS SNMP Provider
  6. //
  7. // Purpose:
  8. //
  9. // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
  10. //
  11. //***************************************************************************
  12. /*---------------------------------------------------------
  13. Filename: flow.cpp
  14. Written By: B.Rajeev
  15. ----------------------------------------------------------*/
  16. #include "precomp.h"
  17. #include "common.h"
  18. #include "sync.h"
  19. #include "flow.h"
  20. #include "frame.h"
  21. #include "message.h"
  22. #include "vblist.h"
  23. #include "sec.h"
  24. #include "pdu.h"
  25. #include "dummy.h"
  26. #include "ssent.h"
  27. #include "idmap.h"
  28. #include "opreg.h"
  29. #include "session.h"
  30. // Add to the end of the queue.
  31. void MessageStore::Enqueue( Message &new_message )
  32. {
  33. AddTail(&new_message);
  34. }
  35. // Remove and return the first element in the Store
  36. Message* MessageStore::Dequeue(void)
  37. {
  38. if ( !IsEmpty() )
  39. return RemoveHead();
  40. return NULL;
  41. }
  42. // remove and return the message with the session_frame_id
  43. // throws a GeneralException(Snmp_Error, Snmp_Local_Error) if not found
  44. Message *MessageStore::DeleteMessage(SessionFrameId session_frame_id)
  45. {
  46. POSITION current = GetHeadPosition();
  47. while ( current != NULL )
  48. {
  49. POSITION prev_current = current;
  50. Message *message = GetNext(current);
  51. // if a match is found
  52. if ( message->GetSessionFrameId() == session_frame_id )
  53. {
  54. RemoveAt(prev_current);
  55. return message;
  56. }
  57. }
  58. // if not found, throw an exception
  59. throw GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__);
  60. // should never reach here;
  61. return NULL;
  62. }
  63. // goes through the store and deletes all stored message ptrs
  64. MessageStore::~MessageStore(void)
  65. {
  66. POSITION current = GetHeadPosition();
  67. while ( current != NULL )
  68. {
  69. POSITION prev_current = current;
  70. Message *message = GetNext(current);
  71. delete message;
  72. }
  73. RemoveAll();
  74. }
  75. // obtains the session CriticalSection lock before calling TransmitMessage
  76. void FlowControlMechanism::TransmitMessageUnderProtection(Message *message)
  77. {
  78. CriticalSectionLock access_lock(session->session_CriticalSection);
  79. if ( !access_lock.GetLock(INFINITE) )
  80. throw GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__);
  81. TransmitMessage(message);
  82. // access_lock.UnLock(); The lock may be released at this point
  83. }
  84. // create a waiting message
  85. // register with the frame_registry and let it Transmit
  86. void FlowControlMechanism::TransmitMessage(Message *message)
  87. {
  88. // create a waiting message
  89. WaitingMessage *waiting_message =
  90. new WaitingMessage(*session, *message);
  91. // register with the frame registry
  92. session->frame_registry.RegisterFrame(message->GetSessionFrameId(),
  93. *waiting_message);
  94. // increment the number of outstanding messages before transmission
  95. // to avoid problems in case of callback due to a message receipt
  96. outstanding_messages++;
  97. // let the message transmit
  98. waiting_message->Transmit();
  99. // if the window closes give a FlowControlOn callback
  100. // if an exception is raised in Transmit, this is never
  101. // called
  102. if ( outstanding_messages == window_size )
  103. session->SessionFlowControlOn();
  104. }
  105. // transmits a message(if present) for each empty slot in the
  106. // window.
  107. void FlowControlMechanism::ClearMessageStore(void)
  108. {
  109. while (outstanding_messages < window_size)
  110. {
  111. DebugMacro4(
  112. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  113. __FILE__,__LINE__,
  114. L" checking message store\n"
  115. ) ;
  116. )
  117. // if any message is waiting in the queue, deque it
  118. Message *message = message_store.Dequeue();
  119. // if there is a message, create waiting message, register it and xmit
  120. // (since we are already within the system, no need to call
  121. // TransmitMessageUnderProtection)
  122. if ( message != NULL )
  123. {
  124. // all the exception handling has already been
  125. // performed - nothing needs to be done here
  126. try
  127. {
  128. TransmitMessage(message);
  129. }
  130. catch ( Heap_Exception e_He ) {}
  131. catch(GeneralException exception) {}
  132. }
  133. else // no messages in queue
  134. return;
  135. }
  136. }
  137. // initializes the private variables
  138. FlowControlMechanism::FlowControlMechanism(SnmpImpSession &session,
  139. UINT window_size)
  140. {
  141. FlowControlMechanism::session = &session;
  142. FlowControlMechanism::window_size = window_size;
  143. outstanding_messages = 0;
  144. }
  145. // sends message if within the flow control window
  146. // else queues it up
  147. void FlowControlMechanism::SendMessage(Message &message)
  148. {
  149. // check to see if it may be transmitted immediately,
  150. // create a waiting message
  151. // register with the frame_registry and let it Transmit
  152. if ( outstanding_messages < window_size )
  153. TransmitMessageUnderProtection(&message);
  154. else // else Enqueue onto the message store
  155. message_store.Enqueue(message);
  156. }
  157. // It removes the frame from its message store and deletes it
  158. void FlowControlMechanism::DeleteMessage(SessionFrameId session_frame_id)
  159. {
  160. Message *message = message_store.DeleteMessage(session_frame_id);
  161. delete message;
  162. }
  163. // this is called by a waiting_message indicating arrival or
  164. // a lack of it
  165. void FlowControlMechanism::NotifyReceipt(WaitingMessage &waiting_message,
  166. IN const SnmpPdu *snmp_pdu,
  167. SnmpErrorReport &error_report)
  168. {
  169. smiOCTETS msg_buffer = {0,NULL};
  170. // if this opens up the window, signal FlowControlOff
  171. outstanding_messages--;
  172. if ( (outstanding_messages+1) == window_size )
  173. session->SessionFlowControlOff();
  174. SessionFrameId session_frame_id = waiting_message.GetMessage()->GetSessionFrameId();
  175. // in case of an error
  176. // Note: NotifyOperation either posts a SENT_FRAME event to be processed
  177. // later or sets the variables needed to inform the operation of the
  178. // reply when the control returns to the session
  179. if ( error_report.GetError() != Snmp_Success )
  180. session->NotifyOperation(session_frame_id, SnmpPdu(), error_report);
  181. else // if a reply is succesfully received
  182. {
  183. // pass the message to session->NotifyOperation
  184. session->NotifyOperation(session_frame_id, *snmp_pdu, error_report);
  185. }
  186. // deregister the frame from the message registry
  187. session->frame_registry.DeregisterFrame(session_frame_id);
  188. // destroy waiting message
  189. delete &waiting_message;
  190. // transmits messages in message store as long as the
  191. // flow control window is open
  192. ClearMessageStore();
  193. }
  194. // this is called when, although the session does
  195. // not need to be informed, the flow control window
  196. // must advance (such as frame cancellation)
  197. // also destroys the waiting_message
  198. void FlowControlMechanism::AdvanceWindow(WaitingMessage &waiting_message)
  199. {
  200. // remove the session_frame_id from the frame_registry
  201. session->frame_registry.DeregisterFrame(
  202. waiting_message.GetMessage()->GetSessionFrameId());
  203. // if the flow control window opens up, signal FlowControlOff
  204. outstanding_messages--;
  205. if ( (outstanding_messages+1) == window_size )
  206. session->SessionFlowControlOff();
  207. // transmits messages in message store as long as the
  208. // flow control window is open
  209. ClearMessageStore();
  210. // delete the waiting message
  211. delete &waiting_message;
  212. }