354 lines
9.4 KiB
C++
354 lines
9.4 KiB
C++
/*++
|
||
|
||
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);
|
||
|
||
}
|