mirror of https://github.com/tongzx/nt5src
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
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);
|
|
|
|
}
|