Windows2003-3790/enduser/netmeeting/av/rrcm/rtp/rtprecv.cpp
2020-09-30 16:53:55 +02:00

818 lines
26 KiB
C++

/*----------------------------------------------------------------------------
* File: RTPRECV.C
* Product: RTP/RTCP implementation
* Description: Provides Receive Data Functionality.
*
* This listing is supplied under the terms
* of a license agreement with Intel Corporation and
* many 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 PRTP_CONTEXT pRTPContext;
extern RRCM_WS RRCMws;
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
//INTEROP
extern LPInteropLogger RTPLogger;
#endif
/*----------------------------------------------------------------------------
* Function : RTPReceiveCheck
* Description: Called when a packet is received. Handles any statistical
* processing required for RTCP.
*
* Input : hRTPSession: handle returned by CreateRTPSession
RTPsocket: socket on which the packet was received
char *pPacket: pointer to packet buffer
* cbTransferred: Number of bytes in packet
* pFrom: sender address
* fromlen: sender address length
*
* !!! IMPORTANT NOTE !!!
* Currently assumes CSRC = 0
* !!! IMPORTANT NOTE !!!
*
* Return: Status indicating if the packet is OK or has a problem
---------------------------------------------------------------------------*/
DWORD RTPReceiveCheck (
HANDLE hRTPSession,
SOCKET RTPsocket,
char *pPacket,
DWORD cbTransferred,
PSOCKADDR pFrom,
UINT fromlen
)
{
PRTP_SESSION pRTPSession = (PRTP_SESSION) hRTPSession;
RTP_HDR_T *pRTPHeader = (RTP_HDR_T *)pPacket;
PSSRC_ENTRY pSSRC = NULL;
DWORD dwSSRC;
DWORD oldSSRC;
PSSRC_ENTRY pMySSRC;
DWORD dwStatus = 0;
struct sockaddr_in *pSSRCadr;
IN_OUT_STR ("RTP : Enter RTPReceiveCheck()\n");
ASSERT (pRTPSession);
// If Winsock error or runt packet(used to cancel recvs), signal completion to application
// and do not repost.
if (cbTransferred < RTP_HDR_MIN_LEN)
{
// don't report closeSocket() as an error when the application
// have some pending buffers remaining
// notify the user if an error occured, so he can free up
// its receive resources. The byte count is set to 0
return RTP_RUNT_PACKET;
}
// Perform validity checking
ASSERT (pRTPHeader);
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
if (RTPLogger)
{
//INTEROP
InteropOutput (RTPLogger,
(BYTE FAR*)(pRTPHeader),
(int)cbTransferred,
RTPLOG_RECEIVED_PDU | RTP_PDU);
}
#endif
// Check RTP Headers for validity. If not valid, then repost buffers
// to the network layer for a new receive.
if (validateRTPHeader (pRTPHeader) )
{
// Get pointer to SSRC entry table for this session
// If SSRC in packet is > 1/2 MAX_RANGE of DWORD, start search from
// tail of SSRC list, otherwise, start from front
RRCMws.ntohl (RTPsocket, pRTPHeader->ssrc, &dwSSRC);
if (dwSSRC > MAX_DWORD/2)
{
pSSRC = searchforSSRCatTail (
(PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.prev,
dwSSRC);
}
else
{
pSSRC = searchforSSRCatHead (
(PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.next,
dwSSRC);
}
// get my own SSRC used for this stream
pMySSRC = searchForMySSRC (
(PSSRC_ENTRY)pRTPSession->pRTCPSession->XmtSSRCList.prev,
RTPsocket);
ASSERT (pMySSRC);
// is this SSRC already known on the receive list ?
if (pSSRC == NULL)
{
// don't create an entry for my own packet looping back on
// a mcast group where loopback has not been turned off
if (pMySSRC->SSRC != dwSSRC)
{
// new party heard from. Create an entry for it
pSSRC = createSSRCEntry (dwSSRC,
pRTPSession->pRTCPSession,
pFrom,
fromlen,
FALSE);
// notify application if interested
RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, dwSSRC,
pRTPHeader->pt);
}
else
{
// my own SSRC received back
// A collision occurs if the SSRC in the rcvd packet is
// equal to mine, and the network transport address is
// different from mine.
// A loop occurs if after a collision has been resolved the
// SSRC collides again from the same source transport address
pSSRCadr = (PSOCKADDR_IN)&pMySSRC->from;
if (((PSOCKADDR_IN)pFrom)->sin_addr.S_un.S_addr !=
pSSRCadr->sin_addr.S_un.S_addr)
{
// check if the source address is already in the
// conflicting table. This identifes that somebody out
// there is looping pckts back to me
if (RRCMChkCollisionTable (pFrom, fromlen, pMySSRC))
{
RRCM_DBG_MSG ("RTP : Loop Detected ...", 0, NULL, 0,
DBG_NOTIFY);
// loop already known
dwStatus |= SSRC_LOOP_DETECTED;
}
else
{
RRCM_DBG_MSG ("RTP : Collision Detected ...", 0, NULL, 0,
DBG_NOTIFY);
// create new entry in conflicting address table
RRCMAddEntryToCollisionTable (pFrom, fromlen, pMySSRC);
// send RTCP BYE packet w/ old SSRC
RTCPsendBYE (pMySSRC, "Loop/collision detected");
// select new SSRC
oldSSRC = pMySSRC->SSRC;
dwSSRC = getSSRC (pMySSRC->pRTCPses->RcvSSRCList,
pMySSRC->pRTCPses->XmtSSRCList);
EnterCriticalSection (&pMySSRC->critSect);
pMySSRC->SSRC = dwSSRC;
LeaveCriticalSection (&pMySSRC->critSect);
// create new entry w/ old SSRC plus actual source
// transport address in our receive list side, so the
// packet actually en-route will be dealt with
createSSRCEntry (oldSSRC,
pRTPSession->pRTCPSession,
pFrom,
fromlen,
FALSE);
// notify application if interested
RRCMnotification (RRCM_LOCAL_COLLISION_EVENT,
pMySSRC, oldSSRC, 0);
// loop already known
dwStatus |= SSRC_COLLISION_DETECTED;
}
}
else
{
// own packet looped back because the sender joined the
// multicast group and loopback is not turned off
dwStatus |= MCAST_LOOPBACK_NOT_OFF;
}
}
}
else if (pSSRC->dwSSRCStatus & THIRD_PARTY_COLLISION)
{
// this SSRC is marked as colliding. Reject the data
dwStatus = THIRD_PARTY_COLLISION;
}
if (dwStatus == 0)
{
// do all the statistical updating stuff
updateRTPStats (pRTPHeader, pSSRC, cbTransferred);
// update the payload type for this SSRC
pSSRC->PayLoadType = pRTPHeader->pt;
} // SSRCList != NULL
} // valid RTP Header
else
{
dwStatus |= INVALID_RTP_HEADER;
}
IN_OUT_STR ("RTP : Exit RTPReceiveCallback()\n");
return dwStatus;
}
/*----------------------------------------------------------------------------
* Function : validateRTPHeader
* Description: Performs basic checking of RTP Header (e.g., version number
* and payload type range).
*
* Input : pRTPHeader: -> to an RTP header
*
* Return: TRUE, RTP Packet Header is valid
* FALSE: Header is invalid
---------------------------------------------------------------------------*/
BOOL validateRTPHeader(RTP_HDR_T *pRTPHeader)
{
BOOL bStatus = TRUE;
IN_OUT_STR ("RTP : Enter validateRTPHeader()\n");
if (! pRTPHeader)
return FALSE;
// Check version number is correct
if (pRTPHeader->type != RTP_TYPE)
bStatus = FALSE;
// Next check that the Packet types look somewhat reasonable,
// at least out of the RTCP range
if (pRTPHeader->pt >= RTCP_SR)
bStatus = FALSE;
IN_OUT_STR ("RTP : Exit validateRTPHeader()\n");
return bStatus;
}
#if 0
/*----------------------------------------------------------------------------
* Function : RTPRecvFrom
* Description: Intercepts receive requests from app. Handles any statistical
* processing required for RTCP. Copies completion routine
* from app and substitutes its own. Apps completion routine
* will be called after RTP's completion routine gets called.
*
* Input : RTPsocket: RTP socket descriptor
* pBuffers: -> to WSAbuf structure
* dwBufferCount: Buffer count in WSAbuf structure
* pNumBytesRecvd: -> to number of bytes received
* pFlags: -> to flags
* pFrom: -> to the source address
* pFromLen: -> to source address length
* pOverlapped: -> to overlapped I/O structure
* pCompletionRoutine: -> to completion routine
*
* Return: RRCM_NoError = OK.
* Otherwise(!=0) = Check RRCM.h file for references.
---------------------------------------------------------------------------*/
DWORD WINAPI RTPRecvFrom (SOCKET RTPsocket,
LPWSABUF pBuffers,
DWORD dwBufferCount,
LPDWORD pNumBytesRecvd,
LPDWORD pFlags,
PSOCKADDR pFrom,
LPINT pFromlen,
LPWSAOVERLAPPED pOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE pCompletionRoutine)
{
int dwStatus = RRCM_NoError;
int dwError;
PRTP_SESSION pRTPSession;
PRTP_BFR_LIST pRCVStruct;
IN_OUT_STR ("RTP : Enter RTPRecvFrom()\n");
// If RTP context doesn't exist, report error and return.
if (pRTPContext == NULL)
{
RRCM_DBG_MSG ("RTP : ERROR - No RTP Instance", 0,
__FILE__, __LINE__, DBG_CRITICAL);
IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
return (MAKE_RRCM_ERROR(RRCMError_RTPInvalid));
}
// Search for the proper session based on incoming socket
pRTPSession = findSessionID(RTPsocket);
if (pRTPSession == NULL)
{
RRCM_DBG_MSG ("RTP : ERROR - Invalid RTP session", 0,
__FILE__, __LINE__, DBG_CRITICAL);
IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
return (MAKE_RRCM_ERROR(RRCMError_RTPInvalidSession));
}
// We need to associate a completionRoutine's lpOverlapped with a
// session. We look at each buffer and associate a socket so when
// the completion routine is called, we can pull out the socket.
if (dwStatus = saveRCVWinsockContext(pOverlapped,
pBuffers,
pCompletionRoutine,
pRTPSession,
dwBufferCount,
pNumBytesRecvd,
pFlags,
pFrom,
pFromlen,
RTPsocket) != RRCM_NoError)
{
RRCM_DBG_MSG ("RTP : ERROR - Out of resources...", 0,
__FILE__, __LINE__, DBG_NOTIFY);
IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
return (MAKE_RRCM_ERROR(dwStatus));
}
// Forward to winsock, substituting our completion routine for the
// one handed to us.
dwStatus = RRCMws.recvFrom (RTPsocket,
pBuffers,
dwBufferCount,
pNumBytesRecvd,
pFlags,
pFrom,
pFromlen,
pOverlapped,
RTPReceiveCallback);
// Check if Winsock Call succeeded
if (dwStatus != 0)
{
// If serious error, the receive request won't proceed so
// we must undo all our work
dwError = GetLastError();
if ((dwError != WSA_IO_PENDING) && (dwError != WSAEMSGSIZE))
{
// Reinstate the Apps WSAEVENT
pRCVStruct = (PRTP_BFR_LIST)pOverlapped->hEvent;
pOverlapped->hEvent = pRCVStruct->hEvent;
RRCM_DBG_MSG ("RTP : ERROR - WSARecvFrom()", dwError,
__FILE__, __LINE__, DBG_NOTIFY);
// Return the struct to the free queue
addToHeadOfList (&pRTPSession->pRTPFreeList,
(PLINK_LIST)pRCVStruct,
&pRTPSession->critSect);
}
}
IN_OUT_STR ("RTP : Exit RTPRecvFrom()\n");
return (dwStatus);
}
/*----------------------------------------------------------------------------
* Function : RTPReceiveCallback
* Description: Callback routine from Winsock2 Handles any statistical
* processing required for RTCP. Copies completion routine
* from app and substitutes its own. Apps completion routine
* will be called after RTP's completion routine gets called.
*
* Input : dwError: I/O completion error code
* cbTransferred: Number of bytes transferred
* pOverlapped: -> to overlapped I/O structure
* dwFlags: Flags
*
* !!! IMPORTANT NOTE !!!
* Currently assumes CSRC = 0
* !!! IMPORTANT NOTE !!!
*
* Return: None
---------------------------------------------------------------------------*/
void CALLBACK RTPReceiveCallback (DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED pOverlapped,
DWORD dwFlags)
{
PRTP_SESSION pRTPSession;
RTP_HDR_T *pRTPHeader;
PRTP_BFR_LIST pRCVStruct;
PSSRC_ENTRY pSSRC = NULL;
DWORD dwSSRC;
DWORD oldSSRC;
PSSRC_ENTRY pMySSRC;
DWORD dwRequeue = 0;
struct sockaddr_in *pSSRCadr;
IN_OUT_STR ("RTP : Enter RTPReceiveCallback()\n");
// GEORGEJ: catch Winsock 2 bug (94903) where I get a bogus callback
// after WSARecv returns WSAEMSGSIZE.
if (!dwError && ((int) cbTransferred < 0)) {
RRCM_DBG_MSG ("RTP : RCV Callback : bad cbTransferred", cbTransferred,
__FILE__, __LINE__, DBG_ERROR);
return;
}
// The returning hEvent in the LPWSAOVERLAPPED struct contains the
// information mapping the session and the buffer.
pRCVStruct = (PRTP_BFR_LIST)pOverlapped->hEvent;
// Search for the proper session based on incoming socket
pRTPSession = (PRTP_SESSION)pRCVStruct->pSession;
ASSERT (pRTPSession);
// If Winsock error or runt packet(used to cancel recvs), signal completion to application
// and do not repost.
if (dwError || cbTransferred < RTP_HDR_MIN_LEN)
{
// don't report closeSocket() as an error when the application
// have some pending buffers remaining
if ((dwError != 65534) && (dwError == WSA_OPERATION_ABORTED))
{
RRCM_DBG_MSG ("RTP : RCV Callback", dwError,
__FILE__, __LINE__, DBG_ERROR);
}
// notify the user if an error occured, so he can free up
// its receive resources. The byte count is set to 0
// Reinstate the AppSs WSAEVENT
pOverlapped->hEvent = pRCVStruct->hEvent;
// And call the apps completion routine
pRCVStruct->pfnCompletionNotification (dwError,
cbTransferred,
pOverlapped,
dwFlags);
// Return the struct to the free queue
addToHeadOfList (&pRTPSession->pRTPFreeList,
(PLINK_LIST)pRCVStruct,
&pRTPSession->critSect);
IN_OUT_STR ("RTP : Exit RTPReceiveCallback()\n");
return;
}
// Perform validity checking
pRTPHeader = (RTP_HDR_T *)pRCVStruct->pBuffer->buf;
ASSERT (pRTPHeader);
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
if (RTPLogger)
{
//INTEROP
InteropOutput (RTPLogger,
(BYTE FAR*)(pRCVStruct->pBuffer->buf),
(int)cbTransferred,
RTPLOG_RECEIVED_PDU | RTP_PDU);
}
#endif
// Check RTP Headers for validity. If not valid, then repost buffers
// to the network layer for a new receive.
if (validateRTPHeader (pRTPHeader) && (dwError == 0))
{
// Get pointer to SSRC entry table for this session
// If SSRC in packet is > 1/2 MAX_RANGE of DWORD, start search from
// tail of SSRC list, otherwise, start from front
RRCMws.ntohl (pRCVStruct->RTPsocket, pRTPHeader->ssrc, &dwSSRC);
if (dwSSRC > MAX_DWORD/2)
{
pSSRC = searchforSSRCatTail (
(PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.prev,
dwSSRC);
}
else
{
pSSRC = searchforSSRCatHead (
(PSSRC_ENTRY)pRTPSession->pRTCPSession->RcvSSRCList.next,
dwSSRC);
}
// get my own SSRC used for this stream
pMySSRC = searchForMySSRC (
(PSSRC_ENTRY)pRTPSession->pRTCPSession->XmtSSRCList.prev,
pRCVStruct->RTPsocket);
ASSERT (pMySSRC);
// is this SSRC already known on the receive list ?
if (pSSRC == NULL)
{
// don't create an entry for my own packet looping back on
// a mcast group where loopback has not been turned off
if (pMySSRC->SSRC != dwSSRC)
{
// new party heard from. Create an entry for it
pSSRC = createSSRCEntry (dwSSRC,
pRTPSession->pRTCPSession,
(PSOCKADDR)pRCVStruct->pFrom,
(DWORD)*pRCVStruct->pFromlen,
FALSE);
// notify application if interested
RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, dwSSRC,
pRTPHeader->pt);
}
else
{
// my own SSRC received back
// A collision occurs if the SSRC in the rcvd packet is
// equal to mine, and the network transport address is
// different from mine.
// A loop occurs if after a collision has been resolved the
// SSRC collides again from the same source transport address
pSSRCadr = (PSOCKADDR_IN)&pMySSRC->from;
if (((PSOCKADDR_IN)pRCVStruct->pFrom)->sin_addr.S_un.S_addr !=
pSSRCadr->sin_addr.S_un.S_addr)
{
// check if the source address is already in the
// conflicting table. This identifes that somebody out
// there is looping pckts back to me
if (RRCMChkCollisionTable ((PSOCKADDR)pRCVStruct->pFrom,*pRCVStruct->pFromlen, pMySSRC))
{
RRCM_DBG_MSG ("RTP : Loop Detected ...", 0, NULL, 0,
DBG_NOTIFY);
// loop already known
dwRequeue |= SSRC_LOOP_DETECTED;
}
else
{
RRCM_DBG_MSG ("RTP : Collision Detected ...", 0, NULL, 0,
DBG_NOTIFY);
// create new entry in conflicting address table
RRCMAddEntryToCollisionTable ((PSOCKADDR)pRCVStruct->pFrom,*pRCVStruct->pFromlen, pMySSRC);
// send RTCP BYE packet w/ old SSRC
RTCPsendBYE (pMySSRC, "Loop/collision detected");
// select new SSRC
oldSSRC = pMySSRC->SSRC;
dwSSRC = getSSRC (pMySSRC->pRTCPses->RcvSSRCList,
pMySSRC->pRTCPses->XmtSSRCList);
EnterCriticalSection (&pMySSRC->critSect);
pMySSRC->SSRC = dwSSRC;
LeaveCriticalSection (&pMySSRC->critSect);
// create new entry w/ old SSRC plus actual source
// transport address in our receive list side, so the
// packet actually en-route will be dealt with
createSSRCEntry (oldSSRC,
pRTPSession->pRTCPSession,
(PSOCKADDR)pRCVStruct->pFrom,
(DWORD)*pRCVStruct->pFromlen,
FALSE);
// notify application if interested
RRCMnotification (RRCM_LOCAL_COLLISION_EVENT,
pMySSRC, oldSSRC, 0);
// loop already known
dwRequeue |= SSRC_COLLISION_DETECTED;
}
}
else
{
// own packet looped back because the sender joined the
// multicast group and loopback is not turned off
dwRequeue |= MCAST_LOOPBACK_NOT_OFF;
}
}
}
else if (pSSRC->dwSSRCStatus & THIRD_PARTY_COLLISION)
{
// this SSRC is marked as colliding. Reject the data
dwRequeue = THIRD_PARTY_COLLISION;
}
if ((pSSRC != NULL) && (dwRequeue == 0))
{
// do all the statistical updating stuff
updateRTPStats (pRTPHeader, pSSRC, cbTransferred);
// update the payload type for this SSRC
pSSRC->PayLoadType = pRTPHeader->pt;
// Reinstate the AppSs WSAEVENT
pOverlapped->hEvent = pRCVStruct->hEvent;
// And call the apps completion routine
pRCVStruct->pfnCompletionNotification (dwError,
cbTransferred,
pOverlapped,
dwFlags);
// Return the struct to the free queue
addToHeadOfList (&pRTPSession->pRTPFreeList,
(PLINK_LIST)pRCVStruct,
&pRTPSession->critSect);
} // SSRCList != NULL
} // valid RTP Header
else
{
dwRequeue |= INVALID_RTP_HEADER;
}
if (dwRequeue)
{
// The RTP packet was invalid for some reason
RTPpostRecvBfr (dwError, cbTransferred, pOverlapped, dwFlags);
}
IN_OUT_STR ("RTP : Exit RTPReceiveCallback()\n");
}
/*----------------------------------------------------------------------------
* Function : saveRCVWinsockContext
* Description: Saves context for this buffer so that when a completion
* routine returns with a handle, we know exactly what
* buffer/stream this refers to.
*
* Input : pOverlapped : -> to overlapped structure
* pBuffers : -> to WSA buffers
* pFunc : -> to completion routine
* pSession : -> to the RTP session
* dwBufferCount : Number of WSA buffers
* pNumBytesRecvd : -> to number of bytes received
* pFlags : -> to flags
* pFrom : -> to the From address field
* pFromlen : -> to the from address field length
* RTPsocket : RTP socket descriptor
*
* Return: RRCM_NoError = OK.
* Otherwise(!=0) = Check RRCM.h file for references.
---------------------------------------------------------------------------*/
DWORD CALLBACK saveRCVWinsockContext(LPWSAOVERLAPPED pOverlapped,
LPWSABUF pBuffers,
LPWSAOVERLAPPED_COMPLETION_ROUTINE pFunc,
PRTP_SESSION pSession,
DWORD dwBufferCount,
LPDWORD pNumBytesRecvd,
LPDWORD pFlags,
LPVOID pFrom,
LPINT pFromlen,
SOCKET RTPsocket)
{
PRTP_BFR_LIST pNewCell;
DWORD dwStatus = RRCM_NoError;
DWORD numCells = NUM_FREE_CONTEXT_CELLS;
IN_OUT_STR ("RTP : Enter saveRCVWinsockContext()\n");
// Get a PRTP Buffer from the free list
pNewCell = (PRTP_BFR_LIST)removePcktFromTail (
(PLINK_LIST)&pSession->pRTPFreeList,
&pSession->critSect);
if (pNewCell == NULL)
{
// try to reallocate some free cells
if (pSession->dwNumTimesFreeListAllocated <= MAXNUM_CONTEXT_CELLS_REALLOC)
{
// increment the number of reallocated times even if the realloc
// fails next. Will avoid trying to realloc of a realloc problem
pSession->dwNumTimesFreeListAllocated++;
if (allocateLinkedList (&pSession->pRTPFreeList,
pSession->hHeapFreeList,
&numCells,
sizeof(RTP_BFR_LIST),
&pSession->critSect) == RRCM_NoError)
{
pNewCell = (PRTP_BFR_LIST)removePcktFromTail (
(PLINK_LIST)&pSession->pRTPFreeList,
&pSession->critSect);
}
}
}
if (pNewCell != NULL)
{
// Initialize the params
pNewCell->hEvent = pOverlapped->hEvent;
pNewCell->pBuffer = pBuffers;
pNewCell->pSession = pSession;
pNewCell->dwFlags = *pFlags;
pNewCell->pFrom = pFrom;
pNewCell->pFromlen = pFromlen;
pNewCell->RTPsocket = RTPsocket;
pNewCell->dwBufferCount = dwBufferCount;
pNewCell->pfnCompletionNotification = pFunc;
// Overwrite the hEvent handed down from app.
// Will return the real one when the completion routine is called
pOverlapped->hEvent = (WSAEVENT)pNewCell;
}
else
dwStatus = RRCMError_RTPResources;
IN_OUT_STR ("RTP : Exit saveRCVWinsockContext()\n");
return (dwStatus);
}
/*----------------------------------------------------------------------------
* Function : RTPpostRecvBfr
* Description: RTP post a receive buffer to Winsock
*
* Input : dwError : Error code
* cbTransferred : Bytes transferred
* pOverlapped : -> to overlapped structure
* dwFlags : Flags
*
* Return: None
---------------------------------------------------------------------------*/
void RTPpostRecvBfr (DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED pOverlapped,
DWORD dwFlags)
{
DWORD dwStatus;
PRTP_BFR_LIST pRCVStruct;
PRTP_SESSION pRTPSession;
IN_OUT_STR ("RTP : Enter RTPpostRecvBfr\n");
// Reuse the packet with another receive
pRCVStruct = (PRTP_BFR_LIST)pOverlapped->hEvent;
// Corresponding RTP session
pRTPSession = (PRTP_SESSION)pRCVStruct->pSession;
dwStatus = RRCMws.recvFrom (pRCVStruct->RTPsocket,
pRCVStruct->pBuffer,
pRCVStruct->dwBufferCount,
&cbTransferred,
&pRCVStruct->dwFlags,
(PSOCKADDR)pRCVStruct->pFrom,
pRCVStruct->pFromlen,
pOverlapped,
RTPReceiveCallback);
// Check if Winsock Call succeeded
if (dwStatus == SOCKET_ERROR)
{
// If serious error, the receive request won't proceed
dwStatus = GetLastError();
if ((dwStatus != WSA_IO_PENDING) && (dwStatus != WSAEMSGSIZE))
{
RRCM_DBG_MSG ("RTP : ERROR - WSARecvFrom()", dwError,
__FILE__, __LINE__, DBG_ERROR);
// notify the user if an error occured, so he can free up
// its receive resources. The byte count is set to 0
// Reinstate the AppSs WSAEVENT
pOverlapped->hEvent = pRCVStruct->hEvent;
// And call the apps completion routine
pRCVStruct->pfnCompletionNotification (dwStatus,
0,
pOverlapped,
dwFlags);
// Return the receive structure to the free list
addToHeadOfList (&pRTPSession->pRTPFreeList,
(PLINK_LIST)pRCVStruct,
&pRTPSession->critSect);
}
}
IN_OUT_STR ("RTP : Exit RTPpostRecvBfr\n");
}
#endif
// [EOF]