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.

481 lines
14 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: message.cpp
  14. Written By: B.Rajeev
  15. ----------------------------------------------------------*/
  16. #include "precomp.h"
  17. #include "common.h"
  18. #include "sync.h"
  19. #include "message.h"
  20. #include "idmap.h"
  21. #include "dummy.h"
  22. #include "flow.h"
  23. #include "vblist.h"
  24. #include "sec.h"
  25. #include "pdu.h"
  26. #include "frame.h"
  27. #include "opreg.h"
  28. #include "ssent.h"
  29. #include "session.h"
  30. #define ILLEGAL_PDU_HANDLE 100000
  31. #define ILLEGAL_VBL_HANDLE 100000
  32. Message::Message(IN const SessionFrameId session_frame_id, IN SnmpPdu &snmp_pdu,
  33. SnmpOperation &snmp_operation
  34. ) : snmp_pdu(&snmp_pdu), operation(snmp_operation)
  35. {
  36. Message::session_frame_id = session_frame_id;
  37. }
  38. SessionFrameId Message::GetSessionFrameId(void) const
  39. {
  40. return session_frame_id;
  41. }
  42. SnmpOperation &Message::GetOperation(void) const
  43. {
  44. return operation;
  45. }
  46. SnmpPdu &Message::GetSnmpPdu(void) const
  47. {
  48. return *snmp_pdu;
  49. }
  50. void Message::SetSnmpPdu(IN SnmpPdu &new_snmp_pdu)
  51. {
  52. delete snmp_pdu;
  53. snmp_pdu = &new_snmp_pdu;
  54. }
  55. Message::~Message(void)
  56. {
  57. delete snmp_pdu;
  58. }
  59. // deregisters the waiting message from the message registry
  60. // for each request id stored in the RequestIdList
  61. void WaitingMessage::DeregisterRequestIds()
  62. {
  63. for( UINT request_ids_left = request_id_list.GetCount();
  64. request_ids_left > 0;
  65. request_id_list.RemoveHead(), request_ids_left--)
  66. {
  67. RequestId request_id = request_id_list.GetHead();
  68. session->message_registry.RemoveMessage(request_id);
  69. }
  70. }
  71. // an exit fn - prepares an error report and calls
  72. // ReceiveReply to signal a non-receipt
  73. void WaitingMessage::WrapUp(IN SnmpErrorReport &error_report)
  74. {
  75. DebugMacro4(
  76. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  77. __FILE__,__LINE__,
  78. L"WaitingMessage :: WrapUp () session_id(%d), frame_id(%d)\n" ,message->GetSessionFrameId(), last_transport_frame_id
  79. ) ;
  80. )
  81. try // ignore any exceptions arising during the ReceiveReply
  82. {
  83. // no reply to receive
  84. ReceiveReply(NULL, error_report);
  85. }
  86. catch ( Heap_Exception e_He ) {}
  87. catch(GeneralException exception) {}
  88. }
  89. // initializes the private variables
  90. WaitingMessage::WaitingMessage(IN SnmpImpSession &session,
  91. IN Message &message) : session ( NULL ) , message ( NULL ), reply_snmp_pdu ( NULL )
  92. {
  93. WaitingMessage::session = &session;
  94. // the message ptr must be deleted by the waiting message
  95. WaitingMessage::message = &message;
  96. // sent message has not been processed yet
  97. sent_message_processed = FALSE;
  98. // set illegal values for last_transport_frame_id
  99. last_transport_frame_id = ILLEGAL_TRANSPORT_FRAME_ID;
  100. // these values are currently obtained from the
  101. // session, but may be specified per message later
  102. max_rexns = SnmpImpSession :: RetryCount ( session.GetRetryCount() ) ;
  103. rexns_left = max_rexns;
  104. strobes = 0 ;
  105. active = FALSE;
  106. }
  107. // sends the message. involves request_id generation,
  108. // registering with the message_registry, decoding the
  109. // message and updating the pdu and registering a timer
  110. // event
  111. void WaitingMessage::Transmit()
  112. {
  113. try
  114. {
  115. // generate request_id and register with the registry
  116. RequestId request_id =
  117. session->message_registry.GenerateRequestId(*this);
  118. // insert the request id into the message
  119. // if unsuccessful, the exception handler gets called
  120. session->m_EncodeDecode.SetRequestId(
  121. message->GetSnmpPdu(),
  122. request_id
  123. );
  124. last_transport_frame_id = request_id ;
  125. // append the request id to the request id list
  126. request_id_list.AddTail(request_id);
  127. DebugMacro4(
  128. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  129. __FILE__,__LINE__,
  130. L"WaitingMessage :: Transmit - About to transmit (session (%d), frame_id(%d))\n", message->GetSessionFrameId(), request_id
  131. ) ;
  132. )
  133. // save the previous value of active and set the active
  134. // flag. This is needed to check on returning whether the
  135. // waiting message needs to be destroyed
  136. BOOL prev_active_state = active;
  137. active = TRUE;
  138. strobes = GetTickCount () ;
  139. // send message
  140. session->transport.TransportSendFrame(last_transport_frame_id, message->GetSnmpPdu());
  141. session->id_mapping.Associate(last_transport_frame_id, message->GetSessionFrameId());
  142. // if asked to destroy self, well, do it (and return)
  143. if ( !active )
  144. {
  145. delete this;
  146. return;
  147. }
  148. // restore the previous value of "active"
  149. active = prev_active_state;
  150. // generate timer_event_id and register with the timer
  151. session->timer.SetMessageTimerEvent(*this);
  152. DebugMacro4(
  153. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  154. __FILE__,__LINE__,
  155. L"WaitingMessage :: Transmit - Transmitted session_id(%d),frame_id(%d))\n",message->GetSessionFrameId(), request_id
  156. ) ;
  157. )
  158. }
  159. catch ( Heap_Exception e_He )
  160. {
  161. WrapUp(GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__));
  162. throw;
  163. }
  164. catch(GeneralException exception)
  165. {
  166. WrapUp(exception);
  167. throw;
  168. }
  169. }
  170. // used by the timer to notify the waiting message of
  171. // a timer event. if need, the message is retransmitted.
  172. // when all rexns are exhausted, ReceiveReply is called
  173. void WaitingMessage::TimerNotification()
  174. {
  175. DWORD t_Ticks = GetTickCount () ;
  176. if ( strobes > t_Ticks )
  177. {
  178. strobes = t_Ticks ; // Take hit on clock overflow
  179. return ;
  180. }
  181. if ( ( t_Ticks - strobes ) >= SnmpImpSession :: RetryTimeout ( session->GetRetryTimeout () ) )
  182. {
  183. DebugMacro4(
  184. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  185. __FILE__,__LINE__,
  186. L"WaitingMessage :: TimerNotification - timed out after (%ld)" , ( t_Ticks - strobes )
  187. ) ;
  188. )
  189. // if any rexns left, update rexns_left, send message
  190. if ( rexns_left > 0 )
  191. {
  192. // generate request_id and register with the registry
  193. RequestId request_id = session->message_registry.GenerateRequestId(*this);
  194. // insert the request id into the message
  195. // if unsuccessful, the exception handler gets called
  196. try
  197. {
  198. session->m_EncodeDecode.SetRequestId(
  199. message->GetSnmpPdu() ,
  200. request_id
  201. );
  202. }
  203. catch ( Heap_Exception e_He )
  204. {
  205. WrapUp(GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__));
  206. return ;
  207. }
  208. catch(GeneralException exception)
  209. {
  210. WrapUp(exception);
  211. return;
  212. }
  213. last_transport_frame_id = request_id ;
  214. // append the request id to the request id list
  215. request_id_list.AddTail(request_id);
  216. BOOL prev_active_state = active;
  217. active = TRUE;
  218. strobes = GetTickCount () ;
  219. DebugMacro4(
  220. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  221. __FILE__,__LINE__,
  222. L"WaitingMessage :: TimerNotification - Resend %d.%d, req_id(%d), this(%d) at time (%d)\n",message->GetSessionFrameId(), rexns_left, request_id, this, strobes
  223. ) ;
  224. )
  225. session->id_mapping.DisassociateTransportFrameId(last_transport_frame_id);
  226. // send message
  227. session->transport.TransportSendFrame(last_transport_frame_id, message->GetSnmpPdu());
  228. // associate the last transport frame id with the session frame id
  229. session->id_mapping.Associate(last_transport_frame_id, message->GetSessionFrameId());
  230. // if asked to destroy self, well, do it (and return)
  231. if ( !active )
  232. {
  233. delete this;
  234. return;
  235. }
  236. // restore the previous value of "active"
  237. active = prev_active_state;
  238. rexns_left--;
  239. DebugMacro4(
  240. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  241. __FILE__,__LINE__,
  242. L"WaitingMessage :: TimerNotification - Retransmitted session_id(%d),frame_id(%d))\n",message->GetSessionFrameId(), last_transport_frame_id
  243. ) ;
  244. )
  245. }
  246. else
  247. {
  248. DebugMacro4(
  249. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  250. __FILE__,__LINE__,
  251. L"WaitingMessage :: TimerNotification - No response session_id(%d),frame_id(%d))\n",message->GetSessionFrameId(), last_transport_frame_id
  252. ) ;
  253. )
  254. // else wrap up as no response has been received
  255. WrapUp(SnmpErrorReport(Snmp_Error, Snmp_No_Response));
  256. return; // since the waiting_message would have been destroyed
  257. }
  258. }
  259. else
  260. {
  261. }
  262. }
  263. // A call to this function signifies that state corresponding to the
  264. // waiting_message need not be kept any further
  265. // if required, it cancels the timer event and
  266. // deregisters with the message registry
  267. // it notifies the flow control mechanism of the termination
  268. // which destroys the waiting_message
  269. void WaitingMessage::ReceiveReply(IN const SnmpPdu *snmp_pdu, IN SnmpErrorReport &error_report)
  270. {
  271. DebugMacro4(
  272. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  273. __FILE__,__LINE__,
  274. 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()
  275. ) ;
  276. )
  277. // cancels registrations with message registry
  278. DeregisterRequestIds();
  279. // cancels timer event
  280. session->timer.CancelMessageTimer(*this,session->timer_event_id);
  281. // if required (the corresponding SENT event has not been signaled
  282. // yet), cancel the association with the last transport frame id
  283. if ( last_transport_frame_id != ILLEGAL_TRANSPORT_FRAME_ID )
  284. {
  285. session->id_mapping.DisassociateTransportFrameId(last_transport_frame_id);
  286. last_transport_frame_id = ILLEGAL_TRANSPORT_FRAME_ID;
  287. }
  288. // call fc_mech.NotifyReceipt(this,pdu,error_report)
  289. // which should destroy the waiting message
  290. session->flow_control.NotifyReceipt(*this, snmp_pdu, error_report);
  291. }
  292. // buffers the snmp pdu received as a reply
  293. void WaitingMessage::BufferReply(IN const SnmpPdu &reply_snmp_pdu)
  294. {
  295. if ( WaitingMessage::reply_snmp_pdu == NULL )
  296. {
  297. DebugMacro4(
  298. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  299. __FILE__,__LINE__,
  300. L"WaitingMessage :: Buffering reply %d, %d, this(%d)\n",message->GetSessionFrameId(), rexns_left, this
  301. ) ;
  302. )
  303. WaitingMessage::reply_snmp_pdu = new SnmpPdu((SnmpPdu&)reply_snmp_pdu);
  304. }
  305. }
  306. // returns TRUE if a reply has been buffered
  307. BOOL WaitingMessage::ReplyBuffered()
  308. {
  309. return (reply_snmp_pdu != NULL);
  310. }
  311. // returns a ptr to the buffered reply pdu, if buffered
  312. // otherwise a null ptr is returned
  313. // IMPORTANT: it sets the reply_snmp_pdu to NULL, so that it may not
  314. // be deleted when the waiting message is destroyed
  315. SnmpPdu *WaitingMessage::GetBufferedReply()
  316. {
  317. SnmpPdu *to_return = reply_snmp_pdu;
  318. reply_snmp_pdu = NULL;
  319. return to_return;
  320. }
  321. // informs the waiting message that a sent message has been
  322. // processed
  323. void WaitingMessage::SetSentMessageProcessed()
  324. {
  325. sent_message_processed = TRUE;
  326. }
  327. // if a sent message has been processed, it returns TRUE, else FALSE
  328. BOOL WaitingMessage::GetSentMessageProcessed()
  329. {
  330. return sent_message_processed;
  331. }
  332. void WaitingMessage::SelfDestruct(void)
  333. {
  334. if ( !active )
  335. {
  336. delete this;
  337. return;
  338. }
  339. else // else, set the active flag to FALSE
  340. // when this is detected, it'll self destruct
  341. active = FALSE;
  342. }
  343. TimerEventId WaitingMessage::GetTimerEventId ()
  344. {
  345. return m_TimerEventId ;
  346. }
  347. void WaitingMessage::SetTimerEventId ( TimerEventId a_TimerEventId )
  348. {
  349. m_TimerEventId = a_TimerEventId ;
  350. }
  351. // if required, it cancels registration with the message_registry and
  352. // the timer event with the timer.
  353. WaitingMessage::~WaitingMessage(void)
  354. {
  355. // if required, cancel registrations with message registry
  356. if ( !request_id_list.IsEmpty() )
  357. DeregisterRequestIds();
  358. session->timer.CancelMessageTimer(*this,session->timer_event_id);
  359. // if required (the corresponding SENT event has not been signaled
  360. // yet), cancel the association with the last transport frame id
  361. if ( last_transport_frame_id != ILLEGAL_TRANSPORT_FRAME_ID )
  362. session->id_mapping.DisassociateTransportFrameId(last_transport_frame_id);
  363. // if a reply pdu has been buffered, destroy it
  364. if ( reply_snmp_pdu != NULL )
  365. {
  366. delete &reply_snmp_pdu->GetVarbindList () ;
  367. delete reply_snmp_pdu;
  368. }
  369. // deletes the message ptr
  370. delete message;
  371. }