|
|
/*++
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);
}
|