Source code of Windows XP (NT5)
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.

992 lines
22 KiB

  1. /*++
  2. Copyright (c) 1998 - 2000 Microsoft Corporation
  3. Module Name:
  4. cbridge.cpp
  5. Abstract:
  6. Contains the CALL_BRIDGE-related common definitions
  7. (not specific to Q931 or H245).
  8. The call bridge calls the event manager for async winsock
  9. operations and the event manager calls the overlapped
  10. processor with the results.
  11. Revision History:
  12. 1. created
  13. Byrisetty Rajeev (rajeevb) 12-Jun-1998
  14. 2. q931.cpp and h245.cpp were created with functions in this
  15. file on 21-Aug-1998. This was done to reduce file sizes and
  16. remote unnecessary tapi, rend, atl dependencies.
  17. --*/
  18. /* TO DO -
  19. 4. Need fn on Q931_INFO and H245_INFO to simplify modify a PDU from the opposite
  20. instance and forward it to its remote end.
  21. 6. Clearly define when and where we should return if in shutdown mode
  22. 7. Need to use the oss library free methods to free the pdu structs
  23. 9. Must receive be queued (always) after state transition? Does it matter?
  24. 10. Should try to recover from error situations, but should initiate clean
  25. up in case of unrecoverable situations.
  26. 11. Need to isolate recoverable error situations.
  27. 12. Use a table to handle PDUs in a given state - look at the destination
  28. instance's (q931) methods for the same.
  29. DONE -
  30. 1. Should the state transition be fired immediately or after the actions have been taken
  31. Ans: Should be done after the actions as, in case of error, if the state transition is still
  32. fired, the actions will never be retried. So failure should either be handled by resetting
  33. the member variables or by always using temporary variables and copying the results into
  34. member variables after state transition.
  35. 5. IMPORTANT: Need to send the RELEASE COMPLETE PDU before initiating termination
  36. Ans: We first pass on the PDU to the other instance and then perform state
  37. transitions as well as initiate termination.
  38. 8. Call reference value should be 1-3 bytes, its a WORD currently in both
  39. the q931pdu.h file as well as the cbridge class
  40. Ans: The h225 spec defines the call ref field to be 2 bytes (WORD).
  41. NOT DONE -
  42. 2. Should we try to consolidate all actions taken in response to an event in a single fn
  43. instead of spreading it around in the src and dest instances? Can this be done via
  44. inline fns instead (to maintain some encapsulation)
  45. 3. Should we handle timer events in the same fns as the PDU events?
  46. */
  47. #include "stdafx.h"
  48. // CALL_BRIDGE --------------------------------------------------------------------------
  49. HRESULT CALL_BRIDGE::Initialize (
  50. IN SOCKET Socket,
  51. IN SOCKADDR_IN * LocalAddress,
  52. IN SOCKADDR_IN * RemoteAddress,
  53. IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
  54. )
  55. /*++
  56. Routine Description:
  57. Initializes an instance of CALL_BRIDGE
  58. Arguments:
  59. Socket - Socket on which connection was accepted
  60. LocalAddress - Address of the local side of the session
  61. RemoteAddress - Address of the remote side of the session
  62. RedirectInformation - Information about the redirect (obtained from NAT)
  63. Return Values:
  64. Passes through return value of another method
  65. Notes:
  66. --*/
  67. {
  68. HRESULT Result;
  69. Lock();
  70. Result = InitializeLocked (
  71. Socket,
  72. LocalAddress,
  73. RemoteAddress,
  74. RedirectInformation);
  75. Unlock();
  76. return Result;
  77. } // CALL_BRIDGE::Initialize
  78. HRESULT CALL_BRIDGE::InitializeLocked (
  79. IN SOCKET Socket,
  80. IN SOCKADDR_IN * LocalAddress,
  81. IN SOCKADDR_IN * RemoteAddress,
  82. IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
  83. )
  84. /*++
  85. Routine Description:
  86. Initializes an instance of CALL_BRIDGE
  87. Arguments:
  88. Socket - Socket on which connection was accepted
  89. LocalAddress - Address of the local side of the session
  90. RemoteAddress - Address of the remote side of the session
  91. RedirectInformation - Information about the redirect (obtained from NAT)
  92. Return Values:
  93. S_OK if successful
  94. E_UNEXPECTED if the instance has already been initialized
  95. Otherwise, passes through status code returned by other
  96. functions/methods
  97. Notes:
  98. To be called for a locked instance
  99. --*/
  100. {
  101. HRESULT Result;
  102. ULONG Error;
  103. assert (Socket != INVALID_SOCKET);
  104. assert (LocalAddress);
  105. assert (RemoteAddress);
  106. if (State != STATE_NONE) {
  107. DebugF(_T("Q931: 0x%x has already been initialized, cannot do so again.\n"), this);
  108. return E_UNEXPECTED;
  109. }
  110. DebugF (_T ("Q931: 0x%x connection accepted on adapter %d.\n"), this, RedirectInformation -> AdapterIndex);
  111. SourceInterfaceAddress = H323MapAdapterToAddress (RedirectInformation -> AdapterIndex);
  112. if (INADDR_NONE == SourceInterfaceAddress) {
  113. DebugF (_T ("Q931: 0x%x failed to get source interface address (via H323MapAdapterToAddress).\n"), this);
  114. return E_FAIL;
  115. }
  116. // Address of the best interface to the destination will be determined when alias in Q.931 Setup PDU is
  117. // mapped to the real destination address.
  118. DebugF (_T("Q931: 0x%x arrived on interface %08X.\n"), this, SourceInterfaceAddress);
  119. Result = EventMgrBindIoHandle (Socket);
  120. if (Result != S_OK) {
  121. DebugErrorF (Result, _T("Q931: 0x%x failed to bind I/O handle to completion port\n"), this);
  122. return Result;
  123. }
  124. DebugF (_T("Q931: 0x%x bound I/O handle to socket %x.\n"), this, Socket);
  125. // init source call state
  126. m_SourceH323State.Init (*this);
  127. Result = m_SourceH323State.GetSourceQ931Info().SetIncomingSocket(
  128. Socket,
  129. const_cast <SOCKADDR_IN *> (LocalAddress),
  130. const_cast <SOCKADDR_IN *> (RemoteAddress));
  131. // init dest call state
  132. Result = m_DestH323State.Init (*this);
  133. if (Result != S_OK) {
  134. return Result;
  135. }
  136. State = STATE_CONNECTED;
  137. return Result;
  138. } // CALL_BRIDGE::InitializeLocked
  139. void
  140. CALL_BRIDGE::Terminate (
  141. void
  142. )
  143. /*++
  144. Routine Description:
  145. Terminates the instance
  146. Arguments:
  147. None
  148. Return Values:
  149. None
  150. Notes:
  151. 1. To be called for a locked instance only.
  152. 2. Not to be called when Q.931 Release Complete PDU is received
  153. --*/
  154. {
  155. switch (State) {
  156. case STATE_NONE:
  157. DebugF (_T("Q931: 0x%x terminates. STATE_NONE --> TERMINATED\n"), this);
  158. State = STATE_TERMINATED;
  159. CallBridgeList.RemoveCallBridge (this);
  160. break;
  161. case STATE_TERMINATED:
  162. DebugF (_T("Q931: 0x%x terminates. TERMINATED --> TERMINATED\n"), this);
  163. // no transition
  164. break;
  165. case STATE_CONNECTED:
  166. DebugF (_T("Q931: 0x%x terminates. STATE_CONN --> TERMINATED\n"), this);
  167. // call is currently active
  168. // begin the process of tearing down call state
  169. State = STATE_TERMINATED;
  170. m_SourceH323State.GetQ931Info().SendReleaseCompletePdu();
  171. m_DestH323State.GetQ931Info().SendReleaseCompletePdu();
  172. // cancel all timers, ignore error code
  173. CancelAllTimers ();
  174. // close each socket
  175. m_SourceH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
  176. m_DestH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
  177. CallBridgeList.RemoveCallBridge (this);
  178. break;
  179. default:
  180. assert (FALSE);
  181. break;
  182. }
  183. } // CALL_BRIDGE::Terminate
  184. void
  185. CALL_BRIDGE::TerminateExternal (
  186. void
  187. )
  188. /*++
  189. Routine Description:
  190. Terminates the instance
  191. Arguments:
  192. None
  193. Return Values:
  194. None
  195. Notes:
  196. Not to be called when Q.931 Release Complete PDU is received
  197. --*/
  198. {
  199. Lock();
  200. Terminate ();
  201. Unlock();
  202. } // CALL_BRIDGE::TerminateExternal
  203. BOOL
  204. CALL_BRIDGE::IsConnectionThrough (
  205. IN DWORD InterfaceAddress // host order
  206. )
  207. /*++
  208. Routine Description:
  209. Determines whether the connection goes through the
  210. interface specified
  211. Arguments:
  212. InterfaceAddress - address of the interface for which
  213. the determination is to be made.
  214. Return Values:
  215. TRUE - if the connection being proxied goes through the
  216. interface specified
  217. FALSE - if the connection being proxied does not go through the
  218. interface specified
  219. Notes:
  220. --*/
  221. {
  222. BOOL IsThrough;
  223. IsThrough = (InterfaceAddress == SourceInterfaceAddress) ||
  224. (InterfaceAddress == DestinationInterfaceAddress);
  225. return IsThrough;
  226. } // CALL_BRIDGE::IsConnectionThrough
  227. void
  228. CALL_BRIDGE::OnInterfaceShutdown (
  229. void
  230. )
  231. /*++
  232. Routine Description:
  233. Performs necessary actions when a network interface
  234. through which the connection being proxied goes down.
  235. Arguments:
  236. None
  237. Return Value:
  238. None
  239. Notes:
  240. --*/
  241. {
  242. Lock ();
  243. switch (State) {
  244. case STATE_NONE:
  245. DebugF (_T("Q931: 0x%x terminates (interface goes down). STATE_NONE --> TERMINATED\n"), this);
  246. State = STATE_TERMINATED;
  247. CallBridgeList.RemoveCallBridge (this);
  248. break;
  249. case STATE_TERMINATED:
  250. DebugF (_T("Q931: 0x%x terminates (interface goes down). TERMINATED --> TERMINATED\n"), this);
  251. // no transition
  252. break;
  253. case STATE_CONNECTED:
  254. DebugF (_T("Q931: 0x%x terminates (interface goes down). STATE_CONN --> TERMINATED\n"), this);
  255. // call is currently active
  256. // begin the process of tearing down call state
  257. State = STATE_TERMINATED;
  258. m_SourceH323State.GetH245Info().SendEndSessionCommand ();
  259. m_DestH323State.GetH245Info().SendEndSessionCommand ();
  260. m_SourceH323State.GetQ931Info().SendReleaseCompletePdu();
  261. m_DestH323State.GetQ931Info().SendReleaseCompletePdu();
  262. // cancel all timers, ignore error code
  263. CancelAllTimers ();
  264. CallBridgeList.RemoveCallBridge (this);
  265. break;
  266. default:
  267. assert (FALSE);
  268. break;
  269. }
  270. Unlock ();
  271. } // CALL_BRIDGE::OnInterfaceShutdown
  272. void
  273. CALL_BRIDGE::TerminateCallOnReleaseComplete (
  274. void
  275. )
  276. /*++
  277. Routine Description:
  278. Terminate the instance when Q.931 Release Complete PDU is received
  279. Arguments:
  280. None
  281. Return Values:
  282. None
  283. Notes:
  284. --*/
  285. {
  286. if (State != STATE_TERMINATED)
  287. {
  288. State = STATE_TERMINATED;
  289. CancelAllTimers ();
  290. // CODEWORK: When we are in a terminating state we need not process
  291. // any more PDUs. We can just drop them.
  292. // CODEWORK: When the proxy is originating the call shutdown (because
  293. // of an error or timeout, it should send ReleaseComplete PDUs and
  294. // endSessionCommand PDUs to either side. Do we need to send
  295. // closeLC PDUs also ?
  296. // We probably need a state called RELEASE_COMPLETE_SENT and after
  297. // this any more errors means we just mercilessly shut down everything.
  298. // close H245 sockets, if any as they may have outstanding
  299. // async receive/send requests pending
  300. // NOTE: the source H245 info may be listening for incoming connections
  301. // in which case we just close the listen socket
  302. m_SourceH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
  303. m_DestH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
  304. CallBridgeList.RemoveCallBridge (this);
  305. }
  306. } // CALL_BRIDGE::TerminateCallOnReleaseComplete
  307. DWORD
  308. CALL_BRIDGE::GetSourceInterfaceAddress (
  309. void
  310. ) const
  311. /*++
  312. Routine Description:
  313. Accessor method
  314. Arguments:
  315. None
  316. Return Values:
  317. Address of the interface on which the connection was
  318. accepted
  319. Notes:
  320. --*/
  321. {
  322. return SourceInterfaceAddress;
  323. } // CALL_BRIDGE::GetSourceInterfaceAddress
  324. VOID
  325. CALL_BRIDGE::GetSourceAddress (
  326. OUT SOCKADDR_IN* ReturnSourceAddress
  327. )
  328. /*++
  329. Routine Description:
  330. Accessor method
  331. Arguments:
  332. None
  333. Return Values (by reference):
  334. Address of the remote party that initiated the call
  335. Notes:
  336. --*/
  337. {
  338. _ASSERTE(ReturnSourceAddress);
  339. ReturnSourceAddress->sin_family = SourceAddress.sin_family;
  340. ReturnSourceAddress->sin_addr.s_addr = SourceAddress.sin_addr.s_addr;
  341. ReturnSourceAddress->sin_port = SourceAddress.sin_port;
  342. }
  343. void CALL_BRIDGE::GetDestinationAddress (
  344. OUT SOCKADDR_IN * ReturnDestinationAddress
  345. )
  346. /*++
  347. Routine Description:
  348. Accessor method
  349. Arguments:
  350. ReturnDestinationAddress (out) - Destination address of
  351. the session this instance proxies
  352. Return Values:
  353. None
  354. Notes:
  355. --*/
  356. {
  357. assert (ReturnDestinationAddress);
  358. *ReturnDestinationAddress = DestinationAddress;
  359. }
  360. CALL_BRIDGE::CALL_BRIDGE (
  361. NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
  362. )
  363. :
  364. LIFETIME_CONTROLLER (
  365. &Q931SyncCounter
  366. )
  367. /*++
  368. Routine Description:
  369. Constructor for CALL_BRIDGE class
  370. Arguments:
  371. RedirectInformation - original source/destination before
  372. the NAT redirect was satisfied
  373. Return Values:
  374. None
  375. Notes:
  376. Passes pointer to associated global sync counter to the base class
  377. --*/
  378. {
  379. SourceInterfaceAddress = 0;
  380. DestinationInterfaceAddress = 0;
  381. State = STATE_NONE;
  382. DestinationAddress.sin_family = AF_INET;
  383. DestinationAddress.sin_addr.s_addr = RedirectInformation -> DestinationAddress;
  384. DestinationAddress.sin_port = RedirectInformation -> DestinationPort;
  385. SourceAddress.sin_family = AF_INET;
  386. SourceAddress.sin_addr.s_addr = RedirectInformation -> SourceAddress;
  387. SourceAddress.sin_port = RedirectInformation -> SourcePort;
  388. DebugF (_T("Q931: 0x%x created.\n"), this);
  389. } // CALL_BRIDGE::CALL_BRIDGE
  390. CALL_BRIDGE::~CALL_BRIDGE (
  391. void)
  392. /*++
  393. Routine Description:
  394. Destructor for CALL_BRIDGE class
  395. Arguments:
  396. None
  397. Return Values:
  398. None
  399. Notes:
  400. --*/
  401. {
  402. DebugF (_T("Q931: 0x%x destroyed.\n"), this);
  403. } // CALL_BRIDGE::~CALL_BRIDGE
  404. void
  405. Q931_INFO::IncrementLifetimeCounter (
  406. void
  407. )
  408. /*++
  409. Routine Description:
  410. Increments reference counter to the parent
  411. CALL_BRIDGE on its own behalf
  412. Arguments:
  413. None
  414. Return Values:
  415. None
  416. Notes:
  417. --*/
  418. {
  419. GetCallBridge().AddRef();
  420. } // Q931_INFO::IncrementLifetimeCounter
  421. void
  422. Q931_INFO::DecrementLifetimeCounter (
  423. void
  424. )
  425. /*++
  426. Routine Description:
  427. Decrements reference counter to the parent
  428. CALL_BRIDGE on its own behalf
  429. Arguments:
  430. None
  431. Return Values:
  432. None
  433. Notes:
  434. --*/
  435. {
  436. GetCallBridge().Release ();
  437. } // Q931_INFO::DecrementLifetimeCounter
  438. HRESULT
  439. Q931_INFO::SendCallback (
  440. IN HRESULT CallbackResult
  441. )
  442. /*++
  443. Routine Description:
  444. Handle completion of the send operation
  445. Arguments:
  446. CallbackResult -- status of the async operation invoked
  447. Return Values:
  448. S_OK if the parent call-bridge was already terminated;
  449. passes back the value of CallbackResult otherwise
  450. Notes:
  451. Virtual
  452. --*/
  453. {
  454. CALL_BRIDGE *pCallBridge = &GetCallBridge();
  455. HRESULT Result = S_OK;
  456. pCallBridge->Lock();
  457. if (!pCallBridge -> IsTerminated ()) {
  458. if (FAILED(CallbackResult))
  459. {
  460. pCallBridge->Terminate ();
  461. _ASSERTE(pCallBridge->IsTerminated());
  462. Result = CallbackResult;
  463. }
  464. } else {
  465. // This is here to take care of closing the socket
  466. // when callbridge sends ReleaseComplete PDU during
  467. // termination path.
  468. GetSocketInfo ().Clear (TRUE);
  469. }
  470. pCallBridge->Unlock();
  471. return Result;
  472. } // Q931_INFO::SendCallback
  473. HRESULT
  474. Q931_INFO::ReceiveCallback(
  475. IN HRESULT CallbackResult,
  476. IN BYTE *Buffer,
  477. IN DWORD BufferLength
  478. )
  479. /*++
  480. Routine Description:
  481. Handles completion of a receive operation
  482. Arguments:
  483. CallbackResult -- status of the async operation
  484. Buffer --
  485. BufferLength --
  486. Return Values:
  487. Result of decoding of the received data, if the receive was successful
  488. Otherwise just returns the status code passed.
  489. Notes:
  490. 1. Virtual
  491. 2. This function is responsible for freeing Buffer
  492. --*/
  493. {
  494. Q931_MESSAGE *pQ931msg = NULL;
  495. H323_UserInformation *pDecodedH323UserInfo = NULL;
  496. CALL_BRIDGE *pCallBridge = &GetCallBridge();
  497. pCallBridge->Lock();
  498. if (!pCallBridge -> IsTerminated ()) {
  499. if (SUCCEEDED(CallbackResult))
  500. {
  501. CallbackResult = DecodeQ931PDU(Buffer, BufferLength,
  502. &pQ931msg, &pDecodedH323UserInfo);
  503. if (SUCCEEDED(CallbackResult))
  504. {
  505. // Process the PDU
  506. ReceiveCallback(pQ931msg, pDecodedH323UserInfo);
  507. FreeQ931PDU(pQ931msg, pDecodedH323UserInfo);
  508. }
  509. else
  510. {
  511. // An error occured. Terminate the CALL_BRIDGE
  512. EM_FREE (Buffer);
  513. DebugF( _T("Q931: 0x%x terminating on receive callback. Error=0x%x."),
  514. pCallBridge,
  515. CallbackResult);
  516. pCallBridge->Terminate ();
  517. }
  518. }
  519. else
  520. {
  521. // An error occured. Terminate the CALL_BRIDGE
  522. EM_FREE (Buffer);
  523. DebugF( _T("Q931: 0x%x terminating on receive callback. Error=0x%x."),
  524. pCallBridge,
  525. CallbackResult);
  526. pCallBridge->Terminate ();
  527. }
  528. } else {
  529. EM_FREE (Buffer);
  530. }
  531. pCallBridge->Unlock();
  532. return CallbackResult;
  533. } // Q931_INFO::ReceiveCallback
  534. /*++
  535. --*/
  536. HRESULT
  537. Q931_INFO::QueueSend (
  538. IN Q931_MESSAGE *pQ931Message,
  539. IN H323_UserInformation *pH323UserInfo
  540. )
  541. /*++
  542. Routine Description:
  543. Encodes the Q.931 PDU into a buffer and sends it
  544. on the socket. Once the send completes the buffer is freed
  545. Arguments:
  546. pQ931Message --
  547. pH323UserInfo --
  548. Return Values:
  549. Notes:
  550. This function does NOT free the Q.931 PDU.
  551. --*/
  552. {
  553. BYTE *pBuf = NULL;
  554. DWORD BufLen = 0;
  555. // This should be the only place where CRVs are replaced.
  556. // replace the CRV for all calls (incoming and outgoing)
  557. pQ931Message->CallReferenceValue = m_CallRefVal;
  558. // This function also encodes the TPKT header into the buffer.
  559. HRESULT HResult = EncodeQ931PDU(
  560. pQ931Message,
  561. pH323UserInfo, // decoded ASN.1 part - could be NULL
  562. &pBuf,
  563. &BufLen
  564. );
  565. if (FAILED(HResult))
  566. {
  567. DebugF( _T("Q931: 0x%x EncodeQ931PDU() failed. Error=0x%x\n"),
  568. &GetCallBridge (),
  569. HResult);
  570. return HResult;
  571. }
  572. // call the event manager to make the async send call
  573. // the event mgr will free the buffer.
  574. HResult = EventMgrIssueSend (m_SocketInfo.Socket, *this, pBuf, BufLen);
  575. if (FAILED(HResult))
  576. {
  577. DebugF(_T("Q931: 0x%x EventMgrIssueSend failed: Error=0x%x\n"),
  578. &GetCallBridge (),
  579. HResult);
  580. }
  581. return HResult;
  582. } // Q931_INFO::QueueSend
  583. HRESULT
  584. Q931_INFO::QueueReceive (
  585. void
  586. )
  587. /*++
  588. Routine Description:
  589. Issues an asynchronous receive
  590. Arguments:
  591. None
  592. Return Values:
  593. Passes through the result of calling another function
  594. Notes:
  595. --*/
  596. {
  597. // call the event manager to make the async receive call
  598. HRESULT HResult;
  599. HResult = EventMgrIssueRecv (m_SocketInfo.Socket, *this);
  600. if (FAILED(HResult))
  601. {
  602. DebugF (_T("Q931: 0x%x Async Receive call failed.\n"), &GetCallBridge ());
  603. }
  604. return HResult;
  605. } // Q931_INFO::QueueReceive
  606. HRESULT
  607. Q931_INFO::SendReleaseCompletePdu (
  608. void
  609. )
  610. /*++
  611. Routine Description:
  612. Encodes and sends Q.931 Release Complete PDU
  613. Arguments:
  614. None
  615. Return Values:
  616. Passes through the result of calling another function
  617. Notes:
  618. --*/
  619. {
  620. Q931_MESSAGE ReleaseCompletePdu;
  621. H323_UserInformation ReleaseCompleteH323UserInfo;
  622. HRESULT HResult;
  623. HResult = Q931EncodeReleaseCompleteMessage(
  624. m_CallRefVal,
  625. &ReleaseCompletePdu,
  626. &ReleaseCompleteH323UserInfo
  627. );
  628. if (FAILED(HResult))
  629. {
  630. DebugF(_T("Q931: 0x%x cCould not create Release Complete PDU.\n"), &GetCallBridge ());
  631. return HResult;
  632. }
  633. HResult = QueueSend(
  634. &ReleaseCompletePdu,
  635. &ReleaseCompleteH323UserInfo
  636. );
  637. if (FAILED(HResult))
  638. {
  639. DebugF(_T("Q931: 0x%x failed to send ReleaseComplete PDU. Error=0x%x\n"),
  640. &GetCallBridge (),
  641. HResult);
  642. }
  643. return HResult;
  644. } // Q931_INFO::SendReleaseCompletePdu
  645. HRESULT
  646. Q931_INFO::CreateTimer (
  647. IN DWORD TimeoutValue
  648. )
  649. /*++
  650. Routine Description:
  651. Creates a Q.931 timer
  652. Arguments:
  653. TimeoutValue - self-explanatory
  654. Return Values:
  655. S_OK if timer was created successfully
  656. Otherwise, passes back error code from another method
  657. Notes:
  658. --*/
  659. {
  660. DWORD RetCode;
  661. RetCode = TimprocCreateTimer(TimeoutValue);
  662. return HRESULT_FROM_WIN32(RetCode);
  663. } // Q931_INFO::CreateTimer
  664. void
  665. Q931_INFO::TimerCallback (
  666. void
  667. )
  668. /*++
  669. Routine Description:
  670. Called when Q.931 timer expires
  671. Arguments:
  672. None
  673. Return Values:
  674. None
  675. Notes:
  676. Virtual
  677. --*/
  678. {
  679. // We keep a copy of the CALL_BRIDGE to be able to unlock it.
  680. // DeleteAndRemoveSelf() will delete the LOGICAL_CHANNEL and
  681. // so we can not access the CALL_BRIDGE through the member variable
  682. // after the CALL_BRIDGE is deleted.
  683. CALL_BRIDGE *pCallBridge = &GetCallBridge();
  684. pCallBridge->Lock();
  685. // Clear the timer - Note that Termninate () will try to
  686. // cancel all the timers in this CALL_BRIDGE
  687. TimprocCancelTimer();
  688. DebugF (_T("Q931: 0x%x cancelled timer.\n"),
  689. &GetCallBridge ());
  690. // Don't do anything if the CALL_BRIDGE is already terminated.
  691. if (!pCallBridge->IsTerminated())
  692. {
  693. // initiate shutdown
  694. pCallBridge->Terminate ();
  695. _ASSERTE(pCallBridge->IsTerminated());
  696. }
  697. pCallBridge -> Unlock ();
  698. pCallBridge -> Release ();
  699. } // Q931_INFO::TimerCallback (