|
|
/*----------------------------------------------------------------------------
* 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]
|