1095 lines
30 KiB
C++
1095 lines
30 KiB
C++
/*----------------------------------------------------------------------------
|
|
* File: RTCPSESS.C
|
|
* Product: RTP/RTCP implementation
|
|
* Description: Provides RTCP session management.
|
|
*
|
|
* INTEL Corporation Proprietary Information
|
|
* This listing is supplied under the terms of a license agreement with
|
|
* Intel Corporation and may not be copied nor disclosed except in
|
|
* accordance with the terms of that agreement.
|
|
* Copyright (c) 1995 Intel Corporation.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
|
|
#include "rrcm.h"
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
/ Global Variables
|
|
/--------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
/ External Variables
|
|
/--------------------------------------------------------------------------*/
|
|
extern PRTCP_CONTEXT pRTCPContext;
|
|
extern PRTP_CONTEXT pRTPContext;
|
|
extern RRCM_WS RRCMws;
|
|
|
|
#ifdef ENABLE_ISDM2
|
|
extern ISDM2 Isdm2;
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
extern char debug_string[];
|
|
#endif
|
|
|
|
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
|
|
//INTEROP
|
|
extern LPInteropLogger RTPLogger;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : CreateRTCPSession
|
|
* Description: Creates an RTCP session.
|
|
*
|
|
* Input : RTPsd : RTP socket descriptor
|
|
* RTCPsd : RTCP socket descriptor
|
|
* lpTo : To address
|
|
* toLen : To address length
|
|
* pSdesInfo : -> to SDES information
|
|
* dwStreamClock : Stream clocking frequency
|
|
* pEncryptInfo : -> to encryption information
|
|
* ssrc : If set, user selected SSRC
|
|
* pSSRCcallback : Callback for user's selected SSRC
|
|
* dwCallbackInfo : User callback information
|
|
* miscInfo : Miscelleanous information:
|
|
* H.323Conf: 0x00000002
|
|
* Encrypt SR/RR: 0x00000004
|
|
* RTCPon: 0x00000008
|
|
* dwRtpSessionBw : RTP session bandwidth used for RTCP BW
|
|
* *pRTCPStatus : -> to status information
|
|
*
|
|
* Return: NULL : Couldn't create RTCP session
|
|
* !0 : RTCP session's address
|
|
---------------------------------------------------------------------------*/
|
|
PRTCP_SESSION CreateRTCPSession (SOCKET RTPsd,
|
|
SOCKET RTCPsd,
|
|
LPVOID lpTo,
|
|
DWORD toLen,
|
|
PSDES_DATA pSdesInfo,
|
|
DWORD dwStreamClock,
|
|
PENCRYPT_INFO pEncryptInfo,
|
|
DWORD ssrc,
|
|
PRRCM_EVENT_CALLBACK pRRCMcallback,
|
|
DWORD_PTR dwCallbackInfo,
|
|
DWORD miscInfo,
|
|
DWORD dwRtpSessionBw,
|
|
DWORD *pRTCPstatus)
|
|
{
|
|
PRTCP_SESSION pRTCPses = NULL;
|
|
PSSRC_ENTRY pSSRCentry = NULL;
|
|
DWORD dwStatus = RRCM_NoError;
|
|
DWORD startRtcp = FALSE;
|
|
char hName[256];
|
|
int tmpSize;
|
|
struct sockaddr_in *pSockAddr;
|
|
|
|
IN_OUT_STR ("RTCP: Enter CreateRTCPSession()\n");
|
|
|
|
// set status
|
|
*pRTCPstatus = RRCM_NoError;
|
|
|
|
// allocate all required resources for the RTCP session
|
|
dwStatus = allocateRTCPsessionResources (&pRTCPses,
|
|
&pSSRCentry);
|
|
if (dwStatus != RRCM_NoError)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - Resource allocation failed", 0,
|
|
__FILE__, __LINE__, DBG_CRITICAL);
|
|
|
|
IN_OUT_STR ("RTCP: Exit CreateRTCPSession()\n");
|
|
|
|
*pRTCPstatus = dwStatus;
|
|
return (NULL);
|
|
}
|
|
|
|
// if this is the first session, create the RTCP thread, which
|
|
// will be killed when no more sessions exist.
|
|
if (pRTCPContext->RTCPSession.prev == NULL)
|
|
{
|
|
startRtcp = TRUE;
|
|
}
|
|
|
|
// save the parent RTCP session address in the SSRC entry
|
|
pSSRCentry->pRTCPses = pRTCPses;
|
|
|
|
// network destination address
|
|
if (toLen)
|
|
{
|
|
pRTCPses->dwSessionStatus = RTCP_DEST_LEARNED;
|
|
pRTCPses->toLen = toLen;
|
|
memcpy (&pRTCPses->toBfr, lpTo, toLen);
|
|
}
|
|
|
|
// mark the session as new for the benefit of the RTCP thread
|
|
pRTCPses->dwSessionStatus |= NEW_RTCP_SESSION;
|
|
|
|
#ifdef ENABLE_ISDM2
|
|
// initialize the session key in case ISDM is used
|
|
pRTCPses->hSessKey = NULL;
|
|
#endif
|
|
|
|
// number of SSRC for this RTCP session
|
|
pRTCPses->dwCurNumSSRCperSes = 1;
|
|
#ifdef MONITOR_STATS
|
|
pRTCPses->dwHiNumSSRCperSes = 1;
|
|
#endif
|
|
|
|
// SSRC entry related information
|
|
pSSRCentry->RTPsd = RTPsd;
|
|
pSSRCentry->RTCPsd = RTCPsd;
|
|
|
|
// get our own transport address -
|
|
// will be used for collision resolution when using multicast
|
|
tmpSize = sizeof (SOCKADDR);
|
|
dwStatus = RRCMws.getsockname (RTPsd, (PSOCKADDR)pSSRCentry->from, &tmpSize);
|
|
|
|
// only process when no error is reported. If the socket is not bound
|
|
// it won't cause any problem for unicast or multicast if the sender
|
|
// has not join the mcast group. If the sender joins the mcast group
|
|
// it's socket should be bound by now as specified in the EPS
|
|
if (dwStatus == 0)
|
|
{
|
|
// if bound to INADDR_ANY, address will be 0
|
|
pSockAddr = (PSOCKADDR_IN)&pSSRCentry->from;
|
|
if (pSockAddr->sin_addr.s_addr == 0)
|
|
{
|
|
// get the host name (to get the local IP address)
|
|
if ( ! RRCMws.gethostname (hName, sizeof(hName)))
|
|
{
|
|
LPHOSTENT lpHEnt;
|
|
|
|
// get the host by name infor
|
|
if ((lpHEnt = RRCMws.gethostbyname (hName)) != NULL)
|
|
{
|
|
// get the local IP address
|
|
pSockAddr->sin_addr.s_addr =
|
|
*((u_long *)lpHEnt->h_addr_list[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// build session's SDES information
|
|
buildSDESinfo (pSSRCentry, pSdesInfo);
|
|
|
|
// link the SSRC to the RTCP session list of Xmt SSRCs entries
|
|
addToHeadOfList (&(pRTCPses->XmtSSRCList),
|
|
(PLINK_LIST)pSSRCentry,
|
|
&pRTCPses->critSect);
|
|
|
|
// initialize the number of stream for this session
|
|
pRTCPses->dwNumStreamPerSes = 1;
|
|
|
|
// get a unique SSRC for this session
|
|
if (ssrc)
|
|
pSSRCentry->SSRC = ssrc;
|
|
else
|
|
pSSRCentry->SSRC = getSSRC (pRTCPses->XmtSSRCList,
|
|
pRTCPses->RcvSSRCList);
|
|
|
|
// RRCM callback notification
|
|
pRTCPses->pRRCMcallback = pRRCMcallback;
|
|
pRTCPses->dwCallbackUserInfo = dwCallbackInfo;
|
|
|
|
// set operation flag
|
|
if (miscInfo & H323_CONFERENCE)
|
|
pRTCPses->dwSessionStatus |= H323_CONFERENCE;
|
|
if (miscInfo & ENCRYPT_SR_RR)
|
|
pRTCPses->dwSessionStatus |= ENCRYPT_SR_RR;
|
|
|
|
// estimate the initial session bandwidth
|
|
if (dwRtpSessionBw == 0)
|
|
{
|
|
pSSRCentry->xmtInfo.dwRtcpStreamMinBW = INITIAL_RTCP_BANDWIDTH;
|
|
}
|
|
else
|
|
{
|
|
// RTCP bandwidth is 5% of the RTP bandwidth
|
|
pSSRCentry->xmtInfo.dwRtcpStreamMinBW = (dwRtpSessionBw * 5) / 100;
|
|
}
|
|
|
|
// the stream clocking frequency
|
|
pSSRCentry->dwStreamClock = dwStreamClock;
|
|
|
|
// initialize 'dwLastReportRcvdTime' to now
|
|
pSSRCentry->dwLastReportRcvdTime = timeGetTime();
|
|
|
|
#ifdef _DEBUG
|
|
wsprintf(debug_string,
|
|
"RTCP: Add new RTCP session: Addr:x%p", pRTCPses);
|
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|
|
|
wsprintf(debug_string,
|
|
"RTCP: Add SSRC entry (Addr:x%p, SSRC=x%lX) to session (Addr:x%p)",
|
|
pSSRCentry, pSSRCentry->SSRC, pRTCPses);
|
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|
|
|
pSSRCentry->dwPrvTime = timeGetTime();
|
|
#endif
|
|
|
|
// turn on RTCP or not
|
|
if (miscInfo & RTCP_ON)
|
|
{
|
|
// this session sends and receives RTCP reports
|
|
pRTCPses->dwSessionStatus |= RTCP_ON;
|
|
}
|
|
|
|
// link the RTCP session to the head of the list of RTCP sessions
|
|
addToHeadOfList (&(pRTCPContext->RTCPSession),
|
|
(PLINK_LIST)pRTCPses,
|
|
&pRTCPContext->critSect);
|
|
|
|
#ifdef ENABLE_ISDM2
|
|
// register to ISDM only if destination address is known
|
|
if (Isdm2.hISDMdll && (pRTCPses->dwSessionStatus & RTCP_DEST_LEARNED))
|
|
registerSessionToISDM (pSSRCentry, pRTCPses, &Isdm2);
|
|
#endif
|
|
|
|
// create the RTCP thread if needed
|
|
if (startRtcp == TRUE)
|
|
{
|
|
// No RTCP thread if this fail
|
|
dwStatus = CreateRTCPthread ();
|
|
if (dwStatus != RRCM_NoError)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - Cannot create RTCP thread", 0,
|
|
__FILE__, __LINE__, DBG_CRITICAL);
|
|
|
|
IN_OUT_STR ("RTCP: Exit CreateRTCPSession()\n");
|
|
|
|
*pRTCPstatus = dwStatus;
|
|
return (NULL);
|
|
}
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit CreateRTCPSession()\n");
|
|
|
|
return (pRTCPses);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : allocateRTCPsessionResources
|
|
* Description: Allocate all required resources for an RTCP session.
|
|
*
|
|
* Input : *pRTCPses: ->(->) to the RTCP session's information
|
|
* *pSSRCentry: ->(->) to the SSRC's entry
|
|
*
|
|
* Return: OK: RRCM_NoError
|
|
* !0: Error code (see RRCM.H)
|
|
---------------------------------------------------------------------------*/
|
|
DWORD allocateRTCPsessionResources (PRTCP_SESSION *pRTCPses,
|
|
PSSRC_ENTRY *pSSRCentry)
|
|
{
|
|
DWORD dwStatus = RRCM_NoError;
|
|
|
|
IN_OUT_STR ("RTCP: Enter allocateRTCPsessionResources()\n");
|
|
|
|
// get an RTCP session
|
|
*pRTCPses = (PRTCP_SESSION)HeapAlloc (pRTCPContext->hHeapRTCPSes,
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(RTCP_SESSION));
|
|
if (*pRTCPses == NULL)
|
|
dwStatus = RRCMError_RTCPResources;
|
|
|
|
// 'defined' RTCP resources
|
|
if (dwStatus == RRCM_NoError)
|
|
{
|
|
(*pRTCPses)->dwInitNumFreeRcvBfr = NUM_FREE_RCV_BFR;
|
|
(*pRTCPses)->dwRcvBfrSize = pRTPContext->registry.RTCPrcvBfrSize;
|
|
(*pRTCPses)->dwXmtBfrSize = RRCM_XMT_BFR_SIZE;
|
|
|
|
// allocate the RTCP session's Rcv/Xmt heaps and Rcv/Xmt buffers
|
|
dwStatus = allocateRTCPSessionHeaps (pRTCPses);
|
|
}
|
|
|
|
if (dwStatus == RRCM_NoError)
|
|
{
|
|
// initialize this session's critical section
|
|
InitializeCriticalSection (&(*pRTCPses)->critSect);
|
|
|
|
// allocate free list of RTCP receive buffers
|
|
dwStatus = allocateRTCPBfrList (&(*pRTCPses)->RTCPrcvBfrList,
|
|
(*pRTCPses)->hHeapRcvBfrList,
|
|
(*pRTCPses)->hHeapRcvBfr,
|
|
&(*pRTCPses)->dwInitNumFreeRcvBfr,
|
|
(*pRTCPses)->dwRcvBfrSize,
|
|
&(*pRTCPses)->critSect);
|
|
}
|
|
|
|
if (dwStatus == RRCM_NoError)
|
|
{
|
|
(*pRTCPses)->XmtBfr.buf = (char *)LocalAlloc(0,(*pRTCPses)->dwXmtBfrSize);
|
|
if ((*pRTCPses)->XmtBfr.buf == NULL)
|
|
dwStatus = RRCMError_RTCPResources;
|
|
|
|
}
|
|
|
|
if (dwStatus == RRCM_NoError)
|
|
{
|
|
// get an SSRC entry
|
|
*pSSRCentry = getOneSSRCentry (&pRTCPContext->RRCMFreeStat,
|
|
pRTCPContext->hHeapRRCMStat,
|
|
&pRTCPContext->dwInitNumFreeRRCMStat,
|
|
&pRTCPContext->critSect);
|
|
if (*pSSRCentry == NULL)
|
|
dwStatus = RRCMError_RTCPResources;
|
|
}
|
|
|
|
if (dwStatus == RRCM_NoError)
|
|
{
|
|
// manual-reset event that will be used to signal the end of the
|
|
// RTCP session to all of the session's stream
|
|
(*pRTCPses)->hShutdownDone = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
|
|
if ((*pRTCPses)->hShutdownDone == NULL)
|
|
{
|
|
dwStatus = RRCMError_RTCPResources;
|
|
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CreateEvent()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
// any resource allocation problem ?
|
|
if (dwStatus != RRCM_NoError)
|
|
{
|
|
if (*pSSRCentry)
|
|
addToHeadOfList (&pRTCPContext->RRCMFreeStat,
|
|
(PLINK_LIST)*pSSRCentry,
|
|
&pRTCPContext->critSect);
|
|
|
|
if ((*pSSRCentry)->hXmtThread)
|
|
{
|
|
if (TerminateThread ((*pSSRCentry)->hXmtThread,
|
|
(*pSSRCentry)->dwXmtThreadID) == FALSE)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - TerminateThread()",
|
|
GetLastError(), __FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
if (*pRTCPses)
|
|
{
|
|
if (HeapFree (pRTCPContext->hHeapRTCPSes, 0, *pRTCPses) == FALSE)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - HeapFree()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit allocateRTCPsessionResources()\n");
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : buildSDESinfo
|
|
* Description: Build the session's SDES information
|
|
*
|
|
* Input : pRTCPses: -> to session's
|
|
* pSdesInfo: -> to SDES information
|
|
*
|
|
* Return: OK: RRCM_NoError
|
|
* !0: Error code (see RRCM.H)
|
|
---------------------------------------------------------------------------*/
|
|
DWORD buildSDESinfo (PSSRC_ENTRY pSSRCentry,
|
|
PSDES_DATA pSdesInfo)
|
|
{
|
|
PSDES_DATA pTmpSdes;
|
|
DWORD CnameOK = FALSE;
|
|
|
|
IN_OUT_STR ("RTCP: Enter buildSDESinfo()\n");
|
|
|
|
pTmpSdes = pSdesInfo;
|
|
|
|
while (pTmpSdes->dwSdesType)
|
|
{
|
|
switch (pTmpSdes->dwSdesType)
|
|
{
|
|
case RTCP_SDES_CNAME:
|
|
pSSRCentry->cnameInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->cnameInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->cnameInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->cnameInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
|
|
CnameOK = TRUE;
|
|
break;
|
|
|
|
case RTCP_SDES_NAME:
|
|
pSSRCentry->nameInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->nameInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->nameInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->nameInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
|
|
case RTCP_SDES_EMAIL:
|
|
pSSRCentry->emailInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->emailInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->emailInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->emailInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
|
|
case RTCP_SDES_PHONE:
|
|
pSSRCentry->phoneInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->phoneInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->phoneInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->phoneInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
|
|
case RTCP_SDES_LOC:
|
|
pSSRCentry->locInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->locInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->locInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->locInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
|
|
case RTCP_SDES_TOOL:
|
|
pSSRCentry->toolInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->toolInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->toolInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->toolInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
|
|
case RTCP_SDES_TXT:
|
|
pSSRCentry->txtInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->txtInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->txtInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->txtInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
|
|
case RTCP_SDES_PRIV:
|
|
pSSRCentry->privInfo.dwSdesLength = pTmpSdes->dwSdesLength;
|
|
memcpy (pSSRCentry->privInfo.sdesBfr, pTmpSdes->sdesBfr,
|
|
pTmpSdes->dwSdesLength);
|
|
|
|
pSSRCentry->privInfo.dwSdesFrequency =
|
|
frequencyToPckt (pTmpSdes->dwSdesFrequency);
|
|
pSSRCentry->privInfo.dwSdesEncrypted = pTmpSdes->dwSdesEncrypted;
|
|
break;
|
|
}
|
|
|
|
pTmpSdes++;
|
|
}
|
|
|
|
// default CNAME if none provided
|
|
if (CnameOK == FALSE)
|
|
{
|
|
pSSRCentry->cnameInfo.dwSdesLength = sizeof(szDfltCname);
|
|
memcpy (pSSRCentry->cnameInfo.sdesBfr, szDfltCname,
|
|
sizeof(szDfltCname));
|
|
|
|
pSSRCentry->cnameInfo.dwSdesFrequency = 1;
|
|
pSSRCentry->cnameInfo.dwSdesEncrypted = 0;
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit buildSDESinfo()\n");
|
|
return (RRCM_NoError);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : frequencyToPckt
|
|
* Description: Transform the required frequency to a number of packet. (To
|
|
* be used by a modulo function)
|
|
*
|
|
* Input : freq: Desired frequency from 0 to 100
|
|
*
|
|
* Return: X: Packet to skip, ie, one out of X
|
|
---------------------------------------------------------------------------*/
|
|
DWORD frequencyToPckt (DWORD freq)
|
|
{
|
|
if (freq <= 10)
|
|
return 9;
|
|
else if (freq <= 20)
|
|
return 5;
|
|
else if (freq <= 25)
|
|
return 4;
|
|
else if (freq <= 33)
|
|
return 3;
|
|
else if (freq <= 50)
|
|
return 2;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : deleteRTCPSession
|
|
* Description: Closes an RTCP session.
|
|
*
|
|
* Input : RTCPsd : RTCP socket descriptor
|
|
* byeReason : -> to the BYE reason
|
|
*
|
|
* Return: OK: RRCM_NoError
|
|
* !0: Error code (see RRCM.H)
|
|
---------------------------------------------------------------------------*/
|
|
DWORD deleteRTCPSession (SOCKET RTCPsd,
|
|
PCHAR byeReason)
|
|
{
|
|
PLINK_LIST pTmp;
|
|
PSSRC_ENTRY pSSRC;
|
|
PRTCP_SESSION pRTCP;
|
|
DWORD dwStatus = RRCM_NoError;
|
|
DWORD sessionFound = FALSE;
|
|
|
|
IN_OUT_STR ("RTCP: Enter deleteRTCPSEssion()\n");
|
|
|
|
// walk through the list from the tail
|
|
pTmp = pRTCPContext->RTCPSession.prev;
|
|
|
|
#ifdef _DEBUG
|
|
wsprintf(debug_string,
|
|
"RTCP: Deleting RTCP session: (Addr:x%p) ...", pTmp);
|
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|
#endif
|
|
|
|
while (pTmp)
|
|
{
|
|
// get the right session to close by walking the transmit list
|
|
pSSRC = (PSSRC_ENTRY)((PRTCP_SESSION)pTmp)->XmtSSRCList.prev;
|
|
if (pSSRC->RTCPsd == RTCPsd)
|
|
{
|
|
sessionFound = TRUE;
|
|
|
|
// save a pointer to the RTCP session
|
|
pRTCP = pSSRC->pRTCPses;
|
|
|
|
// RTCP send BYE packet for this active stream
|
|
RTCPsendBYE (pSSRC, NULL);
|
|
|
|
// flush out any outstanding I/O
|
|
RTCPflushIO (pSSRC);
|
|
|
|
// if this is the only RTCP session left, terminate the RTCP
|
|
// timeout thread, so it doesn't access the session when it expires
|
|
if ((pRTCPContext->RTCPSession.prev)->next == NULL)
|
|
terminateRtcpThread ();
|
|
|
|
// lock out access to this RTCP session
|
|
EnterCriticalSection (&pRTCP->critSect);
|
|
|
|
// free all Rcv & Xmt SSRC entries used by this session
|
|
deleteSSRClist (pRTCP,
|
|
&pRTCPContext->RRCMFreeStat,
|
|
pRTCPContext);
|
|
|
|
#ifdef ENABLE_ISDM2
|
|
if (Isdm2.hISDMdll && pRTCP->hSessKey)
|
|
Isdm2.ISDMEntry.ISD_DeleteKey(pRTCP->hSessKey);
|
|
#endif
|
|
|
|
// release the RTCP session's heap
|
|
if (pRTCP->hHeapRcvBfrList)
|
|
{
|
|
if (HeapDestroy (pRTCP->hHeapRcvBfrList) == FALSE)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - HeapDestroy()",
|
|
GetLastError(), __FILE__, __LINE__,
|
|
DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
|
|
if (pRTCP->hHeapRcvBfr)
|
|
{
|
|
if (HeapDestroy (pRTCP->hHeapRcvBfr) == FALSE)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - HeapDestroy()",
|
|
GetLastError(), __FILE__, __LINE__,
|
|
DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
|
|
if (pRTCP->XmtBfr.buf)
|
|
LocalFree(pRTCP->XmtBfr.buf);
|
|
// remove the entry from the list of RTCP session
|
|
if (pTmp->next == NULL)
|
|
removePcktFromHead (&pRTCPContext->RTCPSession,
|
|
&pRTCPContext->critSect);
|
|
else if (pTmp->prev == NULL)
|
|
removePcktFromTail (&pRTCPContext->RTCPSession,
|
|
&pRTCPContext->critSect);
|
|
else
|
|
{
|
|
// in between, relink around
|
|
(pTmp->prev)->next = pTmp->next;
|
|
(pTmp->next)->prev = pTmp->prev;
|
|
}
|
|
|
|
// release the critical section
|
|
LeaveCriticalSection (&pRTCP->critSect);
|
|
DeleteCriticalSection (&pRTCP->critSect);
|
|
|
|
// put the RTCP session back on its heap
|
|
if (HeapFree (pRTCPContext->hHeapRTCPSes,
|
|
0,
|
|
pRTCP) == FALSE)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - HeapFree()",
|
|
GetLastError(), __FILE__, __LINE__,
|
|
DBG_ERROR);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
pTmp = pTmp->next;
|
|
}
|
|
|
|
if (sessionFound != TRUE)
|
|
dwStatus = RRCMError_RTCPInvalidSession;
|
|
|
|
IN_OUT_STR ("RTCP: Exit deleteRTCPSEssion()\n");
|
|
|
|
return (dwStatus);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : CreateRTCPthread
|
|
* Description: Create the RTCP thread / timeout thread depending on
|
|
* compilation flag.
|
|
*
|
|
* Input : None.
|
|
*
|
|
* Return: None
|
|
---------------------------------------------------------------------------*/
|
|
DWORD CreateRTCPthread (void)
|
|
{
|
|
DWORD dwStatus = RRCM_NoError;
|
|
|
|
IN_OUT_STR ("RTCP: Enter CreateRTCPthread()\n");
|
|
|
|
pRTCPContext->hTerminateRtcpEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
if (pRTCPContext->hTerminateRtcpEvent == NULL)
|
|
{
|
|
dwStatus = RRCMError_RTCPResources;
|
|
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CreateEvent()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
|
|
pRTCPContext->hRtcpRptRequestEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
if (pRTCPContext->hRtcpRptRequestEvent == NULL)
|
|
{
|
|
dwStatus = RRCMError_RTCPResources;
|
|
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CreateEvent()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
|
|
if (pRTCPContext->hTerminateRtcpEvent)
|
|
{
|
|
// create RTCP thread
|
|
pRTCPContext->hRtcpThread = CreateThread (
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)RTCPThread,
|
|
pRTCPContext,
|
|
0,
|
|
&pRTCPContext->dwRtcpThreadID);
|
|
|
|
if (pRTCPContext->hRtcpThread == FALSE)
|
|
{
|
|
dwStatus = RRCMError_RTCPThreadCreation;
|
|
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CreateThread()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
{
|
|
wsprintf(debug_string,
|
|
"RTCP: Create RTCP thread. Handle: x%p - ID: x%lX",
|
|
pRTCPContext->hRtcpThread,
|
|
pRTCPContext->dwRtcpThreadID);
|
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit CreateRTCPthread()\n");
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : terminateRtcpThread
|
|
* Description: Terminate the RTCP thread.
|
|
*
|
|
* Input : None.
|
|
*
|
|
* Return: None
|
|
---------------------------------------------------------------------------*/
|
|
void terminateRtcpThread (void)
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
IN_OUT_STR ("RTCP: Enter terminateRtcpThread()\n");
|
|
|
|
if (pRTCPContext->hRtcpThread)
|
|
{
|
|
// make sure the RTCP thread is running
|
|
RTCPThreadCtrl (RTCP_ON);
|
|
|
|
// signal the thread to terminate
|
|
SetEvent (pRTCPContext->hTerminateRtcpEvent);
|
|
|
|
// wait for the RTCP thread to be signaled
|
|
dwStatus = WaitForSingleObject (pRTCPContext->hRtcpThread, 500);
|
|
if (dwStatus == WAIT_OBJECT_0)
|
|
;
|
|
else if ((dwStatus == WAIT_TIMEOUT) || (dwStatus == WAIT_FAILED))
|
|
{
|
|
if (dwStatus == WAIT_TIMEOUT)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: Wait timed-out", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
else
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: Wait failed", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
|
|
// Force ungraceful thread termination
|
|
dwStatus = TerminateThread (pRTCPContext->hRtcpThread, 1);
|
|
if (dwStatus == FALSE)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - TerminateThread ()",
|
|
GetLastError(), __FILE__, __LINE__,
|
|
DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
// close the thread handle
|
|
dwStatus = CloseHandle (pRTCPContext->hRtcpThread);
|
|
if (dwStatus == TRUE)
|
|
pRTCPContext->hRtcpThread = 0;
|
|
else
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
|
|
// close the event handle
|
|
dwStatus = CloseHandle (pRTCPContext->hTerminateRtcpEvent);
|
|
if (dwStatus == TRUE)
|
|
pRTCPContext->hTerminateRtcpEvent = 0;
|
|
else
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
|
|
// close the request handle
|
|
dwStatus = CloseHandle (pRTCPContext->hRtcpRptRequestEvent);
|
|
if (dwStatus == TRUE)
|
|
pRTCPContext->hRtcpRptRequestEvent = 0;
|
|
else
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit terminateRtcpThread()\n");
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : RTCPflushIO
|
|
* Description: Flush the receive queue.
|
|
*
|
|
* Input : pSSRC: -> to the SSRC entry
|
|
*
|
|
* Return: None
|
|
---------------------------------------------------------------------------*/
|
|
DWORD RTCPflushIO (PSSRC_ENTRY pSSRC)
|
|
{
|
|
DWORD dwStatus = RRCM_NoError;
|
|
int IoToFlush;
|
|
int waitForXmtTrials;
|
|
|
|
IN_OUT_STR ("RTCP: Enter RTCPflushIO()\n");
|
|
|
|
// set the flush flag
|
|
EnterCriticalSection (&pSSRC->pRTCPses->critSect);
|
|
pSSRC->pRTCPses->dwSessionStatus |= SHUTDOWN_IN_PROGRESS;
|
|
LeaveCriticalSection (&pSSRC->pRTCPses->critSect);
|
|
|
|
// check if need to flush or close the socket
|
|
if (pSSRC->dwSSRCStatus & CLOSE_RTCP_SOCKET)
|
|
{
|
|
// get the number of outstanding buffers
|
|
IoToFlush = pSSRC->pRTCPses->dwNumRcvIoPending;
|
|
#ifdef _DEBUG
|
|
wsprintf(debug_string,
|
|
"RTCPflushIO: closing socket(%d) dwNumRcvIoPending (%d)",
|
|
pSSRC->RTCPsd, pSSRC->pRTCPses->dwNumRcvIoPending);
|
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|
#endif
|
|
|
|
// make sure it's not < 0
|
|
if (IoToFlush < 0)
|
|
IoToFlush = pRTPContext->registry.NumRTCPPostedBfr;
|
|
|
|
dwStatus = RRCMws.closesocket (pSSRC->RTCPsd);
|
|
if (dwStatus != 0)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - closesocket ()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IoToFlush = flushIO (pSSRC);
|
|
}
|
|
|
|
// wait for the receive side to flush it's pending I/Os
|
|
if ((pSSRC->pRTCPses->dwSessionStatus & RTCP_ON) && IoToFlush)
|
|
{
|
|
// wait until the receiver signalled that the shutdown is done
|
|
dwStatus = WaitForSingleObject (pSSRC->pRTCPses->hShutdownDone, 2000);
|
|
if (dwStatus == WAIT_OBJECT_0)
|
|
;
|
|
else if (dwStatus == WAIT_TIMEOUT)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: Flush Wait timed-out", 0,
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
else if (dwStatus == WAIT_FAILED)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: Flush Wait failed", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
|
|
// make sure there is no buffers in transit on the transmit side
|
|
waitForXmtTrials = 3;
|
|
while (waitForXmtTrials--)
|
|
{
|
|
if (pSSRC->dwNumXmtIoPending == 0)
|
|
break;
|
|
|
|
RRCM_DBG_MSG ("RTCP: Xmt I/O Pending - Waiting",
|
|
0, NULL, 0, DBG_TRACE);
|
|
|
|
// wait in an alertable wait-state
|
|
SleepEx (200, TRUE);
|
|
}
|
|
|
|
// close the shutdown handle
|
|
dwStatus = CloseHandle (pSSRC->pRTCPses->hShutdownDone);
|
|
if (dwStatus == TRUE)
|
|
pSSRC->pRTCPses->hShutdownDone = 0;
|
|
else
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - CloseHandle()", GetLastError(),
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit RTCPflushIO()\n");
|
|
|
|
return (dwStatus);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : flushIO
|
|
* Description: Flush the receive queue.
|
|
*
|
|
* Input : pSSRC: -> to the SSRC entry
|
|
*
|
|
* Return: None
|
|
---------------------------------------------------------------------------*/
|
|
DWORD flushIO (PSSRC_ENTRY pSSRC)
|
|
{
|
|
SOCKET tSocket;
|
|
SOCKADDR_IN tAddr;
|
|
char msg[16];
|
|
WSABUF msgBuf;
|
|
DWORD BytesSent;
|
|
int tmpSize;
|
|
DWORD dwStatus = RRCM_NoError;
|
|
int outstanding;
|
|
int IoToFlush;
|
|
RTCP_COMMON_T *pRTCPhdr;
|
|
|
|
IN_OUT_STR ("RTCP: Enter flushIO()\n");
|
|
|
|
// target socket
|
|
tSocket = pSSRC->RTCPsd;
|
|
|
|
// RTCP common header
|
|
pRTCPhdr = (RTCP_COMMON_T *)msg;
|
|
|
|
// RTP protocol version
|
|
pRTCPhdr->type = RTP_TYPE;
|
|
pRTCPhdr->pt = FLUSH_RTP_PAYLOAD_TYPE;
|
|
|
|
msgBuf.len = sizeof(msg);
|
|
msgBuf.buf = msg;
|
|
|
|
// get the address of the socket we are cleaning up
|
|
tmpSize = sizeof(tAddr);
|
|
if (RRCMws.getsockname (tSocket, (PSOCKADDR)&tAddr, &tmpSize))
|
|
{
|
|
dwStatus = GetLastError();
|
|
RRCM_DBG_MSG ("RTCP: ERROR - getsockname()",
|
|
dwStatus, __FILE__, __LINE__, DBG_ERROR);
|
|
|
|
IN_OUT_STR ("RTP : Exit flushIO()\n");
|
|
|
|
// (was: return dwStatus;)
|
|
// Since this function is supposed to return number of pending I/O requests
|
|
// to this socket, returning a non-zero error here is BOGUS!
|
|
// Just return zero because if there is an error (socket has been freed)
|
|
// then just say there's no i/o pending.
|
|
return 0;
|
|
}
|
|
|
|
if (tAddr.sin_addr.s_addr == 0)
|
|
{
|
|
// send to the local address
|
|
tAddr.sin_addr.S_un.S_un_b.s_b1 = 127;
|
|
tAddr.sin_addr.S_un.S_un_b.s_b2 = 0;
|
|
tAddr.sin_addr.S_un.S_un_b.s_b3 = 0;
|
|
tAddr.sin_addr.S_un.S_un_b.s_b4 = 1;
|
|
}
|
|
|
|
// get the number of outstanding buffers
|
|
outstanding = pSSRC->pRTCPses->dwNumRcvIoPending;
|
|
|
|
// make sure it's not < 0
|
|
if (outstanding < 0)
|
|
outstanding = pRTPContext->registry.NumRTCPPostedBfr;
|
|
|
|
// save number of pending I/Os
|
|
IoToFlush = outstanding;
|
|
|
|
#if _DEBUG
|
|
wsprintf(debug_string,
|
|
"RTCP: Flushing %d outstanding RCV buffers", outstanding);
|
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|
#endif
|
|
|
|
// send datagrams to the RTCP socket
|
|
while (outstanding--)
|
|
{
|
|
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
|
|
if (RTPLogger)
|
|
{
|
|
//INTEROP
|
|
InteropOutput (RTPLogger,
|
|
(BYTE FAR*)msgBuf.buf,
|
|
(int)msgBuf.len,
|
|
RTPLOG_SENT_PDU | RTCP_PDU);
|
|
}
|
|
#endif
|
|
|
|
dwStatus = RRCMws.sendTo (tSocket,
|
|
&msgBuf,
|
|
1,
|
|
&BytesSent,
|
|
0,
|
|
(SOCKADDR *)&tAddr,
|
|
sizeof(tAddr),
|
|
NULL,
|
|
#if 1
|
|
NULL);
|
|
#else
|
|
RTCPflushCallback);
|
|
#endif
|
|
if (dwStatus == SOCKET_ERROR)
|
|
{
|
|
// If serious error, undo all our work
|
|
dwStatus = GetLastError();
|
|
|
|
if (dwStatus != WSA_IO_PENDING)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - sendTo()", dwStatus,
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit flushIO()\n");
|
|
|
|
return IoToFlush;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function : RTCPflushCallback
|
|
* Description: Flush callback routine
|
|
*
|
|
* Input : dwError: I/O completion status
|
|
* cbTransferred: Number of bytes received
|
|
* lpOverlapped: -> to overlapped structure
|
|
* dwFlags: Flags
|
|
*
|
|
*
|
|
* Return: None
|
|
---------------------------------------------------------------------------*/
|
|
void CALLBACK RTCPflushCallback (DWORD dwError,
|
|
DWORD cbTransferred,
|
|
LPWSAOVERLAPPED lpOverlapped,
|
|
DWORD dwFlags)
|
|
{
|
|
IN_OUT_STR ("RTCP: Enter RTCPflushCallback\n");
|
|
|
|
// check Winsock callback error status
|
|
if (dwError)
|
|
{
|
|
RRCM_DBG_MSG ("RTCP: ERROR - Rcv Callback", dwError,
|
|
__FILE__, __LINE__, DBG_ERROR);
|
|
|
|
IN_OUT_STR ("RTCP: Exit RTCPflushCallback\n");
|
|
return;
|
|
}
|
|
|
|
IN_OUT_STR ("RTCP: Exit RTCPflushCallback\n");
|
|
}
|
|
|
|
|
|
|
|
|
|
// [EOF]
|
|
|