blob: 22b9a0dcb1efba0ef9cea7ed970d88015aa657bf [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
****************************************************************************
*
* File: IpcMessageObj.cpp (previously under /common)
* Description:
*
* Created: 5/6/98
* Language: C++
*
*
*
****************************************************************************
*/
#include "Platform.h"
#include "NAStdlib.h"
#include "Ipc.h"
#include "IpcMessageObj.h"
#include "str.h"
#include "ComDefs.h" // to get ROUND8
#include <byteswap.h>
// -----------------------------------------------------------------------
// Methods for class IpcMessageObj
// -----------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// general constructor, creates both unpacked, packed objects
IpcMessageObj::IpcMessageObj(IpcMessageObjType msgType,
IpcMessageObjVersion version)
{
s_.objType_ = (short) msgType;
s_.objVersion_ = version;
s_.refCount_ = 1; // an object comes with an initial refcount of 1
s_.objLength_ = 0;
s_.next_ = NULL;
s_.endianness_ = IpcMyEndianness;
s_.spare1_ = 0;
s_.spare2_ = 0;
s_.vPtrPad_ = NULL;
}
///////////////////////////////////////////////////////////////////////////////
// constructor used to perform copyless receive, maps packed objects in place.
IpcMessageObj::IpcMessageObj(IpcBufferedMsgStream* msgStream)
{
// IpcBufferedMsgStream parm used to differentiate from default constructor
if (s_.endianness_ != IpcMyEndianness)
{
swapFourBytes(s_.objType_);
swapFourBytes(s_.objVersion_);
swapFourBytes(s_.objLength_);
assert(0); // didn't implement
s_.refCount_ = 1; // an object comes with an initial refcount of 1
s_.endianness_ = IpcMyEndianness;
}
}
IpcMessageObj::~IpcMessageObj()
{
if (s_.refCount_ != 1)
{
// something went wrong!!!!!!!!!!!!!!!
//
// Take the two cases:
// a) the variable is allocated in static memory or in the stack
// b) the variable was allocated from the heap, using operator new
//
// For case a), the user isn't supposed to perform any increments
// or decrements of the ref count. One possibility is that he did.
// The other possibility is that there are still outstanding I/Os
// or other processes that share the object and therefore we
// shouldn't destroy it.
//
// For case b) it is similar. Either the user hasn't used increment
// and decrement refcount and then he can delete the object or
// get rid of it by decrementing the refcount (preferred method).
// Again, either the user forgot to decrement the refcount or
// the object is still shared by other components.
// Complain about the abuse
ABORT("trying to destroy a message object that is still in use");
}
}
///////////////////////////////////////////////////////////////////////////////
// used to allocate a packed send object.
void* IpcMessageObj::operator new(size_t size,
IpcBufferedMsgStream& msgStream,
IpcMessageObjSize appendDataLen)
{
IpcMessageObjSize appendStart = (IpcMessageObjSize) size;
alignSizeForNextObj(appendStart);
return (msgStream.sendMsgObj(appendStart + appendDataLen));
}
IpcMessageObjSize IpcMessageObj::packObjIntoMessage(
IpcMessageBufferPtr buffer)
{
return packObjIntoMessage(buffer, FALSE);
}
IpcMessageObjSize IpcMessageObj::packObjIntoMessage(IpcMessageBufferPtr buffer,
NABoolean swapBytes)
{
// copy the base class (IpcMessageObj) data members and calculate how
// many more bytes beyond the base class remain to be copied
IpcMessageObjSize derivedObjLen =
packedLength() - packBaseClassIntoMessage(buffer, swapBytes);
// ---------------------------------------------------------------------
// copy derivedObjLen bytes to the message buffer, assuming that
// the packed and unpacked representations of the object are the same,
// that whoever derived from this class did correctly override
// the packedLength() virtual function, and that the derived data is
// stored directly following the base class data (this may not be the
// case if multiple inheritance is used!!!!).
// ---------------------------------------------------------------------
str_cpy_all(buffer, (const char *) &this[1], derivedObjLen);
return derivedObjLen + sizeof(IpcMessageObj);
}
IpcMessageObjSize IpcMessageObj::packObjIntoMessage32(
IpcMessageBufferPtr buffer)
{
return packObjIntoMessage32(buffer, FALSE);
}
IpcMessageObjSize IpcMessageObj::packObjIntoMessage32(IpcMessageBufferPtr buffer,
NABoolean swapBytes)
{
// copy the base class (IpcMessageObj) data members and calculate how
// many more bytes beyond the base class remain to be copied
IpcMessageObjSize derivedObjLen =
packedLength32() - packBaseClassIntoMessage32(buffer, swapBytes);
// ---------------------------------------------------------------------
// copy derivedObjLen bytes to the message buffer, assuming that
// the packed and unpacked representations of the object are the same,
// that whoever derived from this class did correctly override
// the packedLength() virtual function, and that the derived data is
// stored directly following the base class data (this may not be the
// case if multiple inheritance is used!!!!).
// ---------------------------------------------------------------------
str_cpy_all(buffer, (const char *) &this[1], derivedObjLen);
return derivedObjLen + sizeof(IpcMessageObj);
}
void IpcMessageObj::unpackObj(IpcMessageObjType /*objType*/,
IpcMessageObjVersion /*objVersion*/,
NABoolean /*sameEndianness*/,
IpcMessageObjSize objSize,
IpcConstMessageBufferPtr buffer)
{
assert(objSize >= sizeof(IpcMessageObj));
// unpack the first sizeof(IpcMessageObj) bytes and fixup the virtual
// function pointer of the base class
unpackBaseClass(buffer);
// copy the rest into the memory following the IpcMessageObj data members
// (should we allow such a dangerous default implementation?)
str_cpy_all((char *) &this[1], buffer, objSize - sizeof(IpcMessageObj));
// - Change the offset in the next ptr to zero
//
s_.next_ = NULL;
}
void IpcMessageObj::unpackObj32(IpcMessageObjType /*objType*/,
IpcMessageObjVersion /*objVersion*/,
NABoolean /*sameEndianness*/,
IpcMessageObjSize objSize,
IpcConstMessageBufferPtr buffer)
{
assert(objSize >= SQL_32BIT_IPC_MESSAGE_OBJ_SIZE);
// unpack the first sizeof(IpcMessageObj) bytes and fixup the virtual
// function pointer of the base class
unpackBaseClass32(buffer);
// copy the rest into the memory following the IpcMessageObj data members
// (should we allow such a dangerous default implementation?)
str_cpy_all((char *) &this[1], buffer, objSize - SQL_32BIT_IPC_MESSAGE_OBJ_SIZE);
// - Change the offset in the next ptr to zero
//
s_.next_ = NULL;
}
NABoolean IpcMessageObj::checkObj(IpcMessageObjType t,
IpcMessageObjVersion v,
NABoolean sameEndianness,
IpcMessageObjSize size,
IpcConstMessageBufferPtr buffer) const
{
return checkBaseClass(t, v, sameEndianness, size, buffer);
}
NABoolean IpcMessageObj::checkBaseClass(IpcMessageObjType t,
IpcMessageObjVersion v,
NABoolean sameEndianness,
IpcMessageObjSize size,
IpcConstMessageBufferPtr &buffer) const
{
NABoolean result = TRUE;
const IpcConstMessageBufferPtr lastByte = buffer + size - 1;
if (!checkBuffer(buffer, sizeof(IpcMessageObj), lastByte) ||
s_.objType_ != t ||
s_.objVersion_ != v)
{
result = FALSE;
ipcIntegrityCheckEpilogue(result);
}
return result;
}
IpcMessageRefCount IpcMessageObj::incrRefCount()
{
return ++s_.refCount_;
}
IpcMessageRefCount IpcMessageObj::decrRefCount()
{
// delete this object if the result falls down to 0
// NOTE: users who allocate an IpcMessageObj on the stack should
// never call incrRefCount() or decrRefCount() on that object.
if (s_.refCount_ == 1)
{
// don't decrement the refcount; the destructor performs a
// consistency check that an object can only be destroyed
// when it has a refcount of 1
delete this;
return 0;
}
else
{
assert(s_.refCount_ > 1);
return --s_.refCount_;
}
}
IpcMessageObjSize IpcMessageObj::packBaseClassIntoMessage(
IpcMessageBufferPtr &buffer)
{
return packBaseClassIntoMessage(buffer, FALSE);
}
IpcMessageObjSize IpcMessageObj::packBaseClassIntoMessage(
IpcMessageBufferPtr &buffer, NABoolean swapBytes)
{
// the default implementation performs a byte-wise copy
IpcMessageObjSize copyLen = sizeof(IpcMessageObj);
char *savedVPtr = getMyVPtr();
assert(copyLen == 48 AND
sizeof(s_) == 40 AND
(char *) this == ((char *) &s_ - sizeof(char *)));
// wipe out the virtual function pointer before moving data
// (makes sure that the copied object doesn't have a stray pointer in it)
setMyVPtr(NULL);
// ---------------------------------------------------------------------
// Copy packedLength() bytes to the message buffer, assuming that
// the packed and unpacked representations of the object are the same
// and that whoever derived from this class did correctly override
// the packedLength() virtual function. No copy necessary if this
// is packing in-place.
// ---------------------------------------------------------------------
if (buffer == (IpcMessageBufferPtr) this)
{
// now that we're sending we won't allow anybody else to reference
// the object in the message buffer
assert(s_.refCount_ == 1);
}
else
{
// save the current refcount and set it to 1, since the copied object
// is in a new space and therefore should have a refcount of 1
IpcMessageRefCount saveRefCount = s_.refCount_;
IpcMessageObjVersion saveObjVersion = 0;
IpcMessageObjType saveObjType = IPC_MSG_SQLCAT_FIRST;
IpcMessageObjSize saveObjLength = 0;
char saveEndianness = 0;
s_.refCount_ = 1;
if (swapBytes)
{
saveObjType = s_.objType_;
saveObjVersion = s_.objVersion_;
saveEndianness = s_.endianness_;
saveObjLength = s_.objLength_;
s_.objType_ = bswap_32(s_.objType_);
s_.objVersion_ = bswap_32(s_.objVersion_);
// Switch the Endian since we are swapping the bytes
#ifdef NA_LITTLE_ENDIAN
s_.endianness_ = IpcBigEndian;
#else
s_.endianness_ = IpcLittleEndian;
#endif
s_.objLength_ = bswap_32(s_.objLength_);
s_.refCount_ = bswap_32(s_.refCount_);
}
str_cpy_all(buffer,(const char *)this,copyLen);
if (swapBytes)
{
s_.objType_ = saveObjType;
s_.objVersion_ = saveObjVersion;
s_.endianness_ = saveEndianness;
s_.objLength_ = saveObjLength;
}
// restore virtual function pointer and refCount_ for the in-memory copy
s_.refCount_ = saveRefCount;
setMyVPtr(savedVPtr);
}
buffer += copyLen;
return copyLen;
}
// pack the base class to be read by 32-bit BDR client
IpcMessageObjSize IpcMessageObj::packBaseClassIntoMessage32(
IpcMessageBufferPtr &buffer, NABoolean swapBytes)
{
// a hard-coded 32-bit IpcMessageObj class size
IpcMessageObjSize copyLen = SQL_32BIT_IPC_MESSAGE_OBJ_SIZE;
// cleanup buffer first
memset(buffer, 0, copyLen);
// ---------------------------------------------------------------------
// a 32 byte layout of this object:
//
// +---------------------------------+ \
// 0 | _vptr (NT) or padding (NSK) | |
// +---------------------------------+ |
// 4 | objType_ _ (copy) | |
// +---------------------------------+ |
// 8 | objVersion_ (copy) | |
// +---------------------------------+ |
// 12 | refCount_ (copy) | |
// +---------------------------------+ |
// 16 | objLength_ (copy) | > IpcMessageObjStruct
// +---------------------------------+ |
// 20 | next_ | |
// +---------------------------------+ |
// 24 | endianness_ (copy) | |
// +---------------------------------+ |
// 25 | spare1_ | |
// +---------------------------------+ |
// 26 | spare2_ | |
// +---------------------------------+ |
// 28 | _vptr (NSK) or padding (NT) | |
// +---------------------------------+ /
//
// need to copy only marked fields
// ---------------------------------------------------------------------
if (buffer == (IpcMessageBufferPtr) this)
{
// now that we're sending we won't allow anybody else to reference
// the object in the message buffer
assert(s_.refCount_ == 1);
}
else
{
// set refcount to 1, since the copied object
// is in a new space and therefore should have a refcount of 1
IpcMessageRefCount tempRefCount = 1;
IpcMessageObjVersion tempObjVersion = s_.objVersion_;
IpcMessageObjType tempObjType = s_.objType_;
IpcMessageObjSize tempObjLength = s_.objLength_;;
char tempEndianness = s_.endianness_;
if (swapBytes)
{
tempObjType = bswap_32(tempObjType);
tempObjVersion = bswap_32(tempObjVersion);
// Switch the Endian since we are swapping the bytes
#ifdef NA_LITTLE_ENDIAN
tempEndianness = IpcBigEndian;
#else
tempEndianness = IpcLittleEndian;
#endif
tempObjLength = bswap_32(tempObjLength);
tempRefCount = bswap_32(tempRefCount);
}
// move only needed fields, see above
memcpy((char*)buffer + 4, (char*)&tempObjType, 4);
memcpy((char*)buffer + 8, (char*)&tempObjVersion, 4);
memcpy((char*)buffer +12, (char*)&tempRefCount, 4);
memcpy((char*)buffer +16, (char*)&tempObjLength, 4);
memcpy((char*)buffer +24, (char*)&tempEndianness, 1);
}
buffer += copyLen;
return copyLen;
}
void IpcMessageObj::alignBufferForNextObj(IpcConstMessageBufferPtr &buffer)
{
buffer = (IpcConstMessageBufferPtr) ROUND8((Long)buffer);
}
void IpcMessageObj::alignBufferForNextObj(IpcMessageBufferPtr &buffer)
{
buffer = (IpcMessageBufferPtr) ROUND8((Long)buffer);
}
void IpcMessageObj::alignSizeForNextObj(IpcMessageObjSize &size)
{
ULng32 s = (ULng32) size; // just for safety
// clear the last 3 bits of the size to round it down to
// the next size that is divisible by 8
ULng32 roundedDown = s LAND 0xFFFFFFF8;
// if that didn't change anything we're done, the size was
// a multiple of 8 already
if (s != roundedDown)
{
// else we have to round up and add the filler
size = (IpcMessageObjSize) roundedDown + 8;
}
}
void IpcMessageObj::unpackBaseClass(IpcConstMessageBufferPtr &buffer)
{
// save the virtual function pointer (it is already set to the correct value)
char *savedVPtr = getMyVPtr();
// copy objSize bytes into the memory that this object occupies
// this header (should we allow such a dangerous default implementation?)
str_cpy_all((char *) this,buffer,sizeof(IpcMessageObj));
// restore the previously saved virtual function pointer, since it got
// overwritten with a NULL value by the copy operation above
// NOTE: this of course assumes that derived classes don't need their
// own virtual function pointers!!!
setMyVPtr(savedVPtr);
// - Change the offset in the next ptr to zero
//
s_.next_ = NULL;
buffer += sizeof(IpcMessageObj);
}
// unpack base class got from 32-bit server
void IpcMessageObj::unpackBaseClass32(IpcConstMessageBufferPtr &buffer)
{
// copy only selected fields from the buffer
memcpy((char*)&(s_.objType_), (char*)buffer + 4, 4);
memcpy((char*)&(s_.objVersion_), (char*)buffer + 8, 4);
memcpy((char*)&(s_.refCount_), (char*)buffer +12, 4);
memcpy((char*)&(s_.objLength_), (char*)buffer +16, 4);
memcpy((char*)&(s_.endianness_), (char*)buffer +24, 1);
s_.next_ = NULL;
buffer += SQL_32BIT_IPC_MESSAGE_OBJ_SIZE;
}
IpcMessageObjSize IpcMessageObj::packDependentObjIntoMessage(
IpcMessageBufferPtr buffer)
{
return packDependentObjIntoMessage(buffer, FALSE);
}
IpcMessageObjSize IpcMessageObj::packDependentObjIntoMessage(
IpcMessageBufferPtr buffer, NABoolean swapBytes)
{
IpcMessageBufferPtr alignedBuffer = buffer;
alignBufferForNextObj(alignedBuffer);
// pack the object and compute the length
IpcMessageObjSize result = packObjIntoMessage(alignedBuffer, swapBytes);
// finish the object that is now inside the buffer, similarly to what
// IpcMessageStream::send() does
IpcMessageObj *bufObj = (IpcMessageObj *) alignedBuffer;
bufObj->setMyVPtr(NULL);
bufObj->s_.objLength_ = result;
bufObj->s_.refCount_ = 1;
bufObj->s_.next_ = NULL;
if (swapBytes)
{
bufObj->s_.objLength_ = bswap_32(bufObj->s_.objLength_);
bufObj->s_.refCount_ = bswap_32(bufObj->s_.refCount_);
}
// add the filler space that had to be added to the returned result
result += (alignedBuffer - buffer);
return result;
}
IpcMessageObjSize IpcMessageObj::packDependentObjIntoMessage32(
IpcMessageBufferPtr buffer)
{
return packDependentObjIntoMessage32(buffer, FALSE);
}
IpcMessageObjSize IpcMessageObj::packDependentObjIntoMessage32(
IpcMessageBufferPtr buffer, NABoolean swapBytes)
{
IpcMessageBufferPtr alignedBuffer = buffer;
alignBufferForNextObj(alignedBuffer);
// pack the object and compute the length
IpcMessageObjSize result = packObjIntoMessage32(alignedBuffer, swapBytes);
IpcMessageObjSize sResult = result; // swapped result if does
Int32 refCount = 1;
Int32 firstField = 0; // assume Linux where vPtrPad_ is at the end
if (swapBytes)
{
// send to NSK where vPtrPad_ is at the beginning of the structure.
firstField = 4;
refCount = bswap_32(refCount);
sResult = bswap_32(sResult);
}
// finish the object that is now inside the buffer by move only needed fields
memset((char*)alignedBuffer, 0, 4); // vPtrPad_
memcpy((char*)alignedBuffer + 12, (char*)&refCount, 4); // refCount_
memcpy((char*)alignedBuffer + 16, (char*)&sResult, 4); // objLength_
memset((char*)alignedBuffer + 20, 0, 4); // next_
memset((char*)alignedBuffer + 28, 0, 4); // vPtrPad_
// add the filler space that had to be added to the returned result
result += (alignedBuffer - buffer);
return result;
}
void IpcMessageObj::unpackDependentObjFromBuffer(
IpcConstMessageBufferPtr &buffer,
NABoolean sameEndianness)
{
alignBufferForNextObj(buffer);
IpcMessageObj *objInBuffer = (IpcMessageObj *) buffer;
IpcMessageObjSize objLength = objInBuffer->s_.objLength_;
unpackObj(objInBuffer->s_.objType_,
objInBuffer->s_.objVersion_,
sameEndianness,
objLength,
buffer);
buffer += objLength;
}
void IpcMessageObj::unpackDependentObjFromBuffer32(
IpcConstMessageBufferPtr &buffer,
NABoolean sameEndianness)
{
alignBufferForNextObj(buffer);
// NEEDS PORT
// The problem here is that IpcMessageObjStruct does not contain
// the 4 bytes allocated for the virtual function table pointer and
// on NT the vftptr is BEFORE the structure and on unix/NSK it is after.
IpcMessageObjType objType = *(Int32 *)((char *)buffer + 4); // objType_
IpcMessageObjVersion objVersion = *(Int32 *)((char *)buffer + 8); // objVersion_
IpcMessageObjSize objLength = *(Int32 *)((char *)buffer + 16); // objLength_
unpackObj32(objType,
objVersion,
sameEndianness,
objLength,
buffer);
buffer += objLength;
}
NABoolean IpcMessageObj::checkDependentObj(IpcConstMessageBufferPtr &buffer,
NABoolean sameEndianness) const
{
alignBufferForNextObj(buffer);
IpcMessageObj *objInBuffer = (IpcMessageObj *) buffer;
IpcMessageObjSize objLength = objInBuffer->s_.objLength_;
if (!checkObj(objInBuffer->s_.objType_,
objInBuffer->s_.objVersion_,
sameEndianness,
objLength,
buffer))
{
return FALSE;
}
buffer += objLength;
return TRUE;
}
void IpcMessageObj::turnByteOrder()
{
// NEEDS PORT (2/26/97)
// the code to handle endianness is not quite right. as a temporary
// measure for the demo, turn this code off.
return;
}
///////////////////////////////////////////////////////////////////////////////
// merge next packed message object in IpcMessageBuffer with this object
void IpcMessageObj::mergeNextPackedObj()
{
IpcMessageObj* nextObj = getNextFromOffset();
if (nextObj)
{
if (nextObj->s_.next_)
{
IpcMessageObj * offset = (IpcMessageObj*) (
(Long)(s_.next_) + (char *)(nextObj->s_.next_));
s_.next_ = (IpcMessageObj*)offset;
}
else
s_.next_ = NULL;
}
return;
}
IpcMessageObj *IpcMessageObj::getNextFromOffset()
{
if (s_.next_ == NULL)
return NULL;
else
// add the "this" pointer to the offset
return (IpcMessageObj *) ((char*) this + (Long) s_.next_);
}
void IpcMessageObj::convertNextToOffset()
{
// subtract the "this" pointer from the address to make it an offset
if (s_.next_ != NULL)
s_.next_ = (IpcMessageObj *) ((char*) s_.next_ - (char*) this);
}
IpcMessageObjSize packCharStarIntoBuffer(IpcMessageBufferPtr &buffer,
char* strPtr, NABoolean swapBytes)
{
Lng32 length;
if (strPtr==NULL)
length=0;
else
length=str_len(strPtr)+1; // 1 is for the null-terminator char
// NOT a recursive call.
IpcMessageObjSize result = packIntoBuffer(buffer,length, swapBytes);
if (strPtr!=NULL)
str_cpy_all((char*)buffer,strPtr,length);
buffer += length;
return result+length;
}
// UR2
IpcMessageObjSize packCharStarIntoBuffer(IpcMessageBufferPtr &buffer,
NAWchar* strPtr, NABoolean swapBytes)
{
Lng32 length;
if (strPtr==NULL)
length=0;
else
length=na_wcslen(strPtr)+1; // 1 is for the null-terminator char
length *= sizeof(NAWchar);
// NOT a recursive call.
IpcMessageObjSize result = packIntoBuffer(buffer,length, swapBytes);
if (strPtr!=NULL)
na_wcscpy((NAWchar*)buffer,strPtr);
buffer += length;
return result+length;
}
void unpackBuffer(IpcConstMessageBufferPtr &buffer,
char* &strPtr,
CollHeap* collHeapPtr)
{
if (collHeapPtr != NULL)
collHeapPtr->deallocateMemory(strPtr);
else
delete strPtr;
Lng32 length;
// NOT a recursive call.
unpackBuffer(buffer,length); // already has +1 for null terminating char
if (length==0)
strPtr = NULL;
else {
if (collHeapPtr != NULL) {
strPtr = (char*) (collHeapPtr->allocateMemory(length));
assert(strPtr!=NULL);
}
else {
strPtr = new char[length];
assert(strPtr!=NULL);
}
str_cpy_all(strPtr,(char*) buffer, length);
buffer += length;
}
}
void skipCharStarInBuffer(IpcConstMessageBufferPtr &buffer)
{
Lng32 length;
// NOT a recursive call.
unpackBuffer(buffer,length); // already has +1 for null terminating char
buffer += length;
}
// Verify that the next field in a message buffer does not extend
// beyond lastByte.
NABoolean checkBuffer (
/* INOUT */ IpcConstMessageBufferPtr &buffer,
/* IN */ ULng32 dataLength,
/* IN */ IpcConstMessageBufferPtr lastByte )
{
NABoolean result = TRUE;
IpcConstMessageBufferPtr endOfData = buffer + dataLength - 1;
if (endOfData > lastByte)
{
result = FALSE;
ipcIntegrityCheckEpilogue(result);
}
else
{
buffer += dataLength;
}
return result;
}
// Verify that the next field in a message buffer does not extend
// beyond lastByte, and if it does then copy the field into dataPtr.
NABoolean checkAndUnpackBuffer (
/* INOUT */ IpcConstMessageBufferPtr &buffer,
/* IN */ ULng32 dataLength,
/* OUT */ char *dataPtr,
/* IN */ IpcConstMessageBufferPtr lastByte )
{
NABoolean result = TRUE;
IpcConstMessageBufferPtr endOfData = buffer + dataLength - 1;
if (endOfData > lastByte)
{
result = FALSE;
ipcIntegrityCheckEpilogue(result);
}
else
{
str_cpy_all(dataPtr, (char *) buffer, dataLength);
buffer += dataLength;
}
return result;
}
// Verify that the next string field in a message buffer does not
// extend beyond lastByte. Note that the packed format for a string
// includes a 4-byte length field as a prefix.
NABoolean checkCharStarInBuffer (
/* INOUT */ IpcConstMessageBufferPtr &buffer,
/* IN */ NABoolean sameEndianness,
/* IN */ IpcConstMessageBufferPtr lastByte )
{
NABoolean result = TRUE;
Int32 dataLength = 0;
if (!checkAndUnpackBuffer(buffer, sizeof(dataLength),
(char *) &dataLength, lastByte))
{
result = FALSE;
ipcIntegrityCheckEpilogue(result);
}
else
{
if (!sameEndianness)
{
swapFourBytes(dataLength);
}
if (!checkBuffer(buffer, dataLength, lastByte))
{
result = FALSE;
ipcIntegrityCheckEpilogue(result);
}
}
return result;
}
// IpcMessageObj::checkObj() implementations all call this function
// immediately when they detect a failure. Setting a breakpoint here
// can help you quickly track down the cause of a checkObj()
// failure. Right now this function is just a wrapper around
// NAError_stub_for_breakpoints() but in the future we may decide it
// should also do some bookeeping or error reporting of its own.
void ipcIntegrityCheckEpilogue(NABoolean status)
{
if (!status)
{
NAError_stub_for_breakpoints();
}
}