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.

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