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.

608 lines
16 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: op.cpp
  14. Written By: B.Rajeev
  15. ----------------------------------------------------------*/
  16. #include "precomp.h"
  17. #include "common.h"
  18. #include "sync.h"
  19. #include "encap.h"
  20. #include "value.h"
  21. #include "vblist.h"
  22. #include "vbl.h"
  23. #include "fs_reg.h"
  24. #include "error.h"
  25. #include "sec.h"
  26. #include "pdu.h"
  27. #include "pseudo.h"
  28. #include "dummy.h"
  29. #include "flow.h"
  30. #include "frame.h"
  31. #include "timer.h"
  32. #include "message.h"
  33. #include "ssent.h"
  34. #include "idmap.h"
  35. #include "opreg.h"
  36. #include "session.h"
  37. #include "ophelp.h"
  38. #include "op.h"
  39. #include "encdec.h"
  40. void SnmpOperation::ReceiveResponse()
  41. {
  42. }
  43. // the operation uses window messaging encapsulated within the dummy session
  44. // to make the callbacks to an operation user, asynchronous with respect
  45. // to the user's call to SendRequest
  46. // the events currently posted are SEND_ERROR and OPERATION_COMPLETION
  47. LONG SnmpOperation::ProcessInternalEvent(
  48. HWND hWnd,
  49. UINT user_msg_id,
  50. WPARAM wParam,
  51. LPARAM lParam
  52. )
  53. {
  54. LONG rc = 0;
  55. CriticalSectionLock access_lock(exclusive_CriticalSection); // TRUE
  56. // obtain exclusive access into the system
  57. if ( !access_lock.GetLock(INFINITE) )
  58. {
  59. is_valid = FALSE;
  60. return rc;
  61. }
  62. // return immediately, if the operation is not valid
  63. if ( !is_valid )
  64. return rc;
  65. // process the message
  66. if ( user_msg_id == Window :: g_SendErrorEvent )
  67. {
  68. // in case the attempt to send a frame failed
  69. VBList *vblist = (VBList *)wParam;
  70. GeneralException *exception = (GeneralException *)lParam;
  71. ReceiveErroredResponse(vblist->GetIndex (),vblist->GetVarBindList(), *exception);
  72. delete vblist;
  73. delete exception;
  74. }
  75. else if ( user_msg_id == Window :: g_OperationCompletedEvent )
  76. {
  77. // signals completion of the operation
  78. frame_state_registry.DestroySecurity();
  79. in_progress = FALSE;
  80. ReceiveResponse();
  81. }
  82. else
  83. {
  84. // predefined window message
  85. DefWindowProc(hWnd, user_msg_id, wParam, lParam);
  86. }
  87. // give up exclusive access
  88. access_lock.UnLock();
  89. // since this is also a point of entry into the SnmpOperation
  90. // we must check for deletion of the operation
  91. CheckOperationDeletion();
  92. return rc;
  93. }
  94. // this method may be called to delete the Operation
  95. // note: the operation is deleted when a public method
  96. // returns. For this reason, if a public method calls another
  97. // public method, it must not access any per-class variables
  98. // after that.
  99. void SnmpOperation::DestroyOperation()
  100. {
  101. delete_operation = TRUE;
  102. }
  103. // its mandatory for every public method to call this method
  104. // before returning to the caller
  105. // it checks if the call sequence included a call to DestroyOperation
  106. // and if so, deletes "this" before returning
  107. void SnmpOperation::CheckOperationDeletion()
  108. {
  109. if ( delete_operation == TRUE )
  110. delete this;
  111. }
  112. #pragma warning (disable:4355)
  113. // initializes variables and, if successful, registers itself with the session
  114. SnmpOperation::SnmpOperation(
  115. SnmpSession &snmp_session
  116. ) : session(snmp_session),
  117. m_OperationWindow(*this),
  118. helper(*this)
  119. {
  120. in_progress = FALSE;
  121. is_valid = FALSE;
  122. if ( !m_OperationWindow() )
  123. return;
  124. varbinds_per_pdu = SnmpImpSession :: VarbindsPerPdu ( session.GetVarbindsPerPdu() ) ;
  125. delete_operation = FALSE;
  126. session.RegisterOperation(*this);
  127. is_valid = TRUE;
  128. }
  129. #pragma warning (default:4355)
  130. // on destruction, the operation cancels all outstanding frames,
  131. // frees the allocated memory for variables and deregisters with the session
  132. SnmpOperation::~SnmpOperation(void)
  133. {
  134. // calls to public functions from this point should not
  135. // cause repeated deletion - so set the flag to FALSE
  136. delete_operation = FALSE;
  137. // cancel any outstanding frames
  138. CancelRequest();
  139. // deregister with session
  140. session.DeregisterOperation(*this);
  141. }
  142. // sends the varbinds in the var bind list packaged in several
  143. // frames each carrying atmost varbinds_per_pdu varbinds
  144. // if the security context is not NULL, same is used as the context
  145. // for all the generated frames
  146. void SnmpOperation::SendRequest(
  147. IN SnmpVarBindList &varBindList,
  148. IN SnmpSecurity *security
  149. )
  150. {
  151. // if not valid, return immediately
  152. if ( !is_valid )
  153. return;
  154. CriticalSectionLock access_lock(exclusive_CriticalSection); // TRUE
  155. // obtain exclusive access into the system
  156. if ( !access_lock.GetLock(INFINITE) )
  157. {
  158. is_valid = FALSE;
  159. return;
  160. }
  161. // if already in progress, we cannot proceed
  162. if ( in_progress == TRUE )
  163. return;
  164. in_progress = TRUE;
  165. // if length of varBindList exceeds varbinds_per_pdu
  166. // call FrameOverRun()
  167. if ( varBindList.GetLength() > varbinds_per_pdu )
  168. FrameOverRun();
  169. // check if the send request has been cancelled in the
  170. // meantime. Proceed only if still in progress
  171. if ( !in_progress )
  172. return;
  173. // register the security for the duration of SendRequest
  174. // (until a reply for the last outstanding frame is received)
  175. frame_state_registry.RegisterSecurity(security);
  176. // send the varbind list
  177. SendVarBindList(varBindList);
  178. // if no outstanding frames, post a message for the completion
  179. // of operation. This message, when processed, shall set the
  180. // in_progress status, destroy security and call ReceiveResponse
  181. if ( frame_state_registry.Empty() )
  182. {
  183. m_OperationWindow.PostMessage (
  184. Window :: g_OperationCompletedEvent ,
  185. 0,
  186. 0
  187. );
  188. }
  189. // give up exclusive access
  190. // access_lock.UnLock(); The lock may be released at this point
  191. }
  192. void SnmpOperation::SendRequest(IN SnmpVarBindList &varBindList)
  193. {
  194. SendRequest(varBindList, NULL);
  195. CheckOperationDeletion();
  196. }
  197. void SnmpOperation::SendRequest(
  198. IN SnmpVarBindList &varBindList,
  199. IN SnmpSecurity &security
  200. )
  201. {
  202. SendRequest(varBindList, &security);
  203. CheckOperationDeletion();
  204. }
  205. // sends the varbinds in the var bind list packaged in several
  206. // frames each carrying atmost MIN(varbinds_per_pdu, max_size) varbinds
  207. void SnmpOperation::SendVarBindList(IN SnmpVarBindList &varBindList,
  208. IN UINT max_size,
  209. IN ULONG var_index )
  210. {
  211. UINT max_varbinds_per_pdu = MIN(varbinds_per_pdu, max_size);
  212. UINT list_length = varBindList.GetLength();
  213. // set list iterator to the start of the list,
  214. // current_position <- 0
  215. varBindList.Reset();
  216. varBindList.Next();
  217. UINT current_position = 0;
  218. // chop up the varBindList into segments atmost max_varbinds_per_pdu
  219. // in size and send them in separate frames
  220. while ( current_position < list_length )
  221. {
  222. UINT segment_length = MIN((list_length-current_position), max_varbinds_per_pdu);
  223. // create copy of the varBindList from
  224. // current_position (of length segment_length)
  225. SnmpVarBindList *list_segment = varBindList.CopySegment(segment_length);
  226. // create a VBList and call SendFrame with it
  227. SendFrame (
  228. *(new VBList(session.GetSnmpEncodeDecode (),*list_segment,var_index + current_position + 1))
  229. );
  230. // update current_position
  231. current_position += segment_length;
  232. }
  233. }
  234. // transmits a frame with the var binds in the vblist
  235. // using the session and registers the frame state
  236. void SnmpOperation::SendFrame(VBList &vblist)
  237. {
  238. try
  239. {
  240. SessionFrameId session_frame_id = 0L;
  241. helper.TransmitFrame (
  242. session_frame_id,
  243. vblist
  244. );
  245. FrameState *frame_state = new FrameState(session_frame_id,vblist);
  246. // insert a frame_state(session_frame_id, vblist)
  247. frame_state_registry.Insert(session_frame_id, *frame_state );
  248. }
  249. catch(GeneralException exception)
  250. {
  251. // post a message to signal the error in sending the frame
  252. // when processed, it shall call ReceiveErroredResponse and
  253. // delete the vblist
  254. m_OperationWindow.PostMessage (
  255. Window :: g_SendErrorEvent ,
  256. (WPARAM)&vblist,
  257. (LPARAM)(new GeneralException(exception))
  258. );
  259. }
  260. }
  261. // a sent frame notification from the session signifies one transmission
  262. // of the frame. atmost one notification per session frame id can
  263. // signal an error in transmission
  264. void SnmpOperation::SentFrame(
  265. IN const SessionFrameId session_frame_id,
  266. IN const SnmpErrorReport &error_report
  267. )
  268. {
  269. DebugMacro4(
  270. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  271. __FILE__,__LINE__,
  272. L"Sent %d\n" ,session_frame_id
  273. ) ;
  274. )
  275. // if there was an error in sending, let ReceiveFrame handle it
  276. // otherwise ignore it and wait for the reply
  277. if ( error_report.GetError() != Snmp_Success )
  278. {
  279. ReceiveFrame (
  280. session_frame_id,
  281. SnmpPdu(),
  282. error_report
  283. );
  284. }
  285. else
  286. {
  287. CheckOperationDeletion();
  288. }
  289. // since ReceiveFrame might have deleted the operation, we
  290. // must call CheckOperationDeletion only in the else
  291. }
  292. // cancels all the frames whose frame states are currently present in
  293. // the frame state registry
  294. void SnmpOperation::CancelRequest()
  295. {
  296. // if not valid, return immediately
  297. if ( !is_valid )
  298. return;
  299. CriticalSectionLock exclusive_lock(exclusive_CriticalSection);
  300. // obtain exclusive access
  301. if ( !exclusive_lock.GetLock(INFINITE) )
  302. {
  303. is_valid = FALSE;
  304. return;
  305. }
  306. // if not in progress, there is nothing to be done
  307. if ( !in_progress )
  308. return;
  309. // reset the frame_state_registry to set
  310. // the iterator to the beginning
  311. frame_state_registry.ResetIterator();
  312. // cancel all outstanding frames
  313. while (1)
  314. {
  315. // for each registered frame_state
  316. // remove it from the frame_state_registry
  317. FrameState *frame_state = frame_state_registry.GetNext();
  318. // if no more frames, we are done
  319. if ( frame_state == NULL )
  320. break;
  321. // cancel the corresponding frame
  322. session.SessionCancelFrame(
  323. frame_state->GetSessionFrameId()
  324. );
  325. // destroy frame_state
  326. delete frame_state;
  327. }
  328. // remove all the associations
  329. frame_state_registry.RemoveAll();
  330. // destroy the security
  331. frame_state_registry.DestroySecurity();
  332. // in_progress <- FALSE
  333. in_progress = FALSE;
  334. m_OperationWindow.PostMessage (
  335. Window :: g_OperationCompletedEvent ,
  336. 0,
  337. 0
  338. );
  339. // leave exclusive access
  340. exclusive_lock.UnLock();
  341. CheckOperationDeletion();
  342. }
  343. void SnmpOperation::ReceiveErroredResponse(
  344. ULONG var_index ,
  345. SnmpVarBindList &errored_list,
  346. const SnmpErrorReport &error_report
  347. )
  348. {
  349. ULONG t_Index = 0 ;
  350. errored_list.Reset();
  351. while( errored_list.Next() )
  352. {
  353. const SnmpVarBind *var_bind = errored_list.Get();
  354. ReceiveErroredVarBindResponse(
  355. var_index + t_Index ,
  356. *var_bind,
  357. error_report
  358. );
  359. t_Index ++ ;
  360. }
  361. }
  362. // ReceiveFrame is called by the session when a reply is received for
  363. // an outstanding frame or it has received no response for its
  364. // retransmissions. It may also be called by the SnmpOperation::SentFrame
  365. // when the error report shows an error during transmission
  366. // It decodes the received snmp pdu and processes it or else, if no
  367. // reply has been received, informs the user of the error report
  368. // when all no outstanding frames remain, an OPERATION_COMPLETION event
  369. // is posted to inform the user of the event asynchronously
  370. void SnmpOperation::ReceiveFrame(
  371. IN const SessionFrameId session_frame_id,
  372. IN const SnmpPdu &snmpPdu,
  373. IN const SnmpErrorReport &errorReport
  374. )
  375. {
  376. DebugMacro4(
  377. SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
  378. __FILE__,__LINE__,
  379. L"SnmpOperation::ReceiveFrame: received(%d), error(%d), status(%d)\n",session_frame_id, errorReport.GetError(), errorReport.GetStatus()
  380. ) ;
  381. )
  382. // if not valid, return immediately
  383. if ( !is_valid )
  384. return;
  385. CriticalSectionLock exclusive_lock(exclusive_CriticalSection);
  386. // obt. exclusive access
  387. if ( !exclusive_lock.GetLock(INFINITE) )
  388. {
  389. is_valid = FALSE;
  390. return;
  391. }
  392. // if not in progress, nothing needs to be done
  393. // ignore the
  394. if ( !in_progress )
  395. return;
  396. // get corresponding frame_state
  397. FrameState *frame_state = frame_state_registry.Remove(session_frame_id);
  398. // if no such frame_state return
  399. if ( frame_state == NULL )
  400. return;
  401. // decode the frame to extract
  402. // vbl, error-index, error-status
  403. SnmpErrorReport t_SnmpErrorReport ;
  404. SnmpVarBindList *t_SnmpVarBindList ;
  405. SnmpCommunityBasedSecurity *t_SnmpCommunityBasedSecurity = NULL ;
  406. SnmpTransportAddress *t_SrcTransportAddress = NULL ;
  407. SnmpTransportAddress *t_DstTransportAddress = NULL ;
  408. SnmpEncodeDecode :: PduType t_PduType = SnmpEncodeDecode :: PduType :: GET;
  409. RequestId t_RequestId = 0 ;
  410. try
  411. {
  412. session.GetSnmpEncodeDecode ().DecodeFrame (
  413. ( SnmpPdu& ) snmpPdu ,
  414. t_RequestId ,
  415. t_PduType ,
  416. t_SnmpErrorReport ,
  417. t_SnmpVarBindList ,
  418. t_SnmpCommunityBasedSecurity ,
  419. t_SrcTransportAddress ,
  420. t_DstTransportAddress
  421. );
  422. }
  423. catch(GeneralException exception)
  424. {
  425. CheckOperationDeletion();
  426. return;
  427. }
  428. t_SnmpErrorReport = errorReport ;
  429. helper.ProcessResponse (
  430. frame_state,
  431. *t_SnmpVarBindList,
  432. t_SnmpErrorReport
  433. );
  434. // if the registry is empty,
  435. // destroy security, set in_progress, release exclusive access
  436. // call ReceiveResponse() to signal completion finally
  437. if ( frame_state_registry.Empty() )
  438. {
  439. frame_state_registry.DestroySecurity();
  440. in_progress = FALSE;
  441. // leave exclusive access: so that the ReceiveResponse
  442. // call back may be able to make another SendRequest
  443. exclusive_lock.UnLock();
  444. // call the user to inform him of completion
  445. ReceiveResponse();
  446. }
  447. else
  448. {
  449. // leave exclusive access
  450. exclusive_lock.UnLock();
  451. }
  452. CheckOperationDeletion();
  453. }
  454. // The GetOperation sends the GET PDU
  455. SnmpEncodeDecode :: PduType SnmpGetOperation::GetPduType(void)
  456. {
  457. return SnmpEncodeDecode :: GET;
  458. }
  459. // The GetOperation sends the GETNEXT PDU
  460. SnmpEncodeDecode ::PduType SnmpGetNextOperation::GetPduType(void)
  461. {
  462. return SnmpEncodeDecode :: GETNEXT;
  463. }
  464. // The GetOperation sends the SET PDU
  465. SnmpEncodeDecode :: PduType SnmpSetOperation::GetPduType(void)
  466. {
  467. return SnmpEncodeDecode :: SET;
  468. }