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.

583 lines
19 KiB

  1. #include "stdafx.h"
  2. #include "portmgmt.h"
  3. #include "timerval.h"
  4. #include "cbridge.h"
  5. #include "main.h"
  6. // destructor
  7. // virtual
  8. T120_LOGICAL_CHANNEL::~T120_LOGICAL_CHANNEL(
  9. )
  10. {
  11. if ( INVALID_HANDLE_VALUE != m_DynamicRedirectHandle )
  12. {
  13. NatCancelDynamicRedirect( m_DynamicRedirectHandle );
  14. m_DynamicRedirectHandle = INVALID_HANDLE_VALUE;
  15. }
  16. // Free the ports if they have been allocated
  17. FreePorts();
  18. }
  19. // All params in host order
  20. HRESULT
  21. T120_LOGICAL_CHANNEL::SetPorts(
  22. DWORD T120ConnectToIPAddr,
  23. WORD T120ConnectToPort,
  24. DWORD T120ListenOnIPAddr,
  25. DWORD T120ConnectFromIPAddr
  26. )
  27. {
  28. HRESULT HResult;
  29. // CODEWORK: Decide on the maximum number of TCP/IP connections to
  30. // to allow to the same port. CurtSm suggests 8. MaxM thinks 4 for
  31. // NM3.0 and 5 in general - currently allow 5.
  32. // Allocate m_T120ListenOnPort and m_T120ConnectFromPorts
  33. // Note that I am using the same routine I use to reserve
  34. // ports for RTP/RTCP. This call reserves a pair of ports.
  35. // CODEWORK: The port pool should have functions which
  36. // reserve more than 2 ports (6 ports).
  37. HResult = PortPoolAllocRTPPort(&m_T120ListenOnPort);
  38. if (FAILED(HResult))
  39. {
  40. return HResult;
  41. }
  42. m_T120ConnectToIPAddr = T120ConnectToIPAddr;
  43. m_T120ConnectToPort = T120ConnectToPort;
  44. m_T120ListenOnIPAddr = T120ListenOnIPAddr;
  45. m_T120ConnectFromIPAddr = T120ConnectFromIPAddr;
  46. HResult = CreateNatRedirect();
  47. if (FAILED(HResult))
  48. {
  49. return HResult;
  50. }
  51. _ASSERTE(S_OK == HResult);
  52. return S_OK;
  53. }
  54. HRESULT
  55. T120_LOGICAL_CHANNEL::FreePorts()
  56. {
  57. HRESULT Result;
  58. CancelNatRedirect();
  59. if (m_T120ListenOnPort != 0)
  60. {
  61. Result = PortPoolFreeRTPPort(m_T120ListenOnPort);
  62. if (FAILED(Result))
  63. {
  64. DebugF( _T("T120_LOGICAL_CHANNEL::FreePorts: PortPoolFreeRTPPort ")
  65. _T("failed error: 0x%x\n"),
  66. Result);
  67. }
  68. m_T120ListenOnPort = 0;
  69. }
  70. return S_OK;
  71. }
  72. ///////////////////////////////////////////////////////////////////////////////
  73. // //
  74. // Routines for setting up and tearing down NAT Redirects //
  75. // //
  76. ///////////////////////////////////////////////////////////////////////////////
  77. // This is defined in rtplc.cpp
  78. // This should not be required. But currently there is a bug in the API impl.
  79. // Create the NAT redirect
  80. HRESULT
  81. T120_LOGICAL_CHANNEL::CreateNatRedirect(
  82. )
  83. {
  84. // XXX Actually so many checks are not needed
  85. if (m_T120ConnectToIPAddr == INADDR_NONE ||
  86. m_T120ConnectToPort == 0 ||
  87. m_T120ListenOnPort == 0 )
  88. {
  89. DebugF( _T("T120_LOGICAL_CHANNEL::CreateNatRedirect() Ports not set")
  90. _T("m_120ConnectToIPAddr: %d.%d.%d.%d\n"),
  91. BYTES0123(m_T120ConnectToIPAddr)
  92. );
  93. // INVALID state or some such
  94. return E_UNEXPECTED;
  95. }
  96. ULONG Status;
  97. Status = NatCreateDynamicRedirect(
  98. NatRedirectFlagLoopback,
  99. IPPROTO_TCP,
  100. htonl(m_T120ListenOnIPAddr),
  101. htons(m_T120ListenOnPort),
  102. htonl(m_T120ConnectToIPAddr),
  103. htons(m_T120ConnectToPort),
  104. 0,
  105. 0,
  106. &m_DynamicRedirectHandle );
  107. if (Status != STATUS_SUCCESS) {
  108. DebugF (_T ("T120: failed to set up dynamic redirect (*.* -> %08X:%04X) => (*.* -> %08X:%04X).\n"),
  109. m_T120ListenOnIPAddr, // source packet dest address (local)
  110. m_T120ListenOnPort, // source packet dest port (local)
  111. m_T120ConnectToIPAddr, // NewDestinationAddress
  112. m_T120ConnectToPort); // NewDestinationPort
  113. return (HRESULT) Status;
  114. }
  115. else
  116. {
  117. DebugF (_T ("T120: 0x%x set up dynamic redirect (*.* -> %08X:%04X) => (*.* -> %08X:%04X).\n"),
  118. &GetCallBridge (),
  119. m_T120ListenOnIPAddr, // source packet dest address (local)
  120. m_T120ListenOnPort, // source packet dest port (local)
  121. m_T120ConnectToIPAddr, // NewDestinationAddress
  122. m_T120ConnectToPort); // NewDestinationPort
  123. }
  124. return S_OK;
  125. }
  126. void
  127. T120_LOGICAL_CHANNEL::CancelNatRedirect(
  128. )
  129. {
  130. // CODEWORK: CODEWORK:
  131. // Note that this routine gets called every time the destructor
  132. // gets called and this means that only half of the redirects could
  133. // have been established or whatever. So we need to check whether
  134. // each of the redirects has been established. For this purpose
  135. // it is probably advisable to have one more field storing whether
  136. // the redirect has been estd. so that we can appropriately clean
  137. // it up. This field should also be useful in the WSP filter scenario
  138. // where we don't actually store the ports.
  139. // if our current state is LC_STATE_OPEN_ACK_RCVD or
  140. // LC_STATE_OPENED_CLOSE_RCVD, we have a NAT mapping
  141. ULONG Win32ErrorCode;
  142. DebugF (_T("T120: 0x%x cancels redirect (*:* -> %08X:%04X) => (*:* -> %08X:%04X).\n"),
  143. &GetCallBridge (),
  144. m_T120ListenOnIPAddr, // source packet dest address (local)
  145. m_T120ListenOnPort, // source packet dest port (local)
  146. // m_T120ConnectFromIPAddr, // NewSourceAddress
  147. // m_T120ConnectFromPorts[i],
  148. m_T120ConnectToIPAddr, // NewDestinationAddress
  149. m_T120ConnectToPort); // NewDestinationPort
  150. if ( INVALID_HANDLE_VALUE != m_DynamicRedirectHandle )
  151. {
  152. Win32ErrorCode = NatCancelDynamicRedirect( m_DynamicRedirectHandle );
  153. m_DynamicRedirectHandle = INVALID_HANDLE_VALUE;
  154. }
  155. return;
  156. }
  157. #define INADDR_PRIVATE_HOSTORDER 0xC0A80001
  158. BOOL
  159. T120_LOGICAL_CHANNEL::IsT120RedirectNeeded( DWORD T120ConnectToIPAddr,
  160. DWORD T120ListenOnIPAddr,
  161. DWORD T120ConnectFromIPAddr )
  162. {
  163. HRESULT hr;
  164. BOOL IsPrivateDestination;
  165. BOOL IsPrivateSource = FALSE;
  166. BOOL IsPrivateListen = FALSE;
  167. BOOL fIsRedirectNeeded = TRUE;
  168. hr = ::IsPrivateAddress( T120ConnectToIPAddr, &IsPrivateDestination );
  169. ::IsPrivateAddress( T120ConnectToIPAddr, &IsPrivateSource );
  170. ::IsPrivateAddress( T120ListenOnIPAddr, &IsPrivateListen );
  171. DebugF( _T("Address %08X isPrivateDestionation %s\n"),
  172. T120ConnectToIPAddr, IsPrivateDestination ? _T("TRUE"):_T("FALSE") );
  173. DebugF( _T("Address %08X isPrivateSource %s\n"),
  174. T120ConnectFromIPAddr, IsPrivateSource ? _T("TRUE"):_T("FALSE") );
  175. DebugF( _T("Address %08X isPrivateSource %s\n"),
  176. T120ListenOnIPAddr, IsPrivateListen ? _T("TRUE"):_T("FALSE") );
  177. if ( (INADDR_PRIVATE_HOSTORDER == T120ConnectToIPAddr) ||
  178. (INADDR_PRIVATE_HOSTORDER == T120ListenOnIPAddr) )
  179. {
  180. fIsRedirectNeeded = FALSE;
  181. }
  182. else if ( SUCCEEDED(hr) &&
  183. ((FALSE == IsPrivateDestination) && (T120ListenOnIPAddr != T120ConnectToIPAddr)) )
  184. {
  185. fIsRedirectNeeded = FALSE;
  186. }
  187. if ( !fIsRedirectNeeded )
  188. {
  189. DebugF( _T(" T120 Redirect is NOT needed %08X\n"), T120ConnectToIPAddr );
  190. return FALSE;
  191. }
  192. return TRUE;
  193. }
  194. ///////////////////////////////////////////////////////////////////////////////
  195. // //
  196. // Routines for processing H.245 PDUs //
  197. // //
  198. ///////////////////////////////////////////////////////////////////////////////
  199. // all of these are available in the OPEN LOGICAL CHANNEL message
  200. // it modifies the OLC PDU and passes it on to the other H245
  201. // instance for forwarding ???
  202. HRESULT
  203. T120_LOGICAL_CHANNEL::HandleOpenLogicalChannelPDU(
  204. IN H245_INFO &H245Info,
  205. IN MEDIA_TYPE MediaType,
  206. IN WORD LogicalChannelNumber,
  207. IN BYTE SessionId,
  208. IN DWORD T120ConnectToIPAddr,
  209. IN WORD T120ConnectToPort,
  210. IN OUT MultimediaSystemControlMessage *pH245pdu
  211. )
  212. /*++
  213. Routine Description:
  214. This routine handles a T120 OLC PDU. The T120_LOGICAL_CHANNEL
  215. is create by H245_INFO::HandleOpenLogicalChannelPDU().
  216. If T120ConnectToIPAddr and Port are specified, then
  217. m_T120ListenOnPort and m_T120ConnectFromPorts are allocated and
  218. the listen address field in pH245pdu are replaced with an IP address
  219. and port on the other edge of the proxy.
  220. Arguments:
  221. H245Info -
  222. MediaType -
  223. LogicalChannelNumber -
  224. SessionId -
  225. T120ConnectToIPAddr -
  226. T120ConnectToPort -
  227. pH245pdu - If the T120ConnectToIPAddr and Port are specified then
  228. the listen address field in the H245 pdu is replaced with an
  229. IP address and port on the other edge of the proxy.
  230. Return Values:
  231. S_OK on success.
  232. E_INVALIDARG if the PDU is invalid.
  233. --*/
  234. {
  235. // CODEWORK: assert that we are dealing with a T120 PDU
  236. // this should be the first call to this instance after its
  237. // created - hence, these fields must be as asserted
  238. _ASSERTE(LC_STATE_NOT_INIT == m_LogicalChannelState);
  239. _ASSERTE(NULL == m_pH245Info);
  240. HRESULT HResult = E_FAIL;
  241. m_pH245Info = &H245Info;
  242. DWORD T120ListenOnIPAddr = ntohl (m_pH245Info->GetOtherH245Info().GetSocketInfo().LocalAddress.sin_addr.s_addr);
  243. DWORD T120ConnectFromIPAddr = ntohl (m_pH245Info->m_SocketInfo.LocalAddress.sin_addr.s_addr);
  244. // If the IP address that we need to connect to is specified in the
  245. // OLC PDU, then we need to allocate the port for listening on the
  246. // other interface.
  247. if ( (T120ConnectToIPAddr != INADDR_NONE) &&
  248. IsT120RedirectNeeded(T120ConnectToIPAddr, T120ListenOnIPAddr, T120ConnectFromIPAddr) )
  249. {
  250. HResult = SetPorts(
  251. T120ConnectToIPAddr,
  252. T120ConnectToPort,
  253. T120ListenOnIPAddr,
  254. // listen on other h245 local address
  255. T120ConnectFromIPAddr
  256. // connect from our local address
  257. );
  258. if (FAILED(HResult))
  259. {
  260. DebugF( _T("T120_LOGICAL_CHANNEL::HandleOpenLogicalChannelPDU, ")
  261. _T("failed to set its ports, returning 0x%x\n"),
  262. HResult);
  263. return HResult;
  264. }
  265. //_ASSERTE(S_FALSE != HResult);
  266. OpenLogicalChannel &OlcPDU =
  267. pH245pdu->u.request.u.openLogicalChannel;
  268. // modify the OLC PDU by replacing the RTCP address/port
  269. // with the h245 address and RTCP port
  270. FillH245TransportAddress(
  271. m_T120ListenOnIPAddr,
  272. m_T120ListenOnPort,
  273. OlcPDU.separateStack.networkAddress.u.localAreaAddress
  274. );
  275. }
  276. else
  277. {
  278. m_T120ConnectToIPAddr = T120ConnectToIPAddr;
  279. m_T120ConnectToPort = T120ConnectToPort;
  280. m_T120ListenOnIPAddr = T120ListenOnIPAddr;
  281. m_T120ConnectFromIPAddr = T120ConnectFromIPAddr;
  282. }
  283. // Should the part below be pushed into H245_INFO::HandleOpenLogicalChannelPDU ?????
  284. // let the other H245 instance process the PDU
  285. HResult = m_pH245Info->GetOtherH245Info().ProcessMessage(
  286. pH245pdu);
  287. if (FAILED(HResult))
  288. {
  289. DebugF( _T("T120_LOGICAL_CHANNEL::HandleOpenLogicalChannelPDU")
  290. _T("(&H245Info, %u, %u, %d.%d.%d.%d, %u, 0x%x, 0x%x)")
  291. _T("other H245 instance failed to process OLC PDU, returning 0x%x\n"),
  292. LogicalChannelNumber, SessionId, BYTES0123(T120ConnectToIPAddr),
  293. T120ConnectToPort, pH245pdu, HResult);
  294. return HResult;
  295. }
  296. // start timer for a response
  297. // TO DO *** creating timers after queueing the send is sufficient.
  298. // change back earlier policy of creating these only after the send
  299. // callback (to be consistent). creating timers that way would be too
  300. // complex for logical channels
  301. HResult = CreateTimer(LC_POST_OPEN_TIMER_VALUE);
  302. if (FAILED(HResult))
  303. {
  304. DebugF (_T("T120: 0x%x failed to create timer for duration %d milliseconds ('Open Logical Channel'). Error - %x.\n"),
  305. &GetCallBridge (),
  306. LC_POST_OPEN_TIMER_VALUE,
  307. HResult);
  308. return HResult;
  309. }
  310. DebugF (_T("T120: 0x%x created timer for duration %d milliseconds ('Open Logical Channel').\n"),
  311. &GetCallBridge (),
  312. LC_POST_OPEN_TIMER_VALUE);
  313. //_ASSERTE(S_FALSE != HResult);
  314. InitLogicalChannel(&H245Info, MediaType,
  315. LogicalChannelNumber,
  316. SessionId, LC_STATE_OPEN_RCVD);
  317. // transition state to LC_STATE_OPEN_RCVD
  318. m_LogicalChannelState = LC_STATE_OPEN_RCVD;
  319. return S_OK;
  320. }
  321. // If there is no T.120 Listen address in the PDU
  322. // T120ConnectToIPAddr will contain INADDR_NONE
  323. HRESULT
  324. T120_LOGICAL_CHANNEL::CheckOpenLogicalChannelAckPDU(
  325. IN OpenLogicalChannelAck &OlcAckPDU,
  326. OUT DWORD &T120ConnectToIPAddr,
  327. OUT WORD &T120ConnectToPort
  328. )
  329. /*++
  330. Routine Description:
  331. Arguments:
  332. OlcAckPDU -
  333. T120ConnectToIPAddr -
  334. T120ConnectToPort -
  335. Return Values:
  336. S_OK on success.
  337. E_INVALIDARG if the PDU is invalid.
  338. --*/
  339. {
  340. HRESULT HResult = S_OK;
  341. // These are the return values in case of a failure
  342. // or if the address is not present in the PDU
  343. T120ConnectToIPAddr = INADDR_NONE;
  344. T120ConnectToPort = 0;
  345. // there should be reverse logical channel parameters
  346. if (!(OpenLogicalChannelAck_reverseLogicalChannelParameters_present &
  347. OlcAckPDU.bit_mask))
  348. {
  349. DebugF( _T("T120_LOGICAL_CHANNEL::CheckOpenLogicalChannelAckPDU, NO")
  350. _T("reverse logical channel params, returning E_INVALIDARG\n"));
  351. return E_INVALIDARG;
  352. }
  353. // there should be a separate stack if we do not have
  354. // a T.120 end point address to connect to (from the OLC PDU).
  355. if (!(OpenLogicalChannelAck_separateStack_present &
  356. OlcAckPDU.bit_mask) &&
  357. m_T120ConnectToIPAddr == INADDR_NONE)
  358. {
  359. DebugF( _T("T120_LOGICAL_CHANNEL::CheckOpenLogicalChannelAckPDU, ")
  360. _T("NO separate stack, returning E_INVALIDARG\n"));
  361. return E_INVALIDARG;
  362. }
  363. if (OpenLogicalChannelAck_separateStack_present &
  364. OlcAckPDU.bit_mask)
  365. {
  366. HResult = GetT120ConnectToAddress(
  367. OlcAckPDU.separateStack,
  368. T120ConnectToIPAddr,
  369. T120ConnectToPort
  370. );
  371. }
  372. return HResult;
  373. }
  374. HRESULT
  375. T120_LOGICAL_CHANNEL::ProcessOpenLogicalChannelAckPDU(
  376. IN MultimediaSystemControlMessage *pH245pdu
  377. )
  378. /*++
  379. Routine Description:
  380. Arguments:
  381. pH245pdu -
  382. Return Values:
  383. S_OK on success.
  384. E_INVALIDARG if the PDU is invalid.
  385. --*/
  386. {
  387. //The type of this pdu should be OLC Ack
  388. _ASSERTE(pH245pdu->u.response.choice == openLogicalChannelAck_chosen);
  389. HRESULT HResult = E_FAIL;
  390. OpenLogicalChannelAck &OlcAckPDU =
  391. pH245pdu->u.response.u.openLogicalChannelAck;
  392. switch(m_LogicalChannelState)
  393. {
  394. case LC_STATE_OPEN_RCVD:
  395. DWORD T120ConnectToIPAddr;
  396. WORD T120ConnectToPort;
  397. DWORD T120ListenOnIPAddr;
  398. DWORD T120ConnectFromIPAddr;
  399. T120ConnectFromIPAddr = ntohl (m_pH245Info->GetOtherH245Info().GetSocketInfo().LocalAddress.sin_addr.s_addr);
  400. T120ListenOnIPAddr = ntohl (m_pH245Info->m_SocketInfo.LocalAddress.sin_addr.s_addr);
  401. HResult = CheckOpenLogicalChannelAckPDU(
  402. OlcAckPDU,
  403. T120ConnectToIPAddr,
  404. T120ConnectToPort
  405. );
  406. if (FAILED(HResult))
  407. {
  408. return HResult;
  409. }
  410. _ASSERTE(S_OK == HResult);
  411. if ( (T120ConnectToIPAddr != INADDR_NONE)
  412. && IsT120RedirectNeeded(T120ConnectToIPAddr, T120ListenOnIPAddr, T120ConnectFromIPAddr) )
  413. {
  414. HResult = SetPorts(
  415. T120ConnectToIPAddr,
  416. T120ConnectToPort,
  417. T120ListenOnIPAddr,
  418. // listen on our local address
  419. T120ConnectFromIPAddr
  420. // connect from other h245 local address
  421. );
  422. if (FAILED(HResult))
  423. {
  424. return HResult;
  425. }
  426. // modify the OLC PDU by replacing the RTCP address/port
  427. // with the h245 address and RTCP port
  428. FillH245TransportAddress(
  429. m_T120ListenOnIPAddr,
  430. m_T120ListenOnPort,
  431. OlcAckPDU.separateStack.networkAddress.u.localAreaAddress
  432. );
  433. }
  434. else
  435. {
  436. m_T120ConnectToIPAddr = T120ConnectToIPAddr;
  437. m_T120ConnectToPort = T120ConnectToPort;
  438. m_T120ListenOnIPAddr = T120ListenOnIPAddr;
  439. m_T120ConnectFromIPAddr = T120ConnectFromIPAddr;
  440. }
  441. // reset timer, we must have one (ignore error code if any)
  442. //_ASSERTE(NULL != m_TimerHandle);
  443. TimprocCancelTimer();
  444. DebugF (_T("T120: 0x%x cancelled timer.\n"),
  445. &GetCallBridge ());
  446. // transition to LC_STATE_OPEN_ACK_RCVD
  447. m_LogicalChannelState = LC_STATE_OPEN_ACK_RCVD;
  448. break;
  449. case LC_STATE_CLOSE_RCVD:
  450. // if we have received a close logical channel PDU, we must throw
  451. // OLC ACKs away and continue to wait
  452. DebugF( _T("T120_LOGICAL_CHANNEL::ProcessOpenLogicalChannelAckPDU")
  453. _T("(&%x), in close state %d, returning E_INVALIDARG\n"),
  454. pH245pdu, m_LogicalChannelState);
  455. return E_INVALIDARG;
  456. break;
  457. case LC_STATE_NOT_INIT:
  458. case LC_STATE_OPEN_ACK_RCVD:
  459. case LC_STATE_OPENED_CLOSE_RCVD:
  460. default:
  461. DebugF( _T("T120_LOGICAL_CHANNEL::ProcessOpenLogicalChannelAckPDU")
  462. _T("(&%x), in state %d, returning E_UNEXPECTED\n"),
  463. pH245pdu, m_LogicalChannelState);
  464. _ASSERTE(FALSE);
  465. return E_UNEXPECTED;
  466. break;
  467. } // switch (m_LogicalChannelState)
  468. return HResult;
  469. }