blob: ffc0790c21b3342a51cb40c2efe2beea32cf0863 [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.h (previously under /common)
* Description: IpcMessageObj is the base class for objects that need to
* be sent across an IPC interface (see file common/Ipc.h).
*
* Created: 5/6/98
* Language: C++
*
*
*
****************************************************************************
*/
#ifndef IPCMESSAGEOBJ_H
#define IPCMESSAGEOBJ_H
#include "Platform.h"
#include "str.h"
#include "IpcMessageType.h"
#include "CollHeap.h"
#include <byteswap.h>
// -----------------------------------------------------------------------
// Contents of this file
// -----------------------------------------------------------------------
class IpcMessageObj;
// -----------------------------------------------------------------------
// Forward references
// -----------------------------------------------------------------------
class IpcMessageStream;
class IpcBufferedMsgStream;
class IpcMessageBuffer;
// size of 32-bit IpcMessageObj base class
#define SQL_32BIT_IPC_MESSAGE_OBJ_SIZE 32
// -----------------------------------------------------------------------
// IpcMessageObj is the base class of all objects that are sent in
// messages. This class contains fields to identify the object in
// the message and to determine its length and version. It also
// contains some fields that are used internally.
// IpcMessageObj has some virtual methods that allow a user of this
// class to redefine the methods to pack and unpack data into and from
// the message. A virtual method can also be used to determine the
// length of the message when it gets packed into the message.
// -----------------------------------------------------------------------
class IpcMessageObj
{
friend class IpcMessageStream;
friend class IpcBufferedMsgStream;
friend class SockSocket; // to access message header information
// A friend function to enable internal integrity checks in
// IpcMessageBuffer objects.
friend NABoolean verifyIpcMessageBufferBackbone(IpcMessageBuffer &);
public:
// ---------------------------------------------------------------------
// Constructor, to be used by derived classes to specify type and
// version of the object.
// ---------------------------------------------------------------------
IpcMessageObj(IpcMessageObjType objType,
IpcMessageObjVersion version);
// constructor used to perform copyless receive, maps packed object in place.
// Derived class should handle endianness. A message stream may route
// a message after unpacking some of the objects so a message object must
// deal with potentially being unpacked multiple times.
IpcMessageObj(IpcBufferedMsgStream* msgStream);
// destructor
virtual ~IpcMessageObj();
// used to allocate a packed send object. Operator "new" gets
// packedObj from class IpcBufferedMsgStream, then sets "this =
// packedObj" for constructor. "AppendDataLen" allows raw data
// allocation in the message buffer following the packed object for
// packing raw data. "new" can be recalled multiple times during
// construction of complex objects. The root object and all branch
// objects must be derived from IpcMessageObj. Unpacking complex
// objects on the receive side must be in same order as construction
// on the send side.
void* operator new(size_t size,
IpcBufferedMsgStream& msgStream,
IpcMessageObjSize appendDataLen = 0);
// used to perform copyless receive. User must get packedObj from
// IpcBufferedMsgStream::receiveMsgObj(). "new" sets "this = packedObj"
// for constructor so object can be mapped inplace.
void* operator new(size_t size, IpcMessageObj* packedObj)
{ return packedObj; }
// interface to global ::operator new
void* operator new(size_t size, CollHeap* h = NULL)
{ return (h ? h->allocateMemory(size) : ::operator new(size)); }
void operator delete(void *ptr) { ::operator delete(ptr); }
// ---------------------------------------------------------------------
// accessor methods
// ---------------------------------------------------------------------
Int32 getType() const { return (Int32) s_.objType_; }
Int32 getObjLength() const { return (Int32) s_.objLength_; }
IpcMessageObjVersion getVersion() const { return s_.objVersion_; }
void setType(IpcMessageObjType t) { s_.objType_ = t; }
void setVersion(IpcMessageObjVersion v) { s_.objVersion_ = v; }
char getEndianness() const { return s_.endianness_; }
void setEndianness(char e) { s_.endianness_ = e; }
// ---------------------------------------------------------------------
// A way for the user object to tell if the actual version is OK.
// The default is that the actual version is OK only if it matches the object.
//
virtual NABoolean isActualVersionOK (const IpcMessageObjVersion actualVersion) const
{ return (actualVersion == s_.objVersion_);}
// ---------------------------------------------------------------------
// A way for the user object to tell the message system how much space
// to reserve for the packed object (always override this!!).
// Usually, the overriding method looks like this:
//
// IpcMessageObjSize MyDerivedObject::packedLength()
// {
// return (IpcMessageObjSize) sizeof(*this);
// }
//
// Exception: if you are able to compress the object before copying
// it into a message, or if you have to add dependent objects.
// Use method baseClassPackedLength() to find out about the space
// requirements of the IpcMessageObj base class (which must be included
// in the returned result).
// ---------------------------------------------------------------------
virtual IpcMessageObjSize packedLength()
{ return (IpcMessageObjSize) sizeof(*this); }
// hard-code the IpcMessageObj class size on 32-bit mode
// maybe baseClassPackedLength32 is actually used
virtual IpcMessageObjSize packedLength32()
{ return SQL_32BIT_IPC_MESSAGE_OBJ_SIZE; }
// ---------------------------------------------------------------------
// A method to take a user object and pack it into a message
// (buffer has a length of packedLength() bytes, unless a fixed
// length > 0 has been specified in the constructor).
// The default implementation simply copies packedLength() bytes from
// this object into the buffer.
// If you override this function, make sure that you also pack the
// object header (members of IpcMessageObj) into the message by
// calling IpcMessageObj::packBaseClassIntoMessage(). Do not attempt to
// pack the message header yourself, as some fields get altered
// in the call. It is safe, however, to assume that the packed length
// of the header is the same as its unpacked length (32 bytes, see below).
// ---------------------------------------------------------------------
virtual IpcMessageObjSize packObjIntoMessage(
IpcMessageBufferPtr buffer);
virtual IpcMessageObjSize packObjIntoMessage(
IpcMessageBufferPtr buffer, NABoolean swapBytes);
virtual IpcMessageObjSize packObjIntoMessage32(
IpcMessageBufferPtr buffer);
virtual IpcMessageObjSize packObjIntoMessage32(
IpcMessageBufferPtr buffer, NABoolean swapBytes);
// ---------------------------------------------------------------------
// Unpack this object from a buffer (overwrites all existing data
// in this object). The default implementation simply copies a data
// block of objSize bytes over this object and then restores the
// virtual function pointer of the base class, IpcMessageObj.
// If your derived class also has virtual functions or if you need to
// do something other than simply copying the data, then override this!!
// The parameters passed in are:
// - object type and version used for packing the object
// - an indicator whether the object was packed on a machine with the
// same endianness (byte order) as this one
// - the size of the packed object (includes space for this class,
// IpcMessageObj, see baseClassPackedLength() method)
// - the array of bytes that contains the packed data
// ---------------------------------------------------------------------
virtual void unpackObj(IpcMessageObjType objType,
IpcMessageObjVersion objVersion,
NABoolean sameEndianness,
IpcMessageObjSize objSize,
IpcConstMessageBufferPtr buffer);
virtual void unpackObj32(IpcMessageObjType objType,
IpcMessageObjVersion objVersion,
NABoolean sameEndianness,
IpcMessageObjSize objSize,
IpcConstMessageBufferPtr buffer);
// ---------------------------------------------------------------------
// increment/decrement refcounts (indicates how many users the
// object has at this moment). The following operations affect the refcount:
// -- The constructor sets the refcount to 1
// -- Adding an object to a message increments the refcount, unless the
// message doesn't share objects
// -- Sending a message decreases the refcount of a shared object (depending
// on the underlying message system, the refcount of shared objects is
// decreased during the send operation or when the I/O completes or when
// the receiving process releases the shared object.
// -- An object that is copied from a message during a receive operation
// keeps the refcount of the target object.
// -- The incrRefCount() and decrRefCount() methods can be called by
// the user to indicate how many references the user has to the object
// (increment for any additional references except the first), decrement
// when references go away, except when the object is allocated on the
// stack or in a static area and goes out of scope.
// -- For objects allocated on the stack or for global objects, the user
// should NOT call the incrRefCount() or decrRefCount() methods. No
// special handling is necessary when those objects go out of scope.
// The program will abend, however, if such objects go out of scope
// while they are still shared with another component (like an
// outstanding I/O).
// -- For objects allocated with operator new, the user should use the
// decrRefCount() method to indicate that the object can be deleted.
// Actual deletion will be delayed until the object is no longer needed.
// Using operator delete on such objects is not recommended. If it
// is used anyway, the program will abend if the refcount of the object
// is not equal to 1.
// -- Override these functions, for example, if your object has an
// operator delete that needs to be called instead of global operator
// delete.
// ---------------------------------------------------------------------
virtual IpcMessageRefCount incrRefCount();
virtual IpcMessageRefCount decrRefCount();
IpcMessageRefCount getRefCount() { return s_.refCount_; }
// ---------------------------------------------------------------------
// Helper methods for derived classes that override the
// packObjIntoMessage method
// ---------------------------------------------------------------------
// find out the packed length of the base class part of this object
inline IpcMessageObjSize baseClassPackedLength()
{return sizeof(*this);}
// find out the packed length of the 32-bit base class part of this object
inline IpcMessageObjSize baseClassPackedLength32()
{return SQL_32BIT_IPC_MESSAGE_OBJ_SIZE;}
// pack the base class part of this object into the buffer and side-effect
// the buffer pointer to point past that packed object
IpcMessageObjSize packBaseClassIntoMessage(
IpcMessageBufferPtr &buffer);
// pack the base class to be read by 32-bit (BDR) client
IpcMessageObjSize packBaseClassIntoMessage32(
IpcMessageBufferPtr &buffer, NABoolean swapBytes);
// pack the base class part of this object into the buffer after swapping
// if swapBytes is true
// and side-effect the buffer pointer to point past that packed object
IpcMessageObjSize packBaseClassIntoMessage(
IpcMessageBufferPtr &buffer, NABoolean swapBytes);
// add filler to a buffer pointer so it points to an 8 byte aligned address
// (must be done before packing a dependent IpcMessageObj into a buffer)
static void alignBufferForNextObj(
IpcConstMessageBufferPtr &buffer);
static void alignBufferForNextObj(
IpcMessageBufferPtr &buffer);
// do the same as alignBufferForNextObj, but with a size instead of a buffer
static void alignSizeForNextObj(IpcMessageObjSize &size);
// unpack the base class part from the buffer and side-effect the buffer
// to point to directly past the base class part
void unpackBaseClass(IpcConstMessageBufferPtr &buffer);
// unpack base class got from 32-bit server
void unpackBaseClass32(IpcConstMessageBufferPtr &buffer);
IpcMessageObjSize packDependentObjIntoMessage(
IpcMessageBufferPtr buffer, NABoolean swapBytes);
// pack a dependent object that is also an IpcMessageObj into a buffer
// (don't call packObjIntoMessage() directly to do this)
IpcMessageObjSize packDependentObjIntoMessage(
IpcMessageBufferPtr buffer);
IpcMessageObjSize packDependentObjIntoMessage32(
IpcMessageBufferPtr buffer, NABoolean swapBytes);
// pack a dependent object that is also an IpcMessageObj into a buffer
// (don't call packObjIntoMessage() directly to do this)
IpcMessageObjSize packDependentObjIntoMessage32(
IpcMessageBufferPtr buffer);
// unpack a dependent IpcMessageObj object from a buffer and side-effect
// the buffer to point directly past the object that was unpacked
// (this methods reads object type and version from the buffer and
// then calls the virtual method unpackObj(), so it needs to be
// called on the dependent object that has its virtual function ptr. set up)
void unpackDependentObjFromBuffer(
IpcConstMessageBufferPtr &buffer,
NABoolean sameEndianness);
void unpackDependentObjFromBuffer32(
IpcConstMessageBufferPtr &buffer,
NABoolean sameEndianness);
// ---------------------------------------------------------------------
// The following "check" methods are used prior to unpacking to
// verify that the unpacking of a packed object will not create
// inconsistent structures or bad pointers. Currently we only do
// these checks on replies from the non-trusted UDR server.
//
// checkObj() is a virtual method and should be overridden in
// message classes used ir UDR replies.
//
// checkBaseClass() and checkDependentObj() are non-virtual helper
// functions that can be used in overridden checkObj() methods.
// ---------------------------------------------------------------------
virtual NABoolean checkObj(IpcMessageObjType t,
IpcMessageObjVersion v,
NABoolean sameEndianness,
IpcMessageObjSize size,
IpcConstMessageBufferPtr buffer) const;
NABoolean checkDependentObj(IpcConstMessageBufferPtr &buffer,
NABoolean sameEndianness) const;
NABoolean checkBaseClass(IpcMessageObjType t,
IpcMessageObjVersion v,
NABoolean sameEndianness,
IpcMessageObjSize size,
IpcConstMessageBufferPtr &buffer) const;
IpcMessageObj *getNextFromOffset();
protected:
// turn the representation of the internal object from little-endian
// to big-endian and vice versa (used by communication services that
// talk between big-endians and little-endians, e.g. sockets)
public:
void turnByteOrder();
private:
// Called to check if IpcMessageObj in IpcMessageBuffer is available for
// recycle. Derived classes MUST define if using copyless receive and object
// needs to persist beyond the unpacking of the complete receive message. If
// this method is not defined by the derived class then it will be guaranteed
// to persist until the current receive message is advanced via
// IpcBufferedMsgStream::getNextReceiveMsg().
virtual NABoolean msgObjIsFree()
{ return(TRUE); }
// prepare object for send. Called prior to sending the IPC message via
// IpcBufferedMsgStream::prepSendMsgForOutput(). Derived class may define
// to deal with transport issues such as changing pointers to offsets, etc.
virtual void prepMsgObjForSend()
{ return; }
// merge next packed message object in IpcMessageBuffer with this object
void mergeNextPackedObj();
// make the data members reside in their own struct, since this is the unit
// of transfer between in-memory objects and messages
// NOTE: the struct does not contain the _vptr data member of the class!!!
struct IpcMessageObjStruct
{
IpcMessageObjType objType_;
IpcMessageObjVersion objVersion_;
IpcMessageRefCount refCount_;
IpcMessageObjSize objLength_; // used by IpcMessageStream only
IpcMessageObj *next_; // IpcBufferedMsgStream - offset only
// IpcMessageStream - offset and ptr
char endianness_; // big-endian, little endian
char spare1_; // spare for future use
short spare2_; // spare for future use
char* vPtrPad_; // if NT or HSC, allocate space for NSK vptr
} s_;
// ---------------------------------------------------------------------
// we assume a 32 byte layout of this object that is as follows:
//
// +---------------------------------+ \
// 0 | _vptr (NT) or padding (NSK) | |
// +---------------------------------+ |
// 4 | objType_ _ | |
// +---------------------------------+ |
// 8 | objVersion_ | |
// +---------------------------------+ |
// 12 | refCount_ | |
// +---------------------------------+ |
// 16 | objLength_ | > IpcMessageObjStruct
// +---------------------------------+ |
// 20 | next_ | |
// +---------------------------------+ |
// 24 | endianness_ | |
// +---------------------------------+ |
// 25 | spare1_ | |
// +---------------------------------+ |
// 26 | spare2_ | |
// +---------------------------------+ |
// 28 | _vptr (NSK) or padding (NT) | |
// +---------------------------------+ /
//
// And, although we are ashamed to admit it, we access the virtual
// function pointer, if necessary, by using ((char **) (&this[1]))[-1]
//
// Note: in the packed representation, each packed object starts on
// an address that is aligned on an 8 byte boundary. Since
// sizeof(IpcMessageObj) == 32, the part for a derived object also
// starts on an address that is aligned on an 8 byte boundary.
// ---------------------------------------------------------------------
char *getMyVPtr() { return ((char **) (&this[0]))[0]; }
void setMyVPtr(char *v) { ((char **) (&this[0]))[0] = v; }
// return a pointer to the next object in the message by converting
// the relative offset stored in next_ back into a pointer
// convert the next_ pointer into an offset
void convertNextToOffset();
};
// -----------------------------------------------------------------------
// Functions (templates, too) for packing and unpacking scalars.
// "Check" functions are also provided to determine whether a buffer
// has sufficient space for an item of a given size.
// -----------------------------------------------------------------------
IpcMessageObjSize packCharStarIntoBuffer(IpcMessageBufferPtr &buffer,
char* strPtr,
NABoolean swapBytes = FALSE);
// UR2
IpcMessageObjSize packCharStarIntoBuffer(IpcMessageBufferPtr &buffer,
NAWchar* strPtr,
NABoolean swapBytes = FALSE);
inline IpcMessageObjSize packStrIntoBuffer(char* &buffer,
char* targetObj,
ULng32 objSize)
{
str_cpy_all(buffer, targetObj, (Lng32)objSize);
buffer += objSize;
return objSize;
}
void unpackBuffer(const char* &buffer,
char* &strPtr, CollHeap* collHeapPtr);
inline void unpackStrFromBuffer(const char* &buffer,
char* targetObj,
ULng32 objSize)
{
str_cpy_all(targetObj, buffer, (Lng32)objSize);
buffer += objSize;
}
void skipCharStarInBuffer(const char* &buffer);
NABoolean checkBuffer (
/* INOUT */ IpcConstMessageBufferPtr &buffer,
/* IN */ ULng32 dataLength,
/* IN */ IpcConstMessageBufferPtr lastByte );
NABoolean checkAndUnpackBuffer (
/* INOUT */ IpcConstMessageBufferPtr &buffer,
/* IN */ ULng32 dataLength,
/* OUT */ char *dataPtr,
/* IN */ IpcConstMessageBufferPtr lastByte );
NABoolean checkCharStarInBuffer (
/* INOUT */ IpcConstMessageBufferPtr &buffer,
/* IN */ NABoolean sameEndianness,
/* IN */ IpcConstMessageBufferPtr lastByte );
// An integrity check epilogue function is provided here. It should be
// called whenever an overridden IpcMessageObj::checkObj()
// implementation detects a failure. The global "check" functions
// above call this epilogue when they detect a failure. If a
// checkObj() method detects a failure by some means other than by
// calling one of the "check" functions, it should call the epilogue
// before returning FALSE. Current the epilogue's only purpose is as a
// debugging aid. By setting a breakpoint on the epilogue you can
// quickly track down the cause of a checkObj() failure.
void ipcIntegrityCheckEpilogue(NABoolean status);
template <class ScalarType>
inline IpcMessageObjSize packIntoBuffer(char* &buffer,
ScalarType scalarVariable)
{
// * (ScalarType *) buffer = scalarVariable;
str_cpy_all(buffer,(char*)&scalarVariable,sizeof(ScalarType));
buffer += sizeof(ScalarType);
return sizeof(ScalarType);
}
template <class ScalarType>
inline IpcMessageObjSize packIntoBuffer(char* &buffer,
ScalarType scalarVariable,
NABoolean swapBytes)
{
if (swapBytes)
{
switch (sizeof(ScalarType))
{
case 2:
scalarVariable = (ScalarType)bswap_16(scalarVariable);
break;
case 4:
scalarVariable = (ScalarType)bswap_32(scalarVariable);
break;
case 8:
scalarVariable = (ScalarType)bswap_64(scalarVariable);
break;
}
}
// * (ScalarType *) buffer = scalarVariable;
str_cpy_all(buffer,(char*)&scalarVariable,sizeof(ScalarType));
buffer += sizeof(ScalarType);
return sizeof(ScalarType);
}
template <class ScalarType>
inline void unpackBuffer(const char* &buffer,
ScalarType& scalarVariable)
{
// scalarVariable = * (ScalarType *) buffer;
ScalarType temp;
str_cpy_all((char*) &temp,buffer,sizeof(ScalarType));
scalarVariable = temp;
buffer += sizeof(ScalarType);
}
inline void swapFourBytes(UInt32 &b4)
{
char *c4 = (char *) (&b4);
char x;
x = c4[0]; c4[0] = c4[3]; c4[3] = x;
x = c4[1]; c4[1] = c4[2]; c4[2] = x;
}
inline void swapFourBytes(Int32 &b4)
{
char *c4 = (char *) (&b4);
char x;
x = c4[0]; c4[0] = c4[3]; c4[3] = x;
x = c4[1]; c4[1] = c4[2]; c4[2] = x;
}
inline void swapTwoBytes(unsigned short &b2)
{
char *c2 = (char *) (&b2);
char x;
x = c2[0]; c2[0] = c2[1]; c2[1] = x;
}
inline void swapTwoBytes(short &b2)
{
char *c2 = (char *) (&b2);
char x;
x = c2[0]; c2[0] = c2[1]; c2[1] = x;
}
#endif /* IPCMESSAGEOBJ_H */