Leaked source code of windows server 2003
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.
 
 
 
 
 
 

627 lines
18 KiB

//+-------------------------------------------------------------------
//
// File: serial.cxx
//
// Contents: serialization support
//
// Classes: Serializer
//
// Functions: Helper class for serialization which holds
// serialization state like MES handles, position
// in buffer, stream etc. Provides a virtual
// buffer for operation but is created from and
// commited back to an IStream object.
//
// History: 24-Jan-98 vinaykr Created
// 17-Aug-98 vinaykr Made every method inline
// and non-COM class.
//
//--------------------------------------------------------------------
#ifndef __SERIAL_HXX
#define __SERIAL_HXX
#include <rpc.h>
#include <midles.h>
#include <actstrm.hxx>
#include <buffer.h>
#include <serializ.h>
#include <ole2int.h>
// Flag used to signal the in-proc case for Serialization header marshalling
#define INTERNAL_SERIALIZATION_FLAG 0x487fabc
extern GUID gProcessGuid;
typedef struct _SSerializationHeader
{
DWORD dwSize;
void* pvMarshalPtr;
} SerializationHeader;
class Serializer
{
public:
enum
{
DIRECTION_READ = 0x1,
DIRECTION_WRITE = 0x2
};
inline ~Serializer()
{
// Free MES handle
if (_handle!=0)
MesHandleFree(_handle);
// If we have a stream free it
if (_pStream)
{
_pIBuff->Release();
_pStream->Release();
}
// If original stream is different free it
if ((_pOriginalStream) && (_pOriginalStream != _pStream))
_pOriginalStream->Release();
}
inline Serializer()
{
_bufSize=0;
_operationSize=0;
_buffer = 0;
_nWritten = 0;
_position = 0;
_start = 0;
_pStream = NULL;
_pOriginalStream = NULL;
_pIBuff = NULL;
_handle = 0;
_clRefs = 1;
}
inline Serializer(DWORD dwMaxDestCtx, DWORD dwCurrCtx, DWORD dwMarshalFlags)
{
this->Serializer::Serializer();
_dwMaxDestCtx = dwMaxDestCtx;
_dwCurrentDestCtx = dwCurrCtx;
_dwMarshalFlags = dwMarshalFlags;
}
inline ULONG Serializer::Release(void)
{
Win4Assert((_clRefs != 0) && "Serializer::Release");
ULONG ulRefs = InterlockedDecrement(&_clRefs);
if (ulRefs == 0)
{
delete this;
}
return ulRefs;
}
/***************************************************************************/
/** Initializes state based on stream for serialization **/
/** Assumes that we know the limits of our operation before hand if we **/
/** writing out to the stream. **/
/** Note that it is the responsibility of the caller to ensure that the **/
/** variable pMarshalPtr is only passed during in process marshalling **/
/** otherwise undefined errors may result. **/
/** Note that when writing pMarshalPtr and dwSize are input parameters **/
/** and while reading they are output.
/***************************************************************************/
inline HRESULT InitStream(IStream *pStream,DWORD &dwSize, DWORD direction, void* &pMarshalPtr)
{
HRESULT hr;
DWORD nRead;
_direction = direction;
_pOriginalStream = pStream;
_pOriginalStream->AddRef();
// Either read or write initial protocol header
if (direction == DIRECTION_READ)
{
SerializationHeader hdr;
DWORD dwFlag;
// There was a slight security hole here, on both 32 and 64 bit,
// because we could deference arbitrary pointers if we read them
// out of a malicious objref.
//
// For the in-proc marshal case, we'll solve this by writing out the
// in-proc serialization flag, followed by the process' secret guid
// as 'authentication', followed by the actual CObjectContext pointer,
//
// -mfeingol 2/28/2002
// Read the size
if ((hr = _pOriginalStream->Read(&hdr.dwSize, sizeof (hdr.dwSize), &nRead)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
// Read the flag
if ((hr = _pOriginalStream->Read(&dwFlag, sizeof (dwFlag), &nRead)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
// Determine if the stream comes from in-proc or out-of-proc
if (dwFlag == INTERNAL_SERIALIZATION_FLAG)
{
// Inproc case: there's a guid, then a pointer in the stream
GUID guidGuess = GUID_NULL;
if ((hr = _pOriginalStream->Read(&guidGuess, sizeof (guidGuess), &nRead)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
Win4Assert (gProcessGuid != GUID_NULL);
if (guidGuess != gProcessGuid)
return E_UNEXPECTED;
// Now we know that there's a real pointer in the stream
if ((hr = _pOriginalStream->Read(&hdr.pvMarshalPtr, sizeof (hdr.pvMarshalPtr), &nRead)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
}
else
{
// Out of proc case; the DWORD we read is just a NULL placeholder
hdr.pvMarshalPtr = NULL;
}
pMarshalPtr = hdr.pvMarshalPtr;
if (hdr.pvMarshalPtr)
{
_operationSize = hdr.dwSize;
}
else
{
BYTE *pSrc = (BYTE*) &hdr.dwSize;
_operationSize = 0;
for (int i = 0; i<(sizeof(DWORD)/sizeof(BYTE)); i++)
{
_operationSize |= ((((DWORD)(*pSrc++)) & 0xFF) << (i*8));
}
}
dwSize = _operationSize;
}
else
{
_operationSize = dwSize;
SerializationHeader hdr;
hdr.pvMarshalPtr = pMarshalPtr;
if (pMarshalPtr)
{
hdr.dwSize = dwSize;
}
else
{
BYTE *pDst = (BYTE*) &hdr.dwSize;
for (int i = 0; i<(sizeof(DWORD)/sizeof(BYTE)); i++)
{
*pDst++ = (BYTE)((dwSize>>(i*8)) & 0xFF);
}
}
if (pMarshalPtr)
{
// Inproc case: write the size DWORD, the flag, the process' secret guid GUID, then the ptr
DWORD dwFlag = INTERNAL_SERIALIZATION_FLAG;
if ((hr = _pOriginalStream->Write(&hdr.dwSize, sizeof (hdr.dwSize), &_nWritten)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
if ((hr = _pOriginalStream->Write(&dwFlag, sizeof (dwFlag), &_nWritten)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
if ((hr = _pOriginalStream->Write(&gProcessGuid, sizeof (gProcessGuid), &_nWritten)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
if ((hr = _pOriginalStream->Write(&pMarshalPtr, sizeof (pMarshalPtr), &_nWritten)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
}
else
{
DWORD dwFlag = 0;
// Out of proc case: write the DWORD and a blank DWORD for the NULL pointer
if ((hr = _pOriginalStream->Write(&hdr.dwSize, sizeof (hdr.dwSize), &_nWritten)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
if ((hr = _pOriginalStream->Write(&dwFlag, sizeof (dwFlag), &_nWritten)) != S_OK)
return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
}
}
if (!_operationSize)
{
if (!pMarshalPtr)
return E_UNEXPECTED;
return S_OK;
}
// See if given stream supports IBuffer otherwise create one that does
IBuffer *pibuff;
if (_pOriginalStream->QueryInterface(IID_IBuffer, (void**)&pibuff)!=S_OK)
{
// allocate more in case alignment needed
_bufSize = _operationSize + 8;
_pStream = new ActivationStream(_bufSize);
if (_pStream==NULL)
return E_OUTOFMEMORY;
hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
ASSERT(hr==S_OK);
pibuff = _pIBuff;
}
do // Loop until we get right buffer
{
// Invariant is that pibuff must exist by the time we get here
ASSERT(pibuff != 0);
// Set up our buffer appropriately
if (direction == DIRECTION_READ)
{
if (pibuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
return E_FAIL;
if (_bufSize < _operationSize)
return E_FAIL;
}
else
if (direction == DIRECTION_WRITE)
{
if (pibuff->GetOrCreateBuffer(_operationSize+GetSize(),
&_bufSize, &_buffer)!=S_OK)
return E_FAIL;
}
if(((LONG_PTR)_buffer)&0x7)
{
// If buffer is not 8 byte aligned, do it
if (pibuff != _pIBuff)
{
// Only get here if we are still using original
ASSERT(_pIBuff == 0);
// So release it and create a new aligned one
pibuff->Release();
_bufSize = _operationSize + 8;
_pStream = new ActivationStream(_bufSize);
if (_pStream==NULL)
return E_OUTOFMEMORY;
hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
ASSERT(hr==S_OK);
pibuff = _pIBuff; //Continue loop
}
else
{
// Got a buffer which we can align
ASSERT(_pIBuff != 0);
pibuff = 0; //Signal end of loop
// Align buffer
_start = (DWORD)(8-(((DWORD_PTR)_buffer)&7));
}
}
else
{
// We have an original good one
_pIBuff = pibuff;
pibuff = 0;
}
}
while (pibuff);
ASSERT(_pIBuff!=0);
// Set position for next operations and set up
// internal state correctly
hr = _pIBuff->SetPosition(_bufSize, _start);
ASSERT(hr == S_OK);
_bufSize -= _start;
_buffer += _start;
_position = 0;
if (direction==DIRECTION_READ)
{
if ((_pStream) && (_pOriginalStream != _pStream))
{
//If what we have is not the original one then we
//need to copy data into aligned address from original
DWORD nOver=0;
do {
if ((hr=_pOriginalStream->Read(_buffer+nOver,
_operationSize-nOver, &nRead))!= S_OK)
return hr;
nOver += nRead;
}
while (nOver<_operationSize);
_pOriginalStream->Release();
_pOriginalStream = 0; // Don't need original any longer
}
else
_pStream = _pOriginalStream; // Set operating to original
ASSERT(_pStream!=0);
// Create decoding handle for MES operations
MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
if (_handle == NULL)
return E_OUTOFMEMORY;
}
else
{
_nWritten = 0;
// Check if we are still using the orignal stream
if (_pStream == 0)
_pStream = _pOriginalStream;
// Create encoding handle for MES operations
MesEncodeFixedBufferHandleCreate((char*)_buffer,
_bufSize, &_nWritten, &_handle);
if (_handle == NULL)
return E_OUTOFMEMORY;
}
return S_OK;
}
/***************************************************************************/
/** Sets stream and state for further serialization operations **/
/** Assumes that a stream supporting IBuffer is provided. **/
/***************************************************************************/
inline HRESULT SetStream(IStream *pStream,DWORD dwOpSize,
DWORD direction)
{
// Set up internal state
_direction = direction;
_pOriginalStream = 0;
_pStream = pStream;
_operationSize = dwOpSize;
_pStream->AddRef();
// Assume IBuffer exists otherwise fail
if (_pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff)!=S_OK)
return E_FAIL;
if (_pIBuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
return E_FAIL;
if (_bufSize < _operationSize)
return E_FAIL;
// Set up MES handles
if (direction==DIRECTION_READ)
MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
else
MesEncodeFixedBufferHandleCreate((char*)_buffer,
_bufSize, &_nWritten, &_handle);
if (_handle == NULL)
return E_OUTOFMEMORY;
return S_OK;
}
// Gets MES handle
inline HRESULT GetSerializationHandle(void *pHandle)
{
*((handle_t*) pHandle) = _handle;
return S_OK;
}
// Gets MES handle for sizing operations
inline HRESULT GetSizingHandle(void *pHandle)
{
char dummy[30], *dummybuff;
unsigned long encodedSize;
handle_t handle;
dummybuff = (char*)(((LONG_PTR)(&dummy[7])) & ~7);
MesEncodeFixedBufferHandleCreate(dummybuff, 100, &encodedSize, (handle_t*)pHandle);
if ( (*(handle_t*)pHandle) == NULL)
return E_OUTOFMEMORY;
return S_OK;
}
//Signals end of operations on this object and commits
//operations to stream
inline HRESULT Commit()
{
// If we are not using original and we are writing,
// then we need to copy
if ((_pOriginalStream) && (_pOriginalStream != _pStream))
{
ASSERT(_direction==DIRECTION_WRITE);
HRESULT hr;
do
{
_nWritten = 0;
hr = _pOriginalStream->Write(_buffer,
_operationSize, &_nWritten);
if (hr != S_OK)
break;
_operationSize -= _nWritten;
_buffer += _nWritten;
}
while (_operationSize);
return hr;
}
else
return _pIBuff->SetPosition(_bufSize, _operationSize);
}
inline HRESULT SetPosition(DWORD dwPos)
{
RPC_STATUS rpcStat;
// Sets position in buffer and creates appropriate MES handle
HRESULT hr = _pIBuff->SetPosition(_bufSize, dwPos);
if (hr!=S_OK)
return hr;
MesHandleFree(_handle);
_handle = NULL;
if (_direction == DIRECTION_READ)
rpcStat = MesDecodeBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_handle);
else
{
_nWritten = 0;
rpcStat = MesEncodeFixedBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_nWritten, &_handle);
}
if (rpcStat != RPC_S_OK)
{
if ( HRESULT_FACILITY(rpcStat) == FACILITY_RPC )
return rpcStat;
else
return HRESULT_FROM_WIN32(rpcStat);
}
if (_handle == NULL)
return E_OUTOFMEMORY;
_position = dwPos;
return S_OK;
}
// Gets current position in buffer
inline HRESULT GetPosition(DWORD *pdwPos)
{
*pdwPos = _position;
return S_OK;
}
// Increment current position by specified amount in buffer
inline HRESULT IncrementPosition(DWORD dwInc)
{
return SetPosition(_position+dwInc);
}
// Get buffers underlying stream object
inline HRESULT GetStream(IStream **ppStream)
{
_pStream->AddRef();
*ppStream = _pStream;
return S_OK;
}
// Get a copy of this object
inline HRESULT GetCopy(Serializer **ppSer)
{
HRESULT hr=E_FAIL;
IStream *pNewStream;
if (_pStream)
{
ASSERT(_direction==DIRECTION_READ); //No need for any other case right now
hr = _pIBuff->SetPosition(_bufSize, 0);
ASSERT(hr==S_OK);
if (_pOriginalStream) // Still using original so clone
{
ASSERT(_start==0);
ASSERT(_pStream==_pOriginalStream);
hr = _pIBuff->SetCopyAlignment(8);
ASSERT(hr==S_OK);
hr = _pStream->Clone(&pNewStream);
if (hr != S_OK)
return hr;
}
else
{
pNewStream = _pStream;
}
Serializer *ser = new Serializer(_dwMaxDestCtx, _dwCurrentDestCtx, _dwMarshalFlags);
if (ser==NULL)
return E_OUTOFMEMORY;
hr = ser->SetStream(pNewStream, _operationSize, _direction);
if (FAILED(hr))
goto exit_point;
hr = ser->SetPosition(_position);
if (FAILED(hr))
goto exit_point;
hr = _pIBuff->SetPosition(_bufSize, _position);
if (FAILED(hr))
goto exit_point;
*ppSer = ser;
exit_point:
if (pNewStream != _pStream)
pNewStream->Release();
if (FAILED(hr))
{
ser->Release();
*ppSer = NULL;
}
}
return hr;
}
// Write provided buffer into our buffer at current position
// and advance position
inline HRESULT Write(BYTE *buff, DWORD nBytes)
{
if(nBytes > (_bufSize - _position))
return E_FAIL;
memcpy(_buffer+_position,buff, (size_t) nBytes);
IncrementPosition(nBytes);
return S_OK;
}
// Copy into provided Serializer our data at given position and length
inline HRESULT CopyTo(Serializer *pSer, DWORD dwPos, DWORD nBytes)
{
if(nBytes > (_bufSize - dwPos) )
return E_FAIL;
return pSer->Write(_buffer+dwPos, nBytes);
}
// return buffer starting at current position
inline HRESULT GetBufferAtCurrent(BYTE **ppBuff)
{
*ppBuff = _buffer+_position;
return S_OK;
}
inline void GetMaxDestCtx(OUT DWORD *pdwDestCtx)
{
*pdwDestCtx = _dwMaxDestCtx;
}
inline void GetCurrDestCtx(OUT DWORD *pdwDestCtx)
{
*pdwDestCtx = _dwCurrentDestCtx;
}
inline void GetMarshalFlags(OUT DWORD *pdwMarshalFlags)
{
*pdwMarshalFlags = _dwMarshalFlags;
}
static inline DWORD GetSize()
{
// fixed initialization length
return sizeof(SerializationHeader);
}
private:
IStream *_pStream;
IStream *_pOriginalStream;
IBuffer *_pIBuff;
BYTE *_buffer;
DWORD _nWritten;
DWORD _bufSize;
DWORD _operationSize;
handle_t _handle;
LONG _clRefs;
DWORD _direction;
DWORD _position;
DWORD _start;
DWORD _dwMaxDestCtx;
DWORD _dwCurrentDestCtx;
DWORD _dwMarshalFlags;
};
#endif //__SERIAL_HXX__