Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

353 lines
9.4 KiB

/*++
Copyright (c) 1998 - 2000 Microsoft Corporation
Module Name:
emrecv.cpp
Abstract:
Contains all the event manager routines which
manage the overlapped recv operations
Revision History:
1. created
Ajay Chitturi (ajaych) 12-Jun-1998
--*/
#include "stdafx.h"
#include "cbridge.h"
#include "ovioctx.h"
static
PSendRecvContext
EventMgrCreateRecvContext(
IN SOCKET sock,
IN OVERLAPPED_PROCESSOR & rOvProcessor
)
{
PSendRecvContext pRecvContext;
// IO Context part - make this a separate inline function
pRecvContext = (PSendRecvContext) HeapAlloc (GetProcessHeap (),
0, // No Flags
sizeof(SendRecvContext));
if (!pRecvContext)
return NULL;
memset(pRecvContext, 0, sizeof(SendRecvContext));
pRecvContext->ioCtxt.reqType = EMGR_OV_IO_REQ_RECV;
pRecvContext->ioCtxt.pOvProcessor = &rOvProcessor;
// Recv Context part
pRecvContext->sock = sock;
pRecvContext->dwTpktHdrBytesDone = 0;
pRecvContext->dwDataLen = 0;
pRecvContext->pbData = NULL;
pRecvContext->dwDataBytesDone = 0;
return pRecvContext;
}
// If you do not want to free the event manager context
// set it to NULL before calling this function.
void
EventMgrFreeRecvContext (
PSendRecvContext pRecvCtxt
)
{
// Socket and OvProcessor are owned by the
// Call Bridge Machine
if (pRecvCtxt->pbData != NULL)
{ EM_FREE(pRecvCtxt->pbData);
}
HeapFree (GetProcessHeap (),
0, // no flags
pRecvCtxt);
}
/*
* Call ReadFile to start an overlapped request
* on a socket. Make sure we handle errors
* that are recoverable.
*
* pRecvCtxt is not freed in case of an error
*/
static
HRESULT
EventMgrIssueRecvHelperFn(
PSendRecvContext pRecvCtxt
)
{
int i = 0;
BOOL bResult;
int err;
DWORD dwNumRead, dwToRead;
PBYTE pbReadBuf;
_ASSERTE(pRecvCtxt);
if (pRecvCtxt ->ioCtxt.pOvProcessor->IsSocketValid())
{
if (pRecvCtxt->dwTpktHdrBytesDone < TPKT_HEADER_SIZE)
{
dwToRead = TPKT_HEADER_SIZE - pRecvCtxt->dwTpktHdrBytesDone;
pbReadBuf = pRecvCtxt->pbTpktHdr + pRecvCtxt->dwTpktHdrBytesDone;
}
else
{
dwToRead = pRecvCtxt->dwDataLen - pRecvCtxt->dwDataBytesDone;
pbReadBuf = pRecvCtxt->pbData + pRecvCtxt->dwDataBytesDone;
}
// Kick off the first read
while (++i)
{
memset(&pRecvCtxt->ioCtxt.ov, 0, sizeof(OVERLAPPED));
// make an overlapped IO Request
// XXX The socket may not be valid at this point
pRecvCtxt->ioCtxt.pOvProcessor->GetCallBridge().AddRef();
bResult = ReadFile((HANDLE)pRecvCtxt->sock,
pbReadBuf,
dwToRead,
&dwNumRead,
&pRecvCtxt->ioCtxt.ov
);
// It succeeded immediately, but do not process it
// here, wait for the completion packet.
if (bResult)
return S_OK;
err = GetLastError();
// This is what we want to happen, its not an error
if (err == ERROR_IO_PENDING)
return S_OK;
pRecvCtxt->ioCtxt.pOvProcessor->GetCallBridge().Release ();
// Handle recoverable error
if ( err == ERROR_INVALID_USER_BUFFER ||
err == ERROR_NOT_ENOUGH_QUOTA ||
err == ERROR_NOT_ENOUGH_MEMORY )
{
if (i <= 5) // I just picked a number
{
Sleep(50); // Wait around and try later
continue;
}
DebugF (_T("H323: System ran out of non-paged space.\n"));
}
// This means this is an unrecoverable error
// one possibility is that that Call bridge could have closed
// the socket some time in between
break;
}//while(++i)
DebugF (_T("H323: ReadFile failed error: %d.\n"), err);
return E_FAIL;
} else {
DebugF (_T("H323: 0x%x overlapped processor %x had invalid socket.\n"),
&pRecvCtxt ->ioCtxt.pOvProcessor -> GetCallBridge (),
pRecvCtxt ->ioCtxt.pOvProcessor);
return E_ABORT;
}
return S_OK;
} //EventMgrIssueRecv()
/*
* The Call Bridge Machine calls this function to issue asynchronous
* receive requests
*
*/
HRESULT
EventMgrIssueRecv(
IN SOCKET sock,
IN OVERLAPPED_PROCESSOR & rOvProcessor
)
{
PSendRecvContext pRecvCtxt =
EventMgrCreateRecvContext(sock, rOvProcessor);
if (!pRecvCtxt)
{
return E_OUTOFMEMORY;
}
HRESULT hRes = EventMgrIssueRecvHelperFn(pRecvCtxt);
if (FAILED(hRes))
{
EventMgrFreeRecvContext(pRecvCtxt);
}
return hRes;
}
/*
* Make the error callback.
*
* Since this is called only in case of an error this need not be an
* inline function
*
*/
void
MakeErrorRecvCallback(
HRESULT hRes,
PSendRecvContext pRecvCtxt
)
{
DebugF (_T("Q931: 0x%x error 0x%x on receive callback.\n"),
&pRecvCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
hRes);
pRecvCtxt->ioCtxt.pOvProcessor->ReceiveCallback(hRes, NULL, NULL);
}
// This function passes the decoded PDUs to the Call bridge Machine.
// This function frees the PDUs after the callback function returns.
// The PDUs are allocated by the ASN1 library and the corresponding
// functions need to be used to free the PDUs.
/*
* This function is called by the event loop when a recv I/O completes.
* The Call Bridge Machine's recv call back function is called.
*
* This function does not return any error code. In case of an error,
* the call bridge machine is notified about the error in the callback.
*
* This function always frees pRecvCtxt if another Recv is not issued
*/
void
HandleRecvCompletion(
PSendRecvContext pRecvCtxt,
DWORD dwNumRead,
DWORD status
)
{
HRESULT hRes;
if (status != NO_ERROR || dwNumRead == 0)
{
// This means an error occured in the read operation
// We need to call the callback with the error status
if (status == NO_ERROR && dwNumRead == 0)
{
DebugF (_T("H323: 0x%x transport connection was closed by peer.\n"),
&pRecvCtxt -> ioCtxt.pOvProcessor -> GetCallBridge ());
hRes = HRESULT_FROM_WIN32 (WSAECONNRESET);
}
else
{
hRes = HRESULT_FROM_WIN32_ERROR_CODE(status);
}
// make callback
MakeErrorRecvCallback(hRes, pRecvCtxt);
EventMgrFreeRecvContext(pRecvCtxt);
return;
}
if (pRecvCtxt->dwTpktHdrBytesDone < TPKT_HEADER_SIZE)
{
// This means we are still reading the TPKT header
pRecvCtxt->dwTpktHdrBytesDone += dwNumRead;
}
else
{
// This means we are reading the data
pRecvCtxt->dwDataBytesDone += dwNumRead;
}
// If the TPKT header has been read completely we need to
// extract the packet size, set it appropriately
// and allocate the data buffer
if (pRecvCtxt->dwDataLen == 0 &&
pRecvCtxt->dwTpktHdrBytesDone == TPKT_HEADER_SIZE)
{
hRes = S_OK;
pRecvCtxt->dwDataLen = GetPktLenFromTPKTHdr(pRecvCtxt->pbTpktHdr);
// The length of the PDU fits in 2 bytes
_ASSERTE(pRecvCtxt->dwDataLen < (1L << 16));
pRecvCtxt->pbData = (PBYTE) EM_MALLOC(pRecvCtxt->dwDataLen);
if (!pRecvCtxt->pbData)
{
DebugF (_T ("H323: 0x%x HandleRecvCompletion(): Could not allocate pbData.\n"),
&pRecvCtxt -> ioCtxt.pOvProcessor -> GetCallBridge ());
MakeErrorRecvCallback(E_OUTOFMEMORY, pRecvCtxt);
EventMgrFreeRecvContext(pRecvCtxt);
return;
}
memset(pRecvCtxt->pbData, 0, pRecvCtxt->dwDataLen);
hRes = EventMgrIssueRecvHelperFn(pRecvCtxt);
if (hRes != S_OK)
{
MakeErrorRecvCallback(hRes, pRecvCtxt);
EventMgrFreeRecvContext(pRecvCtxt);
return;
}
else
{
// Succeeded in making an overlapped recv request
return;
}
}
if (pRecvCtxt->dwTpktHdrBytesDone < TPKT_HEADER_SIZE ||
pRecvCtxt->dwDataBytesDone < pRecvCtxt->dwDataLen)
{
hRes = S_OK;
hRes = EventMgrIssueRecvHelperFn(pRecvCtxt);
if (hRes != S_OK)
{
MakeErrorRecvCallback(hRes, pRecvCtxt);
EventMgrFreeRecvContext(pRecvCtxt);
return;
}
else
{
// Succeeded in making an overlapped recv request
return;
}
}
// Received a complete PDU
// need to decode the packet and call the appropriate callback
// and free pRecvCtxt
pRecvCtxt->ioCtxt.pOvProcessor->ReceiveCallback(S_OK,
pRecvCtxt->pbData,
pRecvCtxt->dwDataLen);
// It is the responsibility of the callback function to free the buffer.
pRecvCtxt->pbData = NULL;
pRecvCtxt->dwDataLen = 0;
// Clean up Recv context structure
EventMgrFreeRecvContext(pRecvCtxt);
}