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.

1094 lines
30 KiB

  1. /*----------------------------------------------------------------------------
  2. * File: RTCPSESS.C
  3. * Product: RTP/RTCP implementation
  4. * Description: Provides RTCP session management.
  5. *
  6. * INTEL Corporation Proprietary Information
  7. * This listing is supplied under the terms of a license agreement with
  8. * Intel Corporation and may not be copied nor disclosed except in
  9. * accordance with the terms of that agreement.
  10. * Copyright (c) 1995 Intel Corporation.
  11. *--------------------------------------------------------------------------*/
  12. #include "rrcm.h"
  13. /*---------------------------------------------------------------------------
  14. / Global Variables
  15. /--------------------------------------------------------------------------*/
  16. /*---------------------------------------------------------------------------
  17. / External Variables
  18. /--------------------------------------------------------------------------*/
  19. extern PRTCP_CONTEXT pRTCPContext;
  20. extern PRTP_CONTEXT pRTPContext;
  21. extern RRCM_WS RRCMws;
  22. #ifdef ENABLE_ISDM2
  23. extern ISDM2 Isdm2;
  24. #endif
  25. #ifdef _DEBUG
  26. extern char debug_string[];
  27. #endif
  28. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  29. //INTEROP
  30. extern LPInteropLogger RTPLogger;
  31. #endif
  32. /*----------------------------------------------------------------------------
  33. * Function : CreateRTCPSession
  34. * Description: Creates an RTCP session.
  35. *
  36. * Input : RTPsd : RTP socket descriptor
  37. * RTCPsd : RTCP socket descriptor
  38. * lpTo : To address
  39. * toLen : To address length
  40. * pSdesInfo : -> to SDES information
  41. * dwStreamClock : Stream clocking frequency
  42. * pEncryptInfo : -> to encryption information
  43. * ssrc : If set, user selected SSRC
  44. * pSSRCcallback : Callback for user's selected SSRC
  45. * dwCallbackInfo : User callback information
  46. * miscInfo : Miscelleanous information:
  47. * H.323Conf: 0x00000002
  48. * Encrypt SR/RR: 0x00000004
  49. * RTCPon: 0x00000008
  50. * dwRtpSessionBw : RTP session bandwidth used for RTCP BW
  51. * *pRTCPStatus : -> to status information
  52. *
  53. * Return: NULL : Couldn't create RTCP session
  54. * !0 : RTCP session's address
  55. ---------------------------------------------------------------------------*/
  56. PRTCP_SESSION CreateRTCPSession (SOCKET RTPsd,
  57. SOCKET RTCPsd,
  58. LPVOID lpTo,
  59. DWORD toLen,
  60. PSDES_DATA pSdesInfo,
  61. DWORD dwStreamClock,
  62. PENCRYPT_INFO pEncryptInfo,
  63. DWORD ssrc,
  64. PRRCM_EVENT_CALLBACK pRRCMcallback,
  65. DWORD_PTR dwCallbackInfo,
  66. DWORD miscInfo,
  67. DWORD dwRtpSessionBw,
  68. DWORD *pRTCPstatus)
  69. {
  70. PRTCP_SESSION pRTCPses = NULL;
  71. PSSRC_ENTRY pSSRCentry = NULL;
  72. DWORD dwStatus = RRCM_NoError;
  73. DWORD startRtcp = FALSE;
  74. char hName[256];
  75. int tmpSize;
  76. struct sockaddr_in *pSockAddr;
  77. IN_OUT_STR ("RTCP: Enter CreateRTCPSession()\n");
  78. // set status
  79. *pRTCPstatus = RRCM_NoError;
  80. // allocate all required resources for the RTCP session
  81. dwStatus = allocateRTCPsessionResources (&pRTCPses,
  82. &pSSRCentry);
  83. if (dwStatus != RRCM_NoError)
  84. {
  85. RRCM_DBG_MSG ("RTCP: ERROR - Resource allocation failed", 0,
  86. __FILE__, __LINE__, DBG_CRITICAL);
  87. IN_OUT_STR ("RTCP: Exit CreateRTCPSession()\n");
  88. *pRTCPstatus = dwStatus;
  89. return (NULL);
  90. }
  91. // if this is the first session, create the RTCP thread, which
  92. // will be killed when no more sessions exist.
  93. if (pRTCPContext->RTCPSession.prev == NULL)
  94. {
  95. startRtcp = TRUE;
  96. }
  97. // save the parent RTCP session address in the SSRC entry
  98. pSSRCentry->pRTCPses = pRTCPses;
  99. // network destination address
  100. if (toLen)
  101. {
  102. pRTCPses->dwSessionStatus = RTCP_DEST_LEARNED;
  103. pRTCPses->toLen = toLen;
  104. memcpy (&pRTCPses->toBfr, lpTo, toLen);
  105. }
  106. // mark the session as new for the benefit of the RTCP thread
  107. pRTCPses->dwSessionStatus |= NEW_RTCP_SESSION;
  108. #ifdef ENABLE_ISDM2
  109. // initialize the session key in case ISDM is used
  110. pRTCPses->hSessKey = NULL;
  111. #endif
  112. // number of SSRC for this RTCP session
  113. pRTCPses->dwCurNumSSRCperSes = 1;
  114. #ifdef MONITOR_STATS
  115. pRTCPses->dwHiNumSSRCperSes = 1;
  116. #endif
  117. // SSRC entry related information
  118. pSSRCentry->RTPsd = RTPsd;
  119. pSSRCentry->RTCPsd = RTCPsd;
  120. // get our own transport address -
  121. // will be used for collision resolution when using multicast
  122. tmpSize = sizeof (SOCKADDR);
  123. dwStatus = RRCMws.getsockname (RTPsd, (PSOCKADDR)pSSRCentry->from, &tmpSize);
  124. // only process when no error is reported. If the socket is not bound
  125. // it won't cause any problem for unicast or multicast if the sender
  126. // has not join the mcast group. If the sender joins the mcast group
  127. // it's socket should be bound by now as specified in the EPS
  128. if (dwStatus == 0)
  129. {
  130. // if bound to INADDR_ANY, address will be 0
  131. pSockAddr = (PSOCKADDR_IN)&pSSRCentry->from;
  132. if (pSockAddr->sin_addr.s_addr == 0)
  133. {
  134. // get the host name (to get the local IP address)
  135. if ( ! RRCMws.gethostname (hName, sizeof(hName)))
  136. {
  137. LPHOSTENT lpHEnt;
  138. // get the host by name infor
  139. if ((lpHEnt = RRCMws.gethostbyname (hName)) != NULL)
  140. {
  141. // get the local IP address
  142. pSockAddr->sin_addr.s_addr =
  143. *((u_long *)lpHEnt->h_addr_list[0]);
  144. }
  145. }
  146. }
  147. }
  148. // build session's SDES information
  149. buildSDESinfo (pSSRCentry, pSdesInfo);
  150. // link the SSRC to the RTCP session list of Xmt SSRCs entries
  151. addToHeadOfList (&(pRTCPses->XmtSSRCList),
  152. (PLINK_LIST)pSSRCentry,
  153. &pRTCPses->critSect);
  154. // initialize the number of stream for this session
  155. pRTCPses->dwNumStreamPerSes = 1;
  156. // get a unique SSRC for this session
  157. if (ssrc)
  158. pSSRCentry->SSRC = ssrc;
  159. else
  160. pSSRCentry->SSRC = getSSRC (pRTCPses->XmtSSRCList,
  161. pRTCPses->RcvSSRCList);
  162. // RRCM callback notification
  163. pRTCPses->pRRCMcallback = pRRCMcallback;
  164. pRTCPses->dwCallbackUserInfo = dwCallbackInfo;
  165. // set operation flag
  166. if (miscInfo & H323_CONFERENCE)
  167. pRTCPses->dwSessionStatus |= H323_CONFERENCE;
  168. if (miscInfo & ENCRYPT_SR_RR)
  169. pRTCPses->dwSessionStatus |= ENCRYPT_SR_RR;
  170. // estimate the initial session bandwidth
  171. if (dwRtpSessionBw == 0)
  172. {
  173. pSSRCentry->xmtInfo.dwRtcpStreamMinBW = INITIAL_RTCP_BANDWIDTH;
  174. }
  175. else
  176. {
  177. // RTCP bandwidth is 5% of the RTP bandwidth
  178. pSSRCentry->xmtInfo.dwRtcpStreamMinBW = (dwRtpSessionBw * 5) / 100;
  179. }
  180. // the stream clocking frequency
  181. pSSRCentry->dwStreamClock = dwStreamClock;
  182. // initialize 'dwLastReportRcvdTime' to now
  183. pSSRCentry->dwLastReportRcvdTime = timeGetTime();
  184. #ifdef _DEBUG
  185. wsprintf(debug_string,
  186. "RTCP: Add new RTCP session: Addr:x%p", pRTCPses);
  187. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  188. wsprintf(debug_string,
  189. "RTCP: Add SSRC entry (Addr:x%p, SSRC=x%lX) to session (Addr:x%p)",
  190. pSSRCentry, pSSRCentry->SSRC, pRTCPses);
  191. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  192. pSSRCentry->dwPrvTime = timeGetTime();
  193. #endif
  194. // turn on RTCP or not
  195. if (miscInfo & RTCP_ON)
  196. {
  197. // this session sends and receives RTCP reports
  198. pRTCPses->dwSessionStatus |= RTCP_ON;
  199. }
  200. // link the RTCP session to the head of the list of RTCP sessions
  201. addToHeadOfList (&(pRTCPContext->RTCPSession),
  202. (PLINK_LIST)pRTCPses,
  203. &pRTCPContext->critSect);
  204. #ifdef ENABLE_ISDM2
  205. // register to ISDM only if destination address is known
  206. if (Isdm2.hISDMdll && (pRTCPses->dwSessionStatus & RTCP_DEST_LEARNED))
  207. registerSessionToISDM (pSSRCentry, pRTCPses, &Isdm2);
  208. #endif
  209. // create the RTCP thread if needed
  210. if (startRtcp == TRUE)
  211. {
  212. // No RTCP thread if this fail
  213. dwStatus = CreateRTCPthread ();
  214. if (dwStatus != RRCM_NoError)
  215. {
  216. RRCM_DBG_MSG ("RTCP: ERROR - Cannot create RTCP thread", 0,
  217. __FILE__, __LINE__, DBG_CRITICAL);
  218. IN_OUT_STR ("RTCP: Exit CreateRTCPSession()\n");
  219. *pRTCPstatus = dwStatus;
  220. return (NULL);
  221. }
  222. }
  223. IN_OUT_STR ("RTCP: Exit CreateRTCPSession()\n");
  224. return (pRTCPses);
  225. }
  226. /*----------------------------------------------------------------------------
  227. * Function : allocateRTCPsessionResources
  228. * Description: Allocate all required resources for an RTCP session.
  229. *
  230. * Input : *pRTCPses: ->(->) to the RTCP session's information
  231. * *pSSRCentry: ->(->) to the SSRC's entry
  232. *
  233. * Return: OK: RRCM_NoError
  234. * !0: Error code (see RRCM.H)
  235. ---------------------------------------------------------------------------*/
  236. DWORD allocateRTCPsessionResources (PRTCP_SESSION *pRTCPses,
  237. PSSRC_ENTRY *pSSRCentry)
  238. {
  239. DWORD dwStatus = RRCM_NoError;
  240. IN_OUT_STR ("RTCP: Enter allocateRTCPsessionResources()\n");
  241. // get an RTCP session
  242. *pRTCPses = (PRTCP_SESSION)HeapAlloc (pRTCPContext->hHeapRTCPSes,
  243. HEAP_ZERO_MEMORY,
  244. sizeof(RTCP_SESSION));
  245. if (*pRTCPses == NULL)
  246. dwStatus = RRCMError_RTCPResources;
  247. // 'defined' RTCP resources
  248. if (dwStatus == RRCM_NoError)
  249. {
  250. (*pRTCPses)->dwInitNumFreeRcvBfr = NUM_FREE_RCV_BFR;
  251. (*pRTCPses)->dwRcvBfrSize = pRTPContext->registry.RTCPrcvBfrSize;
  252. (*pRTCPses)->dwXmtBfrSize = RRCM_XMT_BFR_SIZE;
  253. // allocate the RTCP session's Rcv/Xmt heaps and Rcv/Xmt buffers
  254. dwStatus = allocateRTCPSessionHeaps (pRTCPses);
  255. }
  256. if (dwStatus == RRCM_NoError)
  257. {
  258. // initialize this session's critical section
  259. InitializeCriticalSection (&(*pRTCPses)->critSect);
  260. // allocate free list of RTCP receive buffers
  261. dwStatus = allocateRTCPBfrList (&(*pRTCPses)->RTCPrcvBfrList,
  262. (*pRTCPses)->hHeapRcvBfrList,
  263. (*pRTCPses)->hHeapRcvBfr,
  264. &(*pRTCPses)->dwInitNumFreeRcvBfr,
  265. (*pRTCPses)->dwRcvBfrSize,
  266. &(*pRTCPses)->critSect);
  267. }
  268. if (dwStatus == RRCM_NoError)
  269. {
  270. (*pRTCPses)->XmtBfr.buf = (char *)LocalAlloc(0,(*pRTCPses)->dwXmtBfrSize);
  271. if ((*pRTCPses)->XmtBfr.buf == NULL)
  272. dwStatus = RRCMError_RTCPResources;
  273. }
  274. if (dwStatus == RRCM_NoError)
  275. {
  276. // get an SSRC entry
  277. *pSSRCentry = getOneSSRCentry (&pRTCPContext->RRCMFreeStat,
  278. pRTCPContext->hHeapRRCMStat,
  279. &pRTCPContext->dwInitNumFreeRRCMStat,
  280. &pRTCPContext->critSect);
  281. if (*pSSRCentry == NULL)
  282. dwStatus = RRCMError_RTCPResources;
  283. }
  284. if (dwStatus == RRCM_NoError)
  285. {
  286. // manual-reset event that will be used to signal the end of the
  287. // RTCP session to all of the session's stream
  288. (*pRTCPses)->hShutdownDone = CreateEvent (NULL, TRUE, FALSE, NULL);
  289. if ((*pRTCPses)->hShutdownDone == NULL)
  290. {
  291. dwStatus = RRCMError_RTCPResources;
  292. RRCM_DBG_MSG ("RTCP: ERROR - CreateEvent()", GetLastError(),
  293. __FILE__, __LINE__, DBG_ERROR);
  294. }
  295. }
  296. // any resource allocation problem ?
  297. if (dwStatus != RRCM_NoError)
  298. {
  299. if (*pSSRCentry)
  300. addToHeadOfList (&pRTCPContext->RRCMFreeStat,
  301. (PLINK_LIST)*pSSRCentry,
  302. &pRTCPContext->critSect);
  303. if ((*pSSRCentry)->hXmtThread)
  304. {
  305. if (TerminateThread ((*pSSRCentry)->hXmtThread,
  306. (*pSSRCentry)->dwXmtThreadID) == FALSE)
  307. {
  308. RRCM_DBG_MSG ("RTCP: ERROR - TerminateThread()",
  309. GetLastError(), __FILE__, __LINE__, DBG_ERROR);
  310. }
  311. }
  312. if (*pRTCPses)
  313. {
  314. if (HeapFree (pRTCPContext->hHeapRTCPSes, 0, *pRTCPses) == FALSE)
  315. {
  316. RRCM_DBG_MSG ("RTCP: ERROR - HeapFree()", GetLastError(),
  317. __FILE__, __LINE__, DBG_ERROR);
  318. }
  319. }
  320. }
  321. IN_OUT_STR ("RTCP: Exit allocateRTCPsessionResources()\n");
  322. return dwStatus;
  323. }
  324. /*----------------------------------------------------------------------------
  325. * Function : buildSDESinfo
  326. * Description: Build the session's SDES information
  327. *
  328. * Input : pRTCPses: -> to session's
  329. * pSdesInfo: -> to SDES information
  330. *
  331. * Return: OK: RRCM_NoError
  332. * !0: Error code (see RRCM.H)
  333. ---------------------------------------------------------------------------*/
  334. DWORD buildSDESinfo (PSSRC_ENTRY pSSRCentry,
  335. PSDES_DATA pSdesInfo)
  336. {
  337. PSDES_DATA pTmpSdes;
  338. DWORD CnameOK = FALSE;
  339. IN_OUT_STR ("RTCP: Enter buildSDESinfo()\n");
  340. pTmpSdes = pSdesInfo;
  341. while (pTmpSdes->dwSdesType)
  342. {
  343. switch (pTmpSdes->dwSdesType)
  344. {
  345. case RTCP_SDES_CNAME:
  346. pSSRCentry->cnameInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  347. memcpy (pSSRCentry->cnameInfo.sdesBfr, pTmpSdes->sdesBfr,
  348. pTmpSdes->dwSdesLength);
  349. pSSRCentry->cnameInfo.dwSdesFrequency =
  350. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  351. pSSRCentry->cnameInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  352. CnameOK = TRUE;
  353. break;
  354. case RTCP_SDES_NAME:
  355. pSSRCentry->nameInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  356. memcpy (pSSRCentry->nameInfo.sdesBfr, pTmpSdes->sdesBfr,
  357. pTmpSdes->dwSdesLength);
  358. pSSRCentry->nameInfo.dwSdesFrequency =
  359. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  360. pSSRCentry->nameInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  361. break;
  362. case RTCP_SDES_EMAIL:
  363. pSSRCentry->emailInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  364. memcpy (pSSRCentry->emailInfo.sdesBfr, pTmpSdes->sdesBfr,
  365. pTmpSdes->dwSdesLength);
  366. pSSRCentry->emailInfo.dwSdesFrequency =
  367. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  368. pSSRCentry->emailInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  369. break;
  370. case RTCP_SDES_PHONE:
  371. pSSRCentry->phoneInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  372. memcpy (pSSRCentry->phoneInfo.sdesBfr, pTmpSdes->sdesBfr,
  373. pTmpSdes->dwSdesLength);
  374. pSSRCentry->phoneInfo.dwSdesFrequency =
  375. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  376. pSSRCentry->phoneInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  377. break;
  378. case RTCP_SDES_LOC:
  379. pSSRCentry->locInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  380. memcpy (pSSRCentry->locInfo.sdesBfr, pTmpSdes->sdesBfr,
  381. pTmpSdes->dwSdesLength);
  382. pSSRCentry->locInfo.dwSdesFrequency =
  383. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  384. pSSRCentry->locInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  385. break;
  386. case RTCP_SDES_TOOL:
  387. pSSRCentry->toolInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  388. memcpy (pSSRCentry->toolInfo.sdesBfr, pTmpSdes->sdesBfr,
  389. pTmpSdes->dwSdesLength);
  390. pSSRCentry->toolInfo.dwSdesFrequency =
  391. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  392. pSSRCentry->toolInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  393. break;
  394. case RTCP_SDES_TXT:
  395. pSSRCentry->txtInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  396. memcpy (pSSRCentry->txtInfo.sdesBfr, pTmpSdes->sdesBfr,
  397. pTmpSdes->dwSdesLength);
  398. pSSRCentry->txtInfo.dwSdesFrequency =
  399. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  400. pSSRCentry->txtInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  401. break;
  402. case RTCP_SDES_PRIV:
  403. pSSRCentry->privInfo.dwSdesLength = pTmpSdes->dwSdesLength;
  404. memcpy (pSSRCentry->privInfo.sdesBfr, pTmpSdes->sdesBfr,
  405. pTmpSdes->dwSdesLength);
  406. pSSRCentry->privInfo.dwSdesFrequency =
  407. frequencyToPckt (pTmpSdes->dwSdesFrequency);
  408. pSSRCentry->privInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
  409. break;
  410. }
  411. pTmpSdes++;
  412. }
  413. // default CNAME if none provided
  414. if (CnameOK == FALSE)
  415. {
  416. pSSRCentry->cnameInfo.dwSdesLength = sizeof(szDfltCname);
  417. memcpy (pSSRCentry->cnameInfo.sdesBfr, szDfltCname,
  418. sizeof(szDfltCname));
  419. pSSRCentry->cnameInfo.dwSdesFrequency = 1;
  420. pSSRCentry->cnameInfo.dwSdesEncrypted = 0;
  421. }
  422. IN_OUT_STR ("RTCP: Exit buildSDESinfo()\n");
  423. return (RRCM_NoError);
  424. }
  425. /*----------------------------------------------------------------------------
  426. * Function : frequencyToPckt
  427. * Description: Transform the required frequency to a number of packet. (To
  428. * be used by a modulo function)
  429. *
  430. * Input : freq: Desired frequency from 0 to 100
  431. *
  432. * Return: X: Packet to skip, ie, one out of X
  433. ---------------------------------------------------------------------------*/
  434. DWORD frequencyToPckt (DWORD freq)
  435. {
  436. if (freq <= 10)
  437. return 9;
  438. else if (freq <= 20)
  439. return 5;
  440. else if (freq <= 25)
  441. return 4;
  442. else if (freq <= 33)
  443. return 3;
  444. else if (freq <= 50)
  445. return 2;
  446. else
  447. return 1;
  448. }
  449. /*----------------------------------------------------------------------------
  450. * Function : deleteRTCPSession
  451. * Description: Closes an RTCP session.
  452. *
  453. * Input : RTCPsd : RTCP socket descriptor
  454. * byeReason : -> to the BYE reason
  455. *
  456. * Return: OK: RRCM_NoError
  457. * !0: Error code (see RRCM.H)
  458. ---------------------------------------------------------------------------*/
  459. DWORD deleteRTCPSession (SOCKET RTCPsd,
  460. PCHAR byeReason)
  461. {
  462. PLINK_LIST pTmp;
  463. PSSRC_ENTRY pSSRC;
  464. PRTCP_SESSION pRTCP;
  465. DWORD dwStatus = RRCM_NoError;
  466. DWORD sessionFound = FALSE;
  467. IN_OUT_STR ("RTCP: Enter deleteRTCPSEssion()\n");
  468. // walk through the list from the tail
  469. pTmp = pRTCPContext->RTCPSession.prev;
  470. #ifdef _DEBUG
  471. wsprintf(debug_string,
  472. "RTCP: Deleting RTCP session: (Addr:x%p) ...", pTmp);
  473. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  474. #endif
  475. while (pTmp)
  476. {
  477. // get the right session to close by walking the transmit list
  478. pSSRC = (PSSRC_ENTRY)((PRTCP_SESSION)pTmp)->XmtSSRCList.prev;
  479. if (pSSRC->RTCPsd == RTCPsd)
  480. {
  481. sessionFound = TRUE;
  482. // save a pointer to the RTCP session
  483. pRTCP = pSSRC->pRTCPses;
  484. // RTCP send BYE packet for this active stream
  485. RTCPsendBYE (pSSRC, NULL);
  486. // flush out any outstanding I/O
  487. RTCPflushIO (pSSRC);
  488. // if this is the only RTCP session left, terminate the RTCP
  489. // timeout thread, so it doesn't access the session when it expires
  490. if ((pRTCPContext->RTCPSession.prev)->next == NULL)
  491. terminateRtcpThread ();
  492. // lock out access to this RTCP session
  493. EnterCriticalSection (&pRTCP->critSect);
  494. // free all Rcv & Xmt SSRC entries used by this session
  495. deleteSSRClist (pRTCP,
  496. &pRTCPContext->RRCMFreeStat,
  497. pRTCPContext);
  498. #ifdef ENABLE_ISDM2
  499. if (Isdm2.hISDMdll && pRTCP->hSessKey)
  500. Isdm2.ISDMEntry.ISD_DeleteKey(pRTCP->hSessKey);
  501. #endif
  502. // release the RTCP session's heap
  503. if (pRTCP->hHeapRcvBfrList)
  504. {
  505. if (HeapDestroy (pRTCP->hHeapRcvBfrList) == FALSE)
  506. {
  507. RRCM_DBG_MSG ("RTCP: ERROR - HeapDestroy()",
  508. GetLastError(), __FILE__, __LINE__,
  509. DBG_ERROR);
  510. }
  511. }
  512. if (pRTCP->hHeapRcvBfr)
  513. {
  514. if (HeapDestroy (pRTCP->hHeapRcvBfr) == FALSE)
  515. {
  516. RRCM_DBG_MSG ("RTCP: ERROR - HeapDestroy()",
  517. GetLastError(), __FILE__, __LINE__,
  518. DBG_ERROR);
  519. }
  520. }
  521. if (pRTCP->XmtBfr.buf)
  522. LocalFree(pRTCP->XmtBfr.buf);
  523. // remove the entry from the list of RTCP session
  524. if (pTmp->next == NULL)
  525. removePcktFromHead (&pRTCPContext->RTCPSession,
  526. &pRTCPContext->critSect);
  527. else if (pTmp->prev == NULL)
  528. removePcktFromTail (&pRTCPContext->RTCPSession,
  529. &pRTCPContext->critSect);
  530. else
  531. {
  532. // in between, relink around
  533. (pTmp->prev)->next = pTmp->next;
  534. (pTmp->next)->prev = pTmp->prev;
  535. }
  536. // release the critical section
  537. LeaveCriticalSection (&pRTCP->critSect);
  538. DeleteCriticalSection (&pRTCP->critSect);
  539. // put the RTCP session back on its heap
  540. if (HeapFree (pRTCPContext->hHeapRTCPSes,
  541. 0,
  542. pRTCP) == FALSE)
  543. {
  544. RRCM_DBG_MSG ("RTCP: ERROR - HeapFree()",
  545. GetLastError(), __FILE__, __LINE__,
  546. DBG_ERROR);
  547. }
  548. break;
  549. }
  550. pTmp = pTmp->next;
  551. }
  552. if (sessionFound != TRUE)
  553. dwStatus = RRCMError_RTCPInvalidSession;
  554. IN_OUT_STR ("RTCP: Exit deleteRTCPSEssion()\n");
  555. return (dwStatus);
  556. }
  557. /*----------------------------------------------------------------------------
  558. * Function : CreateRTCPthread
  559. * Description: Create the RTCP thread / timeout thread depending on
  560. * compilation flag.
  561. *
  562. * Input : None.
  563. *
  564. * Return: None
  565. ---------------------------------------------------------------------------*/
  566. DWORD CreateRTCPthread (void)
  567. {
  568. DWORD dwStatus = RRCM_NoError;
  569. IN_OUT_STR ("RTCP: Enter CreateRTCPthread()\n");
  570. pRTCPContext->hTerminateRtcpEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  571. if (pRTCPContext->hTerminateRtcpEvent == NULL)
  572. {
  573. dwStatus = RRCMError_RTCPResources;
  574. RRCM_DBG_MSG ("RTCP: ERROR - CreateEvent()", GetLastError(),
  575. __FILE__, __LINE__, DBG_ERROR);
  576. }
  577. pRTCPContext->hRtcpRptRequestEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  578. if (pRTCPContext->hRtcpRptRequestEvent == NULL)
  579. {
  580. dwStatus = RRCMError_RTCPResources;
  581. RRCM_DBG_MSG ("RTCP: ERROR - CreateEvent()", GetLastError(),
  582. __FILE__, __LINE__, DBG_ERROR);
  583. }
  584. if (pRTCPContext->hTerminateRtcpEvent)
  585. {
  586. // create RTCP thread
  587. pRTCPContext->hRtcpThread = CreateThread (
  588. NULL,
  589. 0,
  590. (LPTHREAD_START_ROUTINE)RTCPThread,
  591. pRTCPContext,
  592. 0,
  593. &pRTCPContext->dwRtcpThreadID);
  594. if (pRTCPContext->hRtcpThread == FALSE)
  595. {
  596. dwStatus = RRCMError_RTCPThreadCreation;
  597. RRCM_DBG_MSG ("RTCP: ERROR - CreateThread()", GetLastError(),
  598. __FILE__, __LINE__, DBG_ERROR);
  599. }
  600. #ifdef _DEBUG
  601. else
  602. {
  603. wsprintf(debug_string,
  604. "RTCP: Create RTCP thread. Handle: x%p - ID: x%lX",
  605. pRTCPContext->hRtcpThread,
  606. pRTCPContext->dwRtcpThreadID);
  607. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  608. }
  609. #endif
  610. }
  611. IN_OUT_STR ("RTCP: Exit CreateRTCPthread()\n");
  612. return dwStatus;
  613. }
  614. /*----------------------------------------------------------------------------
  615. * Function : terminateRtcpThread
  616. * Description: Terminate the RTCP thread.
  617. *
  618. * Input : None.
  619. *
  620. * Return: None
  621. ---------------------------------------------------------------------------*/
  622. void terminateRtcpThread (void)
  623. {
  624. DWORD dwStatus;
  625. IN_OUT_STR ("RTCP: Enter terminateRtcpThread()\n");
  626. if (pRTCPContext->hRtcpThread)
  627. {
  628. // make sure the RTCP thread is running
  629. RTCPThreadCtrl (RTCP_ON);
  630. // signal the thread to terminate
  631. SetEvent (pRTCPContext->hTerminateRtcpEvent);
  632. // wait for the RTCP thread to be signaled
  633. dwStatus = WaitForSingleObject (pRTCPContext->hRtcpThread, 500);
  634. if (dwStatus == WAIT_OBJECT_0)
  635. ;
  636. else if ((dwStatus == WAIT_TIMEOUT) || (dwStatus == WAIT_FAILED))
  637. {
  638. if (dwStatus == WAIT_TIMEOUT)
  639. {
  640. RRCM_DBG_MSG ("RTCP: Wait timed-out", GetLastError(),
  641. __FILE__, __LINE__, DBG_ERROR);
  642. }
  643. else
  644. {
  645. RRCM_DBG_MSG ("RTCP: Wait failed", GetLastError(),
  646. __FILE__, __LINE__, DBG_ERROR);
  647. }
  648. // Force ungraceful thread termination
  649. dwStatus = TerminateThread (pRTCPContext->hRtcpThread, 1);
  650. if (dwStatus == FALSE)
  651. {
  652. RRCM_DBG_MSG ("RTCP: ERROR - TerminateThread ()",
  653. GetLastError(), __FILE__, __LINE__,
  654. DBG_ERROR);
  655. }
  656. }
  657. // close the thread handle
  658. dwStatus = CloseHandle (pRTCPContext->hRtcpThread);
  659. if (dwStatus == TRUE)
  660. pRTCPContext->hRtcpThread = 0;
  661. else
  662. {
  663. RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
  664. __FILE__, __LINE__, DBG_ERROR);
  665. }
  666. // close the event handle
  667. dwStatus = CloseHandle (pRTCPContext->hTerminateRtcpEvent);
  668. if (dwStatus == TRUE)
  669. pRTCPContext->hTerminateRtcpEvent = 0;
  670. else
  671. {
  672. RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
  673. __FILE__, __LINE__, DBG_ERROR);
  674. }
  675. // close the request handle
  676. dwStatus = CloseHandle (pRTCPContext->hRtcpRptRequestEvent);
  677. if (dwStatus == TRUE)
  678. pRTCPContext->hRtcpRptRequestEvent = 0;
  679. else
  680. {
  681. RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
  682. __FILE__, __LINE__, DBG_ERROR);
  683. }
  684. }
  685. IN_OUT_STR ("RTCP: Exit terminateRtcpThread()\n");
  686. }
  687. /*----------------------------------------------------------------------------
  688. * Function : RTCPflushIO
  689. * Description: Flush the receive queue.
  690. *
  691. * Input : pSSRC: -> to the SSRC entry
  692. *
  693. * Return: None
  694. ---------------------------------------------------------------------------*/
  695. DWORD RTCPflushIO (PSSRC_ENTRY pSSRC)
  696. {
  697. DWORD dwStatus = RRCM_NoError;
  698. int IoToFlush;
  699. int waitForXmtTrials;
  700. IN_OUT_STR ("RTCP: Enter RTCPflushIO()\n");
  701. // set the flush flag
  702. EnterCriticalSection (&pSSRC->pRTCPses->critSect);
  703. pSSRC->pRTCPses->dwSessionStatus |= SHUTDOWN_IN_PROGRESS;
  704. LeaveCriticalSection (&pSSRC->pRTCPses->critSect);
  705. // check if need to flush or close the socket
  706. if (pSSRC->dwSSRCStatus & CLOSE_RTCP_SOCKET)
  707. {
  708. // get the number of outstanding buffers
  709. IoToFlush = pSSRC->pRTCPses->dwNumRcvIoPending;
  710. #ifdef _DEBUG
  711. wsprintf(debug_string,
  712. "RTCPflushIO: closing socket(%d) dwNumRcvIoPending (%d)",
  713. pSSRC->RTCPsd, pSSRC->pRTCPses->dwNumRcvIoPending);
  714. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  715. #endif
  716. // make sure it's not < 0
  717. if (IoToFlush < 0)
  718. IoToFlush = pRTPContext->registry.NumRTCPPostedBfr;
  719. dwStatus = RRCMws.closesocket (pSSRC->RTCPsd);
  720. if (dwStatus != 0)
  721. {
  722. RRCM_DBG_MSG ("RTCP: ERROR - closesocket ()", GetLastError(),
  723. __FILE__, __LINE__, DBG_ERROR);
  724. }
  725. }
  726. else
  727. {
  728. IoToFlush = flushIO (pSSRC);
  729. }
  730. // wait for the receive side to flush it's pending I/Os
  731. if ((pSSRC->pRTCPses->dwSessionStatus & RTCP_ON) && IoToFlush)
  732. {
  733. // wait until the receiver signalled that the shutdown is done
  734. dwStatus = WaitForSingleObject (pSSRC->pRTCPses->hShutdownDone, 2000);
  735. if (dwStatus == WAIT_OBJECT_0)
  736. ;
  737. else if (dwStatus == WAIT_TIMEOUT)
  738. {
  739. RRCM_DBG_MSG ("RTCP: Flush Wait timed-out", 0,
  740. __FILE__, __LINE__, DBG_ERROR);
  741. }
  742. else if (dwStatus == WAIT_FAILED)
  743. {
  744. RRCM_DBG_MSG ("RTCP: Flush Wait failed", GetLastError(),
  745. __FILE__, __LINE__, DBG_ERROR);
  746. }
  747. }
  748. // make sure there is no buffers in transit on the transmit side
  749. waitForXmtTrials = 3;
  750. while (waitForXmtTrials--)
  751. {
  752. if (pSSRC->dwNumXmtIoPending == 0)
  753. break;
  754. RRCM_DBG_MSG ("RTCP: Xmt I/O Pending - Waiting",
  755. 0, NULL, 0, DBG_TRACE);
  756. // wait in an alertable wait-state
  757. SleepEx (200, TRUE);
  758. }
  759. // close the shutdown handle
  760. dwStatus = CloseHandle (pSSRC->pRTCPses->hShutdownDone);
  761. if (dwStatus == TRUE)
  762. pSSRC->pRTCPses->hShutdownDone = 0;
  763. else
  764. {
  765. RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
  766. __FILE__, __LINE__, DBG_ERROR);
  767. }
  768. IN_OUT_STR ("RTCP: Exit RTCPflushIO()\n");
  769. return (dwStatus);
  770. }
  771. /*----------------------------------------------------------------------------
  772. * Function : flushIO
  773. * Description: Flush the receive queue.
  774. *
  775. * Input : pSSRC: -> to the SSRC entry
  776. *
  777. * Return: None
  778. ---------------------------------------------------------------------------*/
  779. DWORD flushIO (PSSRC_ENTRY pSSRC)
  780. {
  781. SOCKET tSocket;
  782. SOCKADDR_IN tAddr;
  783. char msg[16];
  784. WSABUF msgBuf;
  785. DWORD BytesSent;
  786. int tmpSize;
  787. DWORD dwStatus = RRCM_NoError;
  788. int outstanding;
  789. int IoToFlush;
  790. RTCP_COMMON_T *pRTCPhdr;
  791. IN_OUT_STR ("RTCP: Enter flushIO()\n");
  792. // target socket
  793. tSocket = pSSRC->RTCPsd;
  794. // RTCP common header
  795. pRTCPhdr = (RTCP_COMMON_T *)msg;
  796. // RTP protocol version
  797. pRTCPhdr->type = RTP_TYPE;
  798. pRTCPhdr->pt = FLUSH_RTP_PAYLOAD_TYPE;
  799. msgBuf.len = sizeof(msg);
  800. msgBuf.buf = msg;
  801. // get the address of the socket we are cleaning up
  802. tmpSize = sizeof(tAddr);
  803. if (RRCMws.getsockname (tSocket, (PSOCKADDR)&tAddr, &tmpSize))
  804. {
  805. dwStatus = GetLastError();
  806. RRCM_DBG_MSG ("RTCP: ERROR - getsockname()",
  807. dwStatus, __FILE__, __LINE__, DBG_ERROR);
  808. IN_OUT_STR ("RTP : Exit flushIO()\n");
  809. // (was: return dwStatus;)
  810. // Since this function is supposed to return number of pending I/O requests
  811. // to this socket, returning a non-zero error here is BOGUS!
  812. // Just return zero because if there is an error (socket has been freed)
  813. // then just say there's no i/o pending.
  814. return 0;
  815. }
  816. if (tAddr.sin_addr.s_addr == 0)
  817. {
  818. // send to the local address
  819. tAddr.sin_addr.S_un.S_un_b.s_b1 = 127;
  820. tAddr.sin_addr.S_un.S_un_b.s_b2 = 0;
  821. tAddr.sin_addr.S_un.S_un_b.s_b3 = 0;
  822. tAddr.sin_addr.S_un.S_un_b.s_b4 = 1;
  823. }
  824. // get the number of outstanding buffers
  825. outstanding = pSSRC->pRTCPses->dwNumRcvIoPending;
  826. // make sure it's not < 0
  827. if (outstanding < 0)
  828. outstanding = pRTPContext->registry.NumRTCPPostedBfr;
  829. // save number of pending I/Os
  830. IoToFlush = outstanding;
  831. #if _DEBUG
  832. wsprintf(debug_string,
  833. "RTCP: Flushing %d outstanding RCV buffers", outstanding);
  834. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  835. #endif
  836. // send datagrams to the RTCP socket
  837. while (outstanding--)
  838. {
  839. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  840. if (RTPLogger)
  841. {
  842. //INTEROP
  843. InteropOutput (RTPLogger,
  844. (BYTE FAR*)msgBuf.buf,
  845. (int)msgBuf.len,
  846. RTPLOG_SENT_PDU | RTCP_PDU);
  847. }
  848. #endif
  849. dwStatus = RRCMws.sendTo (tSocket,
  850. &msgBuf,
  851. 1,
  852. &BytesSent,
  853. 0,
  854. (SOCKADDR *)&tAddr,
  855. sizeof(tAddr),
  856. NULL,
  857. #if 1
  858. NULL);
  859. #else
  860. RTCPflushCallback);
  861. #endif
  862. if (dwStatus == SOCKET_ERROR)
  863. {
  864. // If serious error, undo all our work
  865. dwStatus = GetLastError();
  866. if (dwStatus != WSA_IO_PENDING)
  867. {
  868. RRCM_DBG_MSG ("RTCP: ERROR - sendTo()", dwStatus,
  869. __FILE__, __LINE__, DBG_ERROR);
  870. }
  871. }
  872. }
  873. IN_OUT_STR ("RTCP: Exit flushIO()\n");
  874. return IoToFlush;
  875. }
  876. /*----------------------------------------------------------------------------
  877. * Function : RTCPflushCallback
  878. * Description: Flush callback routine
  879. *
  880. * Input : dwError: I/O completion status
  881. * cbTransferred: Number of bytes received
  882. * lpOverlapped: -> to overlapped structure
  883. * dwFlags: Flags
  884. *
  885. *
  886. * Return: None
  887. ---------------------------------------------------------------------------*/
  888. void CALLBACK RTCPflushCallback (DWORD dwError,
  889. DWORD cbTransferred,
  890. LPWSAOVERLAPPED lpOverlapped,
  891. DWORD dwFlags)
  892. {
  893. IN_OUT_STR ("RTCP: Enter RTCPflushCallback\n");
  894. // check Winsock callback error status
  895. if (dwError)
  896. {
  897. RRCM_DBG_MSG ("RTCP: ERROR - Rcv Callback", dwError,
  898. __FILE__, __LINE__, DBG_ERROR);
  899. IN_OUT_STR ("RTCP: Exit RTCPflushCallback\n");
  900. return;
  901. }
  902. IN_OUT_STR ("RTCP: Exit RTCPflushCallback\n");
  903. }
  904. // [EOF]