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.

1556 lines
45 KiB

  1. /*---------------------------------------------------
  2. Copyright (c) 1998, Microsoft Corporation
  3. File: h245.cpp
  4. Purpose:
  5. Contains the H245 related function definitions.
  6. These include the base classes -
  7. LOGICAL_CHANNEL
  8. H245_INFO
  9. History:
  10. 1. written as part of cbridge.cpp
  11. Byrisetty Rajeev (rajeevb) 12-Jun-1998
  12. 2. moved to a separate file on 21-Aug-1998. This removes
  13. atl, rend, tapi headers and decreases file size
  14. ---------------------------------------------------*/
  15. #include "stdafx.h"
  16. #include "portmgmt.h"
  17. #include "timerval.h"
  18. #include "cbridge.h"
  19. #include "main.h"
  20. #if DBG
  21. #define NUM_H245_MEDIA_TYPES 8
  22. TCHAR* h245MediaTypes[NUM_H245_MEDIA_TYPES + 1] = {
  23. _T("Unknown"),
  24. _T("Non-standard"),
  25. _T("Null-data"),
  26. _T("Video"),
  27. _T("Audio"),
  28. _T("Data"),
  29. _T("Encrypted"),
  30. _T("H235 control"),
  31. _T("H235 media")
  32. };
  33. #define NUM_H245_REQUEST_PDU_TYPES 13
  34. TCHAR* h245RequestTypes[NUM_H245_REQUEST_PDU_TYPES + 1] = {
  35. _T("Unknown"),
  36. _T("Non-standard"),
  37. _T("Master-Slave Determination"),
  38. _T("Terminal Capability Set"),
  39. _T("Open Logical Channel"),
  40. _T("Close Logical Channel"),
  41. _T("Request Channel Close"),
  42. _T("Multiplex Entry Send"),
  43. _T("Request Multiplex Entry"),
  44. _T("Request Mode"),
  45. _T("Round Trip Delay Request"),
  46. _T("Maintenance Loop Request"),
  47. _T("Communication Mode Request"),
  48. _T("Conference Request")
  49. };
  50. #define NUM_H245_RESPONSE_PDU_TYPES 21
  51. TCHAR* h245ResponseTypes[NUM_H245_RESPONSE_PDU_TYPES + 1] = {
  52. _T("Unknown"),
  53. _T("Non-Standard Message"),
  54. _T("Master-Slave Determination Ack"),
  55. _T("Master-Slave Determination Reject"),
  56. _T("Terminal Capability Set Ack"),
  57. _T("Terminal Capability Set Reject"),
  58. _T("Open Logical Channel Ack"),
  59. _T("Open Logical Channel Reject"),
  60. _T("Close Logical Channel Ack"),
  61. _T("Request Channel Close Ack"),
  62. _T("Request Channel Close Reject"),
  63. _T("Multiplex Entry Send Ack"),
  64. _T("Multiplex Entry Send Reject"),
  65. _T("Request Multiplex Entry Ack"),
  66. _T("Request Multiplex Entry Reject"),
  67. _T("Request Mode Ack"),
  68. _T("Request Mode Reject"),
  69. _T("Round Trip Delay Response"),
  70. _T("Maintenance Loop Ack"),
  71. _T("Maintenance Loop Reject"),
  72. _T("Communication Mode Response"),
  73. _T("Conference Response")
  74. };
  75. #endif // DBG
  76. inline HRESULT
  77. H245_INFO::QueueReceive()
  78. {
  79. HRESULT HResult = EventMgrIssueRecv (m_SocketInfo.Socket, *this);
  80. if (FAILED(HResult))
  81. {
  82. DebugF (_T("H245_INFO::QueueReceive: Async Receive call failed.\n"));
  83. }
  84. return HResult;
  85. }
  86. inline HRESULT
  87. H245_INFO::QueueSend(
  88. IN MultimediaSystemControlMessage *pH245pdu
  89. )
  90. {
  91. BYTE *pBuf = NULL;
  92. DWORD BufLen = 0;
  93. // This function encodes the TPKT header also into the buffer
  94. HRESULT HResult = EncodeH245PDU(*pH245pdu, // decoded ASN.1 part
  95. &pBuf,
  96. &BufLen);
  97. if (FAILED(HResult))
  98. {
  99. DebugF(_T("EncodeH245PDU() failed: %x\n"), HResult);
  100. return HResult;
  101. }
  102. // call the event manager to make the async send call
  103. // the event mgr will free the buffer.
  104. HResult = EventMgrIssueSend (m_SocketInfo.Socket, *this, pBuf, BufLen);
  105. if (FAILED(HResult))
  106. {
  107. DebugF(_T("H245_INFO::QueueSend(), AsyncSend() failed: 0x%x\n"),
  108. HResult);
  109. }
  110. // Issuing the send succeeded.
  111. return HResult;
  112. }
  113. /* virtual */ HRESULT
  114. H245_INFO::SendCallback(
  115. IN HRESULT CallbackHResult
  116. )
  117. {
  118. CALL_BRIDGE *pCallBridge = &GetCallBridge();
  119. HRESULT Result = S_OK;
  120. pCallBridge->Lock();
  121. if (!pCallBridge -> IsTerminated ()) {
  122. if (FAILED(CallbackHResult))
  123. {
  124. pCallBridge->Terminate ();
  125. _ASSERTE(pCallBridge->IsTerminated());
  126. Result = CallbackHResult;
  127. }
  128. } else {
  129. // This is here to take care of closing the socket
  130. // when callbridge sends EndSession PDU during
  131. // termination path.
  132. GetSocketInfo ().Clear (TRUE);
  133. }
  134. pCallBridge->Unlock();
  135. return Result;
  136. }
  137. // This clearly assumes that the H.245 listen address will
  138. // always be within the Connect PDU and the dest side will be the one
  139. // which will be calling connect()
  140. inline HRESULT
  141. DEST_H245_INFO::ConnectToCallee(
  142. )
  143. {
  144. // we must be in H245_STATE_CON_INFO
  145. _ASSERTE(H245_STATE_CON_INFO == m_H245State);
  146. // we saved the callee's h245 address/port in the call to SetCalleeInfo
  147. _ASSERTE(ntohl (m_CalleeAddress.sin_addr.s_addr));
  148. _ASSERTE(ntohs (m_CalleeAddress.sin_port));
  149. // try to connect to this address/port
  150. // and save the address/port
  151. HRESULT HResult = m_SocketInfo.Connect (&m_CalleeAddress);
  152. if (FAILED(HResult))
  153. {
  154. DebugF (_T("H245: 0x%x failed to connect to callee %08X:%04X.\n"),
  155. &GetCallBridge (),
  156. SOCKADDR_IN_PRINTF (&m_CalleeAddress));
  157. return HResult;
  158. }
  159. //_ASSERTE(S_FALSE != HResult);
  160. // queue receive
  161. HResult = QueueReceive();
  162. if (FAILED(HResult))
  163. {
  164. DebugF (_T("H245: 0x%x failed to queue receive.\n"),
  165. &GetCallBridge ());
  166. DumpError (HResult);
  167. return HResult;
  168. }
  169. //_ASSERTE(S_FALSE != HResult);
  170. // transition to state H245_STATE_CON_ESTD
  171. m_H245State = H245_STATE_CON_ESTD;
  172. return HResult;
  173. }
  174. HRESULT SOURCE_H245_INFO::ListenForCaller (
  175. IN SOCKADDR_IN * ListenAddress)
  176. {
  177. // queues an overlapped accept and returns the
  178. // port on which its listening for incoming connections
  179. // it uses the same local ip address as the source q931 connection
  180. SOCKET ListenSocket;
  181. HRESULT Result;
  182. WORD Port = 0; // in HOST order
  183. SOCKADDR_IN TrivialRedirectSourceAddress = {0};
  184. SOCKADDR_IN TrivialRedirectDestAddress = {0};
  185. ULONG SourceAdapterIndex;
  186. ULONG Status;
  187. ListenSocket = INVALID_SOCKET;
  188. Result = EventMgrIssueAccept(
  189. ntohl (ListenAddress -> sin_addr.s_addr),
  190. *this,
  191. Port, // out param
  192. ListenSocket);
  193. ListenAddress -> sin_port = htons (Port);
  194. if (FAILED (Result)) {
  195. DebugF (_T("H245: 0x%x failed to issue accept from caller.\n"), &GetCallBridge ());
  196. DumpError (Result);
  197. return Result;
  198. }
  199. //_ASSERTE(S_FALSE != HResult);
  200. // save the listen socket, address and port in our socket info
  201. m_SocketInfo.SetListenInfo (ListenSocket, ListenAddress);
  202. // Open trivial source-side NAT mapping
  203. //
  204. // The purpose of this mapping is to puncture the firewall for H.245
  205. // session if the firewall happened to be activated.
  206. // Note that this assumes that the caller sends both Q.931 and H.245
  207. // traffic from the same IP address.
  208. SourceAdapterIndex = ::NhMapAddressToAdapter (htonl (GetCallBridge().GetSourceInterfaceAddress()));
  209. if(SourceAdapterIndex == (ULONG)-1)
  210. {
  211. DebugF (_T("H245: 0x%x failed to map address %08X to adapter index.\n"),
  212. &GetCallBridge (),
  213. GetCallBridge().GetSourceInterfaceAddress());
  214. return E_FAIL;
  215. }
  216. #if PARTIAL_TRIVIAL_REDIRECTS_ENABLED // enable this when it would be possible to set up a trivial redirect
  217. // with only source port (new and old) unspecified.
  218. GetCallBridge().GetSourceAddress(&TrivialRedirectSourceAddress);
  219. #endif // PARTIAL_TRIVIAL_REDIRECTS_ENABLED
  220. TrivialRedirectDestAddress.sin_addr.s_addr = ListenAddress->sin_addr.s_addr;
  221. TrivialRedirectDestAddress.sin_port = ListenAddress->sin_port;
  222. Status = m_SocketInfo.CreateTrivialNatRedirect(
  223. &TrivialRedirectDestAddress,
  224. &TrivialRedirectSourceAddress,
  225. SourceAdapterIndex);
  226. if (Status != S_OK) {
  227. return E_FAIL;
  228. }
  229. // transition state to H245_STATE_CON_LISTEN
  230. m_H245State = H245_STATE_CON_LISTEN;
  231. return S_OK;
  232. }
  233. // virtual
  234. HRESULT SOURCE_H245_INFO::AcceptCallback (
  235. IN DWORD Status,
  236. IN SOCKET Socket,
  237. IN SOCKADDR_IN * LocalAddress,
  238. IN SOCKADDR_IN * RemoteAddress)
  239. {
  240. HRESULT HResult = Status;
  241. CALL_BRIDGE *pCallBridge = &GetCallBridge();
  242. ///////////////////////////////
  243. //// LOCK the CALL_BRIDGE
  244. ///////////////////////////////
  245. pCallBridge->Lock();
  246. if (!pCallBridge -> IsTerminated ()) {
  247. do {
  248. if (FAILED (HResult))
  249. {
  250. // An error occured. Terminate the CALL_BRIDGE
  251. DebugF (_T("H245: 0x%x accept failed, terminating.\n"), &GetCallBridge ());
  252. DumpError (HResult);
  253. break;
  254. }
  255. // we must be in H245_STATE_CON_LISTEN state
  256. _ASSERTE(H245_STATE_CON_LISTEN == m_H245State);
  257. // call the dest instance to establish a connection with the callee
  258. HResult = GetDestH245Info().ConnectToCallee();
  259. if (FAILED(HResult))
  260. break;
  261. //_ASSERTE(S_FALSE != HResult);
  262. // close the listen socket, don't cancel trivial NAT redirect
  263. m_SocketInfo.Clear(FALSE);
  264. m_SocketInfo.Init(Socket, LocalAddress, RemoteAddress);
  265. // queue receive
  266. HResult = QueueReceive();
  267. if (FAILED(HResult))
  268. break;
  269. //_ASSERTE(S_FALSE != HResult);
  270. // transition state to H245_STATE_CON_ESTD
  271. m_H245State = H245_STATE_CON_ESTD;
  272. } while (FALSE);
  273. if (FAILED (HResult))
  274. {
  275. // initiate shutdown
  276. pCallBridge->Terminate ();
  277. _ASSERTE(pCallBridge->IsTerminated());
  278. }
  279. }
  280. ///////////////////////////////
  281. //// UNLOCK the CALL_BRIDGE
  282. ///////////////////////////////
  283. pCallBridge->Unlock();
  284. return HResult;
  285. }
  286. /*++
  287. Routine Description:
  288. This function is responsible for freeing pBuf (if it is not stored).
  289. Arguments:
  290. Return Values:
  291. --*/
  292. //virtual
  293. HRESULT
  294. H245_INFO::ReceiveCallback(
  295. IN HRESULT CallbackHResult,
  296. IN BYTE *pBuf,
  297. IN DWORD BufLen
  298. )
  299. {
  300. MultimediaSystemControlMessage *pDecodedH245pdu = NULL;
  301. CALL_BRIDGE *pCallBridge = &GetCallBridge();
  302. pCallBridge->Lock();
  303. if (!pCallBridge -> IsTerminated ()) {
  304. if (SUCCEEDED(CallbackHResult))
  305. {
  306. CallbackHResult = DecodeH245PDU(pBuf, BufLen, &pDecodedH245pdu);
  307. if (SUCCEEDED(CallbackHResult))
  308. {
  309. // Process the PDU
  310. CallbackHResult = ReceiveCallback(pDecodedH245pdu);
  311. FreeH245PDU(pDecodedH245pdu);
  312. }
  313. else
  314. {
  315. DebugF (_T("H245: 0x%x error 0x%x on decode.\n"),
  316. &GetCallBridge (),
  317. CallbackHResult);
  318. pCallBridge->Terminate ();
  319. }
  320. }
  321. else
  322. {
  323. // An error occured. Terminate the CALL_BRIDGE
  324. DebugF (_T("H245: 0x%x error 0x%x on receive callback.\n"),
  325. &GetCallBridge (),
  326. CallbackHResult);
  327. pCallBridge->Terminate ();
  328. }
  329. }
  330. pCallBridge -> Unlock();
  331. EM_FREE(pBuf);
  332. return CallbackHResult;
  333. }
  334. /* virtual */ HRESULT
  335. H245_INFO::ReceiveCallback(
  336. IN MultimediaSystemControlMessage *pH245pdu
  337. )
  338. /*++
  339. Routine Description:
  340. Only Request PDUs are handled by this H245_INFO instance.
  341. All the other PDUs are just passed on for processing to the
  342. other instance.
  343. CODEWORK: How should we handle endSessionCommand PDUs ?
  344. Arguments:
  345. Return Values:
  346. S_OK on success.
  347. E_INVALIDARG if the PDU is invalid.
  348. --*/
  349. {
  350. HRESULT HResult;
  351. // check to see if we must destroy self
  352. // CHECK_TERMINATION;
  353. // we must have a valid decoded PDU
  354. _ASSERTE(NULL != pH245pdu);
  355. // we must be in H245_STATE_CON_ESTD state
  356. _ASSERTE(H245_STATE_CON_ESTD == m_H245State);
  357. // check message type
  358. if (MultimediaSystemControlMessage_request_chosen ==
  359. pH245pdu->choice)
  360. {
  361. // we only handle requests in the H245 instance which
  362. // actually receives the PDU
  363. HResult = HandleRequestMessage(pH245pdu);
  364. }
  365. else
  366. {
  367. // we don't process these here, pass them on to the other
  368. // H245 instance.
  369. HResult = GetOtherH245Info().ProcessMessage(pH245pdu);
  370. }
  371. // CODEWORK: Which errors should result in just dropped PDUs
  372. // and which ones should result in shutting down the whole call ???
  373. // if there is an error
  374. if (FAILED(HResult) && HResult != E_INVALIDARG)
  375. {
  376. goto shutdown;
  377. }
  378. // CODEWORK: If HResult is E_INVALIDARG, this means that the PDU
  379. // should be dropped. We need to let the caller know about this
  380. // and send him a closeLC message or some such.
  381. // Probably an OLC PDU should get an OLCReject etc.
  382. // we must queue a receive irrespective of whether or not the
  383. // previous message was dropped.
  384. // queue an async receive
  385. HResult = QueueReceive();
  386. if (FAILED(HResult))
  387. {
  388. goto shutdown;
  389. }
  390. return HResult;
  391. shutdown:
  392. // initiate shutdown
  393. GetCallBridge().Terminate ();
  394. return HResult;
  395. }
  396. ///////////////////////////////////////////////////////////////////////////////
  397. // //
  398. // Routines for processing H.245 PDUs //
  399. // //
  400. ///////////////////////////////////////////////////////////////////////////////
  401. HRESULT
  402. H245_INFO::HandleRequestMessage(
  403. IN MultimediaSystemControlMessage *pH245pdu
  404. )
  405. /*++
  406. Routine Description:
  407. Only the OLC and CLC PDUs are handled here. All the rest are
  408. just passed on to the other H245_INFO instance for processing.
  409. Arguments:
  410. Return Values:
  411. S_OK on success.
  412. E_INVALIDARG if the PDU is invalid.
  413. --*/
  414. {
  415. BOOL IsDestH245Info = (&GetCallBridge().GetDestH323State().GetH245Info() == this);
  416. LogicalChannelNumber LCN;
  417. // it must be a request message
  418. _ASSERTE(MultimediaSystemControlMessage_request_chosen ==
  419. pH245pdu->choice);
  420. // we must be in connected state
  421. _ASSERTE(H245_STATE_CON_ESTD == m_H245State);
  422. HRESULT HResult = E_FAIL;
  423. // check the PDU type
  424. switch(pH245pdu->u.request.choice)
  425. {
  426. case openLogicalChannel_chosen:
  427. {
  428. LCN = pH245pdu->u.request.u.openLogicalChannel.forwardLogicalChannelNumber;
  429. #if DBG
  430. DebugF (_T("H245: 0x%x calle%c sent 'Open Logical Channel' (%s, LCN - %d).\n"),
  431. &GetCallBridge(), IsDestH245Info ? 'e' : 'r',
  432. h245MediaTypes[pH245pdu->u.request.u.openLogicalChannel.forwardLogicalChannelParameters.dataType.choice],
  433. LCN);
  434. #endif
  435. HResult = HandleOpenLogicalChannelPDU(pH245pdu);
  436. }
  437. break;
  438. case closeLogicalChannel_chosen:
  439. {
  440. LCN = pH245pdu->u.request.u.closeLogicalChannel.forwardLogicalChannelNumber;
  441. DebugF (_T("H245: 0x%x calle%c sent 'Close Logical Channel' (LCN - %d).\n"),
  442. &GetCallBridge(), IsDestH245Info ? 'e' : 'r', LCN);
  443. HResult = HandleCloseLogicalChannelPDU(pH245pdu);
  444. }
  445. break;
  446. default:
  447. {
  448. // pass it on to the other H245 instance
  449. #if DBG
  450. DebugF (_T("H245: 0x%x calle%c sent '%s'. Forwarding without processing.\n"),
  451. &GetCallBridge(), IsDestH245Info ? 'e' : 'r',
  452. h245RequestTypes[pH245pdu->u.request.choice]);
  453. #endif
  454. HResult = GetOtherH245Info().ProcessMessage(
  455. pH245pdu);
  456. }
  457. break;
  458. };
  459. return HResult;
  460. }
  461. HRESULT
  462. H245_INFO::ProcessMessage(
  463. IN MultimediaSystemControlMessage *pH245pdu
  464. )
  465. /*++
  466. Routine Description:
  467. Only Response PDUs need processing. All other PDUs
  468. are simply sent out.
  469. Arguments:
  470. Return Values:
  471. S_OK on success.
  472. E_INVALIDARG if the PDU is invalid.
  473. --*/
  474. {
  475. BOOL IsDestH245Info = (&GetCallBridge().GetDestH323State().GetH245Info() == this);
  476. // we must be in H245_STATE_CON_ESTD state
  477. _ASSERTE(H245_STATE_CON_ESTD == m_H245State);
  478. // all messages are passed on
  479. // we only do special processing of response messages here
  480. if (MultimediaSystemControlMessage_response_chosen ==
  481. pH245pdu->choice)
  482. {
  483. HRESULT HResult = E_FAIL;
  484. // we only process requests in the H245 instance which
  485. // actually receives the PDU
  486. HResult = ProcessResponseMessage(pH245pdu);
  487. // XXX This if is redundant
  488. // if we are dropping the PDU, no further processing is required
  489. if (HResult == E_INVALIDARG)
  490. {
  491. DebugF(_T("DEST_Q931_INFO::ProcessMessage(&%x), ")
  492. _T("dropping response message, returning E_INVALIDARG\n"),
  493. pH245pdu);
  494. return E_INVALIDARG;
  495. }
  496. else if (FAILED(HResult))
  497. {
  498. DebugF( _T("DEST_Q931_INFO::ProcessMessage(&%x), ")
  499. _T("unable to process response message, returning 0x%x\n"),
  500. pH245pdu, HResult);
  501. return HResult;
  502. }
  503. }
  504. else if (MultimediaSystemControlMessage_command_chosen ==
  505. pH245pdu->choice)
  506. {
  507. DebugF (_T("H245: 0x%x calle%c sent 'Command Message' (Type %d). Forwarding without processing.\n"),
  508. &GetCallBridge(), IsDestH245Info ? 'r' : 'e',
  509. pH245pdu -> u.command.choice);
  510. }
  511. else if (indication_chosen == pH245pdu->choice)
  512. {
  513. DebugF (_T("H245: 0x%x calle%c sent 'Indication Message' (Type %d). Forwarding without processing.\n"),
  514. &GetCallBridge(), IsDestH245Info ? 'r' : 'e',
  515. pH245pdu -> u.indication.choice);
  516. }
  517. // queue async send for the PDU
  518. HRESULT HResult = E_FAIL;
  519. HResult = QueueSend(pH245pdu);
  520. if (HResult != S_OK) {
  521. DebugF( _T("DEST_Q931_INFO::ProcessMessage(&%x) QueueSend failed, returning %x\n"),
  522. pH245pdu, HResult);
  523. return HResult;
  524. }
  525. return S_OK;
  526. }
  527. //
  528. // we process response messages here
  529. // since the logical channel info for these messages resides in this H245,
  530. // the other H245 instance doesn't process them
  531. //
  532. HRESULT
  533. H245_INFO::ProcessResponseMessage(
  534. IN MultimediaSystemControlMessage *pH245pdu
  535. )
  536. {
  537. BOOL IsDestH245Info = (&GetCallBridge().GetDestH323State().GetH245Info() == this);
  538. // it must be a response message
  539. _ASSERTE(MultimediaSystemControlMessage_response_chosen == \
  540. pH245pdu->choice);
  541. // NOTE: LogicalChannelNumber is USHORT, but we can treat it as an
  542. // unsigned WORD
  543. _ASSERTE(sizeof(LogicalChannelNumber) == sizeof(WORD));
  544. // obtain the logical channel number
  545. WORD LogChanNum = 0;
  546. switch(pH245pdu->u.response.choice)
  547. {
  548. case openLogicalChannelAck_chosen:
  549. {
  550. OpenLogicalChannelAck &OlcAckPDU =
  551. pH245pdu->u.response.u.openLogicalChannelAck;
  552. LogChanNum = OlcAckPDU.forwardLogicalChannelNumber;
  553. DebugF (_T("H245: 0x%x calle%c sent 'Open Logical Channel Ack' (LCN - %d).\n"),
  554. &GetCallBridge (), IsDestH245Info ? 'r' : 'e', LogChanNum);
  555. }
  556. break;
  557. case openLogicalChannelReject_chosen:
  558. {
  559. OpenLogicalChannelReject &OlcRejectPDU =
  560. pH245pdu->u.response.u.openLogicalChannelReject;
  561. LogChanNum = OlcRejectPDU.forwardLogicalChannelNumber;
  562. DebugF (_T("H245: 0x%x calle%c sent 'Open Logical Channel Reject' (LCN - %d).\n"),
  563. &GetCallBridge (), IsDestH245Info ? 'r' : 'e', LogChanNum);
  564. }
  565. break;
  566. #if 0 // 0 ******* Region Commented Out Begins *******
  567. case closeLogicalChannelAck_chosen:
  568. {
  569. CloseLogicalChannelAck &ClcAckPDU =
  570. pH245pdu->u.response.u.closeLogicalChannelAck;
  571. LogChanNum = ClcAckPDU.forwardLogicalChannelNumber;
  572. }
  573. break;
  574. #endif // 0 ******* Region Commented Out Ends *******
  575. // Let the CLCAck messages also go right through
  576. default:
  577. {
  578. #if DBG
  579. // pass it on to the other H245 instance
  580. DebugF (_T("H245: 0x%x calle%c sent '%s'. Forwarding without processing.\n"),
  581. &GetCallBridge(), IsDestH245Info ? 'r' : 'e',
  582. h245ResponseTypes[pH245pdu->u.request.choice]);
  583. #endif
  584. return S_OK;
  585. }
  586. break;
  587. };
  588. // find the logical channel that must process this PDU,
  589. // if none found, drop the PDU
  590. LOGICAL_CHANNEL *pLogicalChannel =
  591. m_LogicalChannelArray.FindByLogicalChannelNum(LogChanNum);
  592. if (NULL == pLogicalChannel)
  593. {
  594. DebugF(_T("H245_INFO::ProcessResponseMessage(&%x), ")
  595. _T("no logical channel with the forward logical channel num = %d, ")
  596. _T("returning E_INVALIDARG\n"),
  597. pH245pdu, LogChanNum);
  598. return E_INVALIDARG;
  599. }
  600. // pass the PDU to the logical channel for processing
  601. HRESULT HResult = E_FAIL;
  602. switch(pH245pdu->u.response.choice)
  603. {
  604. case openLogicalChannelAck_chosen:
  605. {
  606. HResult = pLogicalChannel->ProcessOpenLogicalChannelAckPDU(
  607. pH245pdu
  608. );
  609. }
  610. break;
  611. case openLogicalChannelReject_chosen:
  612. {
  613. HResult = pLogicalChannel->ProcessOpenLogicalChannelRejectPDU(
  614. pH245pdu
  615. );
  616. }
  617. break;
  618. #if 0 // 0 ******* Region Commented Out Begins *******
  619. case closeLogicalChannelAck_chosen:
  620. {
  621. HResult = pLogicalChannel->ProcessCloseLogicalChannelAckPDU(
  622. pH245pdu
  623. );
  624. }
  625. break;
  626. #endif // 0 ******* Region Commented Out Ends *******
  627. default:
  628. {
  629. // do nothing, let it go to the client terminal
  630. DebugF(_T("H245_INFO::ProcessResponseMessage(&%x), we shouldn't have come here, returning E_UNEXPECTED\n"),
  631. pH245pdu);
  632. return E_UNEXPECTED;
  633. }
  634. break;
  635. };
  636. return HResult;
  637. }
  638. // Make Checks specific to RTP logical channels
  639. HRESULT
  640. H245_INFO::CheckOpenRtpLogicalChannelPDU(
  641. IN OpenLogicalChannel &OlcPDU,
  642. OUT SOCKADDR_IN * ReturnSourceAddress)
  643. /*++
  644. Routine Description:
  645. Arguments:
  646. Return Values:
  647. S_OK on success.
  648. E_INVALIDARG if the PDU is invalid.
  649. --*/
  650. {
  651. HRESULT HResult;
  652. // it must be unidirectional
  653. // bidirectional channels are only present for data channels
  654. if (OpenLogicalChannel_reverseLogicalChannelParameters_present &
  655. OlcPDU.bit_mask)
  656. {
  657. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  658. _T("has reverse logical channel parameters, ")
  659. _T("returning E_INVALIDARG\n")
  660. );
  661. return E_INVALIDARG;
  662. }
  663. // there shouldn't be a separate stack
  664. // we don't proxy data on the separate stack address/port
  665. if (OpenLogicalChannel_separateStack_present &
  666. OlcPDU.bit_mask)
  667. {
  668. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu)")
  669. _T("has a separate stack, returning E_INVALIDARG\n")
  670. );
  671. return E_INVALIDARG;
  672. }
  673. OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters &MultiplexParams =
  674. OlcPDU.forwardLogicalChannelParameters.multiplexParameters;
  675. H2250LogicalChannelParameters & H2250Params =
  676. MultiplexParams.u.h2250LogicalChannelParameters;
  677. // we must have a media control channel
  678. if (!(H2250LogicalChannelParameters_mediaControlChannel_present &
  679. H2250Params.bit_mask))
  680. {
  681. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  682. _T("doesn't have a mediaControlChannel, returning E_INVALIDARG\n")
  683. );
  684. return E_INVALIDARG;
  685. }
  686. // we only proxy best-effort UDP RTCP streams for now
  687. if ((H2250LogicalChannelParameters_mediaControlGuaranteedDelivery_present &
  688. H2250Params.bit_mask) &&
  689. (TRUE ==
  690. H2250Params.mediaControlGuaranteedDelivery))
  691. {
  692. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  693. _T("requires guaranteed media delivery for RTCP, returning E_INVALIDARG\n")
  694. );
  695. return E_INVALIDARG;
  696. }
  697. // the proposed RTCP address should be a unicast IPv4 address
  698. if ((unicastAddress_chosen != H2250Params.mediaControlChannel.choice) ||
  699. (UnicastAddress_iPAddress_chosen !=
  700. H2250Params.mediaControlChannel.u.unicastAddress.choice))
  701. {
  702. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  703. _T("RTCP address is not a unicast IPv4 address, ")
  704. _T("address type = %d, unicast address type = %d")
  705. _T("returning E_INVALIDARG\n"),
  706. H2250Params.mediaControlChannel.choice,
  707. H2250Params.mediaControlChannel.u.unicastAddress.choice);
  708. return E_INVALIDARG;
  709. }
  710. // we only proxy best-effort UDP data streams for now
  711. if ((H2250LogicalChannelParameters_mediaGuaranteedDelivery_present & H2250Params.bit_mask)
  712. && H2250Params.mediaGuaranteedDelivery) {
  713. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  714. _T("requires guaranteed media delivery for RTP, returning E_INVALIDARG\n")
  715. );
  716. return E_INVALIDARG;
  717. }
  718. // get in the source ipv4 address and RTCP port
  719. HResult = GetH245TransportInfo(
  720. H2250Params.mediaControlChannel,
  721. ReturnSourceAddress);
  722. return HResult;
  723. }
  724. // Make checks needed for the DataType member in forward and reverse
  725. // LogicalChannelParameters
  726. inline HRESULT
  727. CheckT120DataType(
  728. IN DataType &dataType
  729. )
  730. /*++
  731. Routine Description:
  732. Arguments:
  733. Return Values:
  734. S_OK on success.
  735. E_INVALIDARG if the PDU is invalid.
  736. --*/
  737. {
  738. // The reverse logical channel should also be of type data.
  739. if (dataType.choice != DataType_data_chosen)
  740. {
  741. return E_INVALIDARG;
  742. }
  743. // and of type T120 alone
  744. if (dataType.u.data.application.choice !=
  745. DataApplicationCapability_application_t120_chosen)
  746. return E_INVALIDARG;
  747. // Separate LAN stack is needed
  748. if (dataType.u.data.application.u.t120.choice != separateLANStack_chosen)
  749. return E_INVALIDARG;
  750. return S_OK;
  751. }
  752. // Make Checks specific to T.120 logical channels
  753. // If SeparateStack is not present the routine returns
  754. // INADDR_NONE for the T120ConnectToIPAddr
  755. HRESULT
  756. H245_INFO::CheckOpenT120LogicalChannelPDU(
  757. IN OpenLogicalChannel &OlcPDU,
  758. OUT DWORD &T120ConnectToIPAddr,
  759. OUT WORD &T120ConnectToPort
  760. )
  761. /*++
  762. Routine Description:
  763. Arguments:
  764. Return Values:
  765. S_OK on success.
  766. E_INVALIDARG if the PDU is invalid.
  767. --*/
  768. {
  769. HRESULT HResult;
  770. // This function is called only for data channels
  771. _ASSERTE(OlcPDU.forwardLogicalChannelParameters.dataType.choice ==
  772. DataType_data_chosen);
  773. // It must be bidirectional since this is a data channel.
  774. if (!(OpenLogicalChannel_reverseLogicalChannelParameters_present &
  775. OlcPDU.bit_mask))
  776. {
  777. DebugF( _T("H245_INFO::CheckT120OpenLogicalChannelPDU() ")
  778. _T("has no reverse logical channel parameters, ")
  779. _T("returning E_INVALIDARG\n"));
  780. return E_INVALIDARG;
  781. }
  782. // Ensure that for both forward and reverse LogicalchannelParmeters
  783. // the datatype is application t120 and separateLANStack
  784. HResult = CheckT120DataType(
  785. OlcPDU.forwardLogicalChannelParameters.dataType
  786. );
  787. if (HResult == E_INVALIDARG)
  788. {
  789. return E_INVALIDARG;
  790. }
  791. HResult = CheckT120DataType (OlcPDU.reverseLogicalChannelParameters.dataType);
  792. if (HResult == E_INVALIDARG)
  793. return E_INVALIDARG;
  794. // CODEWORK: What all other checks are needed here ?
  795. // CODEWORK: there could probably be other ways to send the address
  796. // Investigate all possibilities.
  797. // This means we have the address the T.120 endpoint is listening on
  798. if (OpenLogicalChannel_separateStack_present &
  799. OlcPDU.bit_mask)
  800. {
  801. return(GetT120ConnectToAddress(
  802. OlcPDU.separateStack,
  803. T120ConnectToIPAddr,
  804. T120ConnectToPort)
  805. );
  806. }
  807. // If the address is not present, return INADDR_NONE
  808. T120ConnectToIPAddr = INADDR_NONE;
  809. T120ConnectToPort = 0;
  810. // CODEWORK: Do we need a separate success code for this scenario
  811. // (in which the address is not present) ?
  812. return S_OK;
  813. }
  814. HRESULT
  815. H245_INFO::CheckOpenLogicalChannelPDU(
  816. IN MultimediaSystemControlMessage &H245pdu,
  817. OUT BYTE &SessionId,
  818. OUT MEDIA_TYPE &MediaType
  819. )
  820. /*++
  821. Routine Description:
  822. Arguments:
  823. Return Values:
  824. S_OK on success.
  825. E_INVALIDARG if the PDU is invalid.
  826. --*/
  827. {
  828. // it must be an open logical channel request message
  829. _ASSERTE (openLogicalChannel_chosen == H245pdu.u.request.choice);
  830. OpenLogicalChannel &OlcPDU = H245pdu.u.request.u.openLogicalChannel;
  831. // the forward logical channel number cannot be 0 as thats reserved
  832. // for the H245 channel
  833. if (0 == OlcPDU.forwardLogicalChannelNumber)
  834. {
  835. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  836. _T("has a forward logical channel number of 0, ")
  837. _T("returning E_INVALIDARG\n"));
  838. return E_INVALIDARG;
  839. }
  840. if (DataType_videoData_chosen ==
  841. OlcPDU.forwardLogicalChannelParameters.dataType.choice)
  842. {
  843. MediaType = MEDIA_TYPE_VIDEO;
  844. }
  845. else if (DataType_audioData_chosen ==
  846. OlcPDU.forwardLogicalChannelParameters.dataType.choice)
  847. {
  848. MediaType = MEDIA_TYPE_AUDIO;
  849. }
  850. else if (DataType_data_chosen ==
  851. OlcPDU.forwardLogicalChannelParameters.dataType.choice)
  852. {
  853. MediaType = MEDIA_TYPE_DATA;
  854. }
  855. else
  856. {
  857. // we only support audio, video and data types
  858. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  859. _T("has a non audio/video data type = %d, ")
  860. _T("returning E_INVALIDARG\n"),
  861. OlcPDU.forwardLogicalChannelParameters.dataType.choice);
  862. return E_INVALIDARG;
  863. }
  864. // it should have the h2250 parameters
  865. // TODO : check if this is a requirement
  866. // now THESE are some identifiers to be PROUD of! :/
  867. OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters &
  868. MultiplexParams = OlcPDU.forwardLogicalChannelParameters.multiplexParameters;
  869. if (MultiplexParams.choice !=
  870. OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters_chosen)
  871. {
  872. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  873. _T("has an unexpected multiplex param type (non h2250)= %d, ")
  874. _T("returning E_INVALIDARG\n"),
  875. MultiplexParams.choice);
  876. return E_INVALIDARG;
  877. }
  878. // there shouldn't be a mediaChannel as the ITU spec requires it not
  879. // to be present when the transport is unicast and we only support
  880. // unicast IPv4 addresses
  881. H2250LogicalChannelParameters &H2250Params =
  882. MultiplexParams.u.h2250LogicalChannelParameters;
  883. if (H2250LogicalChannelParameters_mediaChannel_present &
  884. H2250Params.bit_mask)
  885. {
  886. DebugF( _T("H245_INFO::CheckOpenLogicalChannelPDU(&H245pdu) ")
  887. _T("has a mediaChannel, returning E_INVALIDARG\n"));
  888. return E_INVALIDARG;
  889. }
  890. // get the session id
  891. // BYTE cast is intentional as the value should be in [0.255]
  892. _ASSERTE(H2250Params.sessionID <= 255);
  893. SessionId = (BYTE)H2250Params.sessionID;
  894. return S_OK;
  895. }
  896. HRESULT
  897. H245_INFO::CreateRtpLogicalChannel(
  898. IN OpenLogicalChannel &OlcPDU,
  899. IN BYTE SessionId,
  900. IN MEDIA_TYPE MediaType,
  901. IN MultimediaSystemControlMessage *pH245pdu,
  902. OUT LOGICAL_CHANNEL **ppReturnLogicalChannel
  903. )
  904. /*++
  905. Routine Description:
  906. Arguments:
  907. Return Values:
  908. S_OK on success.
  909. E_INVALIDARG if the PDU is invalid.
  910. --*/
  911. {
  912. SOCKADDR_IN SourceRtcpAddress;
  913. HRESULT HResult;
  914. *ppReturnLogicalChannel = NULL;
  915. HResult = CheckOpenRtpLogicalChannelPDU (OlcPDU, &SourceRtcpAddress);
  916. if (E_INVALIDARG == HResult) // XXX
  917. {
  918. return E_INVALIDARG;
  919. }
  920. // CODEWORK: We have to check only the
  921. // RTP LOGICAL_CHANNELS
  922. // check if there is a logical channel with the same non-zero
  923. // session id with the other H245 instance
  924. LOGICAL_CHANNEL *pAssocLogicalChannel =
  925. (0 == SessionId) ?
  926. NULL :
  927. GetOtherH245Info().GetLogicalChannelArray().FindBySessionId(SessionId);
  928. // For audio and video data create an RTP Logical Channel
  929. WORD LogChanNum = OlcPDU.forwardLogicalChannelNumber;
  930. RTP_LOGICAL_CHANNEL *pLogicalChannel = new RTP_LOGICAL_CHANNEL();
  931. if (NULL == pLogicalChannel)
  932. {
  933. DebugF( _T("H245_INFO::CreateRtpLogicalChannel() ")
  934. _T("cannot create a RTP_LOGICAL_CHANNEL, returning E_OUTOFMEMORY\n")
  935. );
  936. return E_OUTOFMEMORY;
  937. }
  938. // intialize the logical channel
  939. HResult = pLogicalChannel->HandleOpenLogicalChannelPDU(
  940. *this, // H245_INFO
  941. MediaType, // The type of the media
  942. ntohl (m_SocketInfo.LocalAddress.sin_addr.s_addr), // our local address
  943. ntohl (m_SocketInfo.RemoteAddress.sin_addr.s_addr), // our remote address
  944. ntohl (GetOtherH245Info().GetSocketInfo().LocalAddress.sin_addr.s_addr), // other h245 local address
  945. ntohl (GetOtherH245Info().GetSocketInfo().RemoteAddress.sin_addr.s_addr), // other h245 remote address
  946. LogChanNum, // logical channel number
  947. SessionId, // session id
  948. (RTP_LOGICAL_CHANNEL* )pAssocLogicalChannel,
  949. // associated logical channel
  950. // XXX What is a clean way of doing this ?
  951. ntohl (SourceRtcpAddress.sin_addr.s_addr),
  952. ntohs (SourceRtcpAddress.sin_port),
  953. pH245pdu // h245 pdu (OLC)
  954. );
  955. if (FAILED(HResult))
  956. {
  957. // destroy the logical channel
  958. delete pLogicalChannel;
  959. DebugF( _T("H245_INFO::CreateRtpLogicalChannel(&%x) ")
  960. _T("cannot initialize RTP_LOGICAL_CHANNEL, returning 0x%x\n"),
  961. pH245pdu, HResult);
  962. }
  963. else
  964. {
  965. *ppReturnLogicalChannel = pLogicalChannel;
  966. }
  967. _ASSERTE(S_FALSE != HResult);
  968. return HResult;
  969. }
  970. HRESULT
  971. H245_INFO::CreateT120LogicalChannel(
  972. IN OpenLogicalChannel &OlcPDU,
  973. IN BYTE SessionId,
  974. IN MEDIA_TYPE MediaType,
  975. IN MultimediaSystemControlMessage *pH245pdu,
  976. OUT LOGICAL_CHANNEL **ppReturnLogicalChannel
  977. )
  978. /*++
  979. Routine Description:
  980. Arguments:
  981. Return Values:
  982. S_OK on success.
  983. E_INVALIDARG if the PDU is invalid.
  984. --*/
  985. {
  986. DWORD T120ConnectToIPAddr;
  987. WORD T120ConnectToPort;
  988. HRESULT HResult;
  989. *ppReturnLogicalChannel = NULL;
  990. // CODEWORK: Have success code which returns a value saying
  991. // this PDU does not have the T120 listen address
  992. HResult = CheckOpenT120LogicalChannelPDU(OlcPDU,
  993. T120ConnectToIPAddr,
  994. T120ConnectToPort
  995. );
  996. if (E_INVALIDARG == HResult) // XXX
  997. {
  998. return E_INVALIDARG;
  999. }
  1000. // For data create a T.120 Logical Channel
  1001. WORD LogChanNum = OlcPDU.forwardLogicalChannelNumber;
  1002. T120_LOGICAL_CHANNEL *pLogicalChannel = new T120_LOGICAL_CHANNEL();
  1003. if (NULL == pLogicalChannel)
  1004. {
  1005. DebugF( _T("H245_INFO::CreateT120LogicalChannel(&%x) ")
  1006. _T("cannot create a T120_LOGICAL_CHANNEL, returning E_OUTOFMEMORY\n"),
  1007. pH245pdu);
  1008. return E_OUTOFMEMORY;
  1009. }
  1010. // intialize the logical channel
  1011. HResult = pLogicalChannel->HandleOpenLogicalChannelPDU(
  1012. *this, // H245_INFO
  1013. MediaType, // The type of the media
  1014. LogChanNum, // logical channel number
  1015. SessionId, // session id
  1016. T120ConnectToIPAddr, // T.120 end point is listening on this
  1017. T120ConnectToPort, // IPAddr and Port
  1018. pH245pdu // h245 pdu (OLC)
  1019. );
  1020. if (FAILED(HResult))
  1021. {
  1022. // destroy the logical channel
  1023. delete pLogicalChannel;
  1024. DebugF( _T("H245_INFO::CreateT120LogicalChannel(&%x) ")
  1025. _T("cannot initialize T120_LOGICAL_CHANNEL, returning 0x%x\n"),
  1026. pH245pdu, HResult);
  1027. }
  1028. else
  1029. {
  1030. *ppReturnLogicalChannel = pLogicalChannel;
  1031. }
  1032. _ASSERTE(S_FALSE != HResult);
  1033. return HResult;
  1034. }
  1035. HRESULT
  1036. H245_INFO::HandleOpenLogicalChannelPDU(
  1037. IN MultimediaSystemControlMessage *pH245pdu
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Arguments:
  1042. Return Values:
  1043. S_OK on success.
  1044. E_INVALIDARG if the PDU is invalid.
  1045. --*/
  1046. {
  1047. // it must be an open logical channel request message
  1048. _ASSERTE(MultimediaSystemControlMessage_request_chosen == \
  1049. pH245pdu->choice);
  1050. _ASSERTE(openLogicalChannel_chosen == \
  1051. pH245pdu->u.request.choice);
  1052. HRESULT HResult = E_FAIL;
  1053. OpenLogicalChannel &OlcPDU =
  1054. pH245pdu->u.request.u.openLogicalChannel;
  1055. // check to see if there is already a logical channel with the
  1056. // same forward logical channel number
  1057. // NOTE: the array indices are not the same as the forward logical
  1058. // channel number (0 is reserved for H245 channel and the ITU spec
  1059. // allows a terminal to use any other value for it - i.e. they need
  1060. // not be consecutive)
  1061. // NOTE: LogicalChannelNumber is USHORT, but we can treat it as an
  1062. // unsigned WORD
  1063. _ASSERTE(sizeof(LogicalChannelNumber) == sizeof(WORD));
  1064. WORD LogChanNum = OlcPDU.forwardLogicalChannelNumber;
  1065. if (NULL != m_LogicalChannelArray.FindByLogicalChannelNum(LogChanNum))
  1066. {
  1067. DebugF( _T("H245_INFO::HandleOpenLogicalChannelPDU(&%x) ")
  1068. _T("a logical channel with the forward logical channel num = %d ")
  1069. _T("already exists, returning E_INVALIDARG\n"),
  1070. pH245pdu, LogChanNum);
  1071. return E_INVALIDARG;
  1072. }
  1073. // check to see if we can handle this OLC PDU and
  1074. // return its session id, source ipv4 address, RTCP port
  1075. BYTE SessionId;
  1076. MEDIA_TYPE MediaType;
  1077. HResult = CheckOpenLogicalChannelPDU(
  1078. *pH245pdu,
  1079. SessionId,
  1080. MediaType
  1081. );
  1082. if (FAILED(HResult))
  1083. {
  1084. DebugF( _T("H245_INFO::HandleOpenLogicalChannelPDU(&%x) ")
  1085. _T("cannot handle Open Logical Channel PDU, returning 0x%x\n"),
  1086. pH245pdu, HResult);
  1087. return HResult;
  1088. }
  1089. // check to see if we already have a logical channel with this session id
  1090. if ( (0 != SessionId) &&
  1091. (NULL != m_LogicalChannelArray.FindBySessionId(SessionId)) )
  1092. {
  1093. DebugF( _T("H245_INFO::HandleOpenLogicalChannelPDU(&%x) ")
  1094. _T("another Logical Channel exists with same session id = %u, ")
  1095. _T("returning E_INVALIDARG\n"),
  1096. pH245pdu, SessionId);
  1097. return E_INVALIDARG;
  1098. }
  1099. LOGICAL_CHANNEL *pLogicalChannel = NULL;
  1100. // create an instance of a LOGICAL_CHANNEL
  1101. if (IsMediaTypeRtp(MediaType))
  1102. {
  1103. HResult = CreateRtpLogicalChannel(
  1104. OlcPDU,
  1105. SessionId,
  1106. MediaType,
  1107. pH245pdu,
  1108. &pLogicalChannel
  1109. );
  1110. }
  1111. else
  1112. {
  1113. HResult = CreateT120LogicalChannel(
  1114. OlcPDU,
  1115. SessionId,
  1116. MediaType,
  1117. pH245pdu,
  1118. &pLogicalChannel
  1119. );
  1120. }
  1121. if (FAILED(HResult))
  1122. {
  1123. DebugF( _T("H245_INFO::HandleOpenLogicalChannelPDU(&%x) ")
  1124. _T("Creating Logical channel failed, returning 0x%x\n"),
  1125. pH245pdu, HResult);
  1126. return HResult;
  1127. }
  1128. // insert the logical channel into the array
  1129. // we add this to the array so that the logical channel is
  1130. // available to the other h245 instance when its processing the PDU
  1131. // this is only being done for keeping the code clean
  1132. // and not really needed now
  1133. HResult = m_LogicalChannelArray.Add(*pLogicalChannel);
  1134. if (FAILED(HResult))
  1135. {
  1136. // destroy the logical channel
  1137. // this also removes any associations with any logical channel
  1138. // in the other H245 instance
  1139. delete pLogicalChannel;
  1140. DebugF( _T("H245_INFO::HandleOpenLogicalChannelPDU(&%x) ")
  1141. _T("cannot add new LOGICAL_CHANNEL to the array, returning 0x%x"),
  1142. pH245pdu, HResult);
  1143. return HResult;
  1144. }
  1145. _ASSERTE(S_FALSE != HResult);
  1146. return HResult;
  1147. }
  1148. // handles a request message to close a logical channel
  1149. // we start a timer and close the channel on receiving either a
  1150. // CloseLogicalChannelAck PDU or a timeout
  1151. HRESULT
  1152. H245_INFO::HandleCloseLogicalChannelPDU(
  1153. IN MultimediaSystemControlMessage *pH245pdu
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Arguments:
  1158. Return Values:
  1159. S_OK on success.
  1160. E_INVALIDARG if the PDU is invalid.
  1161. --*/
  1162. {
  1163. // it must be an open logical channel request message
  1164. _ASSERTE(closeLogicalChannel_chosen == pH245pdu->u.request.choice);
  1165. HRESULT HResult = E_FAIL;
  1166. CloseLogicalChannel &ClcPDU =
  1167. pH245pdu->u.request.u.closeLogicalChannel;
  1168. // verify that the logical channel indicated in the message exists
  1169. // NOTE: LogicalChannelNumber is USHORT, but we can treat it as an
  1170. // unsigned WORD
  1171. _ASSERTE(sizeof(LogicalChannelNumber) == sizeof(WORD));
  1172. WORD LogChanNum = ClcPDU.forwardLogicalChannelNumber;
  1173. LOGICAL_CHANNEL *pLogicalChannel =
  1174. m_LogicalChannelArray.FindByLogicalChannelNum(LogChanNum);
  1175. if (NULL == pLogicalChannel)
  1176. {
  1177. DebugF( _T("H245_INFO::HandleCloseLogicalChannelPDU(&%x), ")
  1178. _T("no logical channel with the forward logical channel num = %d, ")
  1179. _T("returning E_INVALIDARG\n"),
  1180. pH245pdu, LogChanNum);
  1181. return E_INVALIDARG;
  1182. }
  1183. // let the Logical Channel instance process the message
  1184. // it also forwards the message to the other H245 instance
  1185. // NOTE: the logical channel should not be used after this call as it
  1186. // may have deleted and removed itself from the array. it only returns
  1187. // an error in case the error cannot be handled by simply deleting
  1188. // itself (the logical channel)
  1189. HResult = pLogicalChannel->HandleCloseLogicalChannelPDU(
  1190. pH245pdu
  1191. );
  1192. if (FAILED(HResult))
  1193. {
  1194. DebugF( _T("H245_INFO::HandleCloseLogicalChannelPDU(&%x), ")
  1195. _T("logical channel (%d) couldn't handle close logical channel PDU, ")
  1196. _T("returning 0x%x\n"),
  1197. pH245pdu, LogChanNum, HResult);
  1198. return HResult;
  1199. }
  1200. _ASSERTE(S_OK == HResult);
  1201. DebugF( _T("H245_INFO::HandleCloseLogicalChannelPDU(&%x) returning 0x%x\n"),
  1202. pH245pdu, HResult);
  1203. return HResult;
  1204. }
  1205. /* virtual */
  1206. H245_INFO::~H245_INFO (void)
  1207. {
  1208. }
  1209. HRESULT
  1210. H245_INFO::SendEndSessionCommand (
  1211. void
  1212. )
  1213. /*++
  1214. Routine Description:
  1215. Encodes and sends H.245 EndSession PDU
  1216. Arguments:
  1217. None
  1218. Return Values:
  1219. Passes through the result of calling another function
  1220. Notes:
  1221. --*/
  1222. {
  1223. MultimediaSystemControlMessage EndSessionCommand;
  1224. HRESULT Result;
  1225. EndSessionCommand.choice = MultimediaSystemControlMessage_command_chosen;
  1226. EndSessionCommand.u.command.choice = endSessionCommand_chosen;
  1227. EndSessionCommand.u.command.u.endSessionCommand.choice = disconnect_chosen;
  1228. Result = QueueSend (&EndSessionCommand);
  1229. if (FAILED(Result))
  1230. {
  1231. DebugF(_T("H245: 0x%x failed to send EndSession PDU. Error=0x%x\n"),
  1232. &GetCallBridge (),
  1233. Result);
  1234. }
  1235. return Result;
  1236. } // H245_INFO::SendEndSessionCommand