From d254c83c84f230b2fb07c54325c4b6180a7ed4c8 Mon Sep 17 00:00:00 2001 From: "Bruno G. Albuquerque" Date: Sat, 17 Jan 2009 21:28:10 +0000 Subject: [PATCH] - Changed BNetBuffer to a simpler (and R5 compatible) implementation. - This has the side effect that now it actually works. - This also indirectly fix BNetEndpoint usage of BNetBuffer. - Added DynamicBuffer (the underlying buffer implementation) to the Jamfile. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28928 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/net/NetBuffer.h | 137 +-- src/kits/network/libnetapi/Jamfile | 1 + src/kits/network/libnetapi/NetBuffer.cpp | 1040 ++++++---------------- 3 files changed, 366 insertions(+), 812 deletions(-) diff --git a/headers/os/net/NetBuffer.h b/headers/os/net/NetBuffer.h index a954c25da8..8a9747e2b7 100644 --- a/headers/os/net/NetBuffer.h +++ b/headers/os/net/NetBuffer.h @@ -1,86 +1,93 @@ /* - * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. + * Copyright 2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * Bruno Albuquerque, bga@bug-br.org.br */ + #ifndef _NETBUFFER_H #define _NETBUFFER_H - -#include -#include #include +#include -#include + +class BMessage; +class DynamicBuffer; class BNetBuffer : public BArchivable { - public: - BNetBuffer(size_t size = 0); - virtual ~BNetBuffer(); +public: + BNetBuffer(size_t size = 0); - status_t InitCheck(); + virtual ~BNetBuffer(); - BNetBuffer(BMessage* archive); - virtual status_t Archive(BMessage* into, bool deep = true) const; - static BArchivable* Instantiate(BMessage* archive); + BNetBuffer(const BNetBuffer& buffer); + BNetBuffer(BMessage* archive); - BNetBuffer(const BNetBuffer &); - BNetBuffer& operator=(const BNetBuffer &); + BNetBuffer& operator=(const BNetBuffer& buffer); - // Mutators. - status_t AppendInt8(int8); - status_t AppendUint8(uint8); - status_t AppendInt16(int16); - status_t AppendUint16(uint16); - status_t AppendInt32(int32); - status_t AppendUint32(uint32); - status_t AppendFloat(float); - status_t AppendDouble(double); - status_t AppendString(const char *); - status_t AppendData(const void *, size_t); - status_t AppendMessage(const BMessage &); - status_t AppendInt64(int64); - status_t AppendUint64(uint64); + virtual status_t Archive(BMessage* into, bool deep = true) const; + static BArchivable* Instantiate(BMessage* archive); - status_t RemoveInt8(int8 &); - status_t RemoveUint8(uint8 &); - status_t RemoveInt16(int16 &); - status_t RemoveUint16(uint16 &); - status_t RemoveInt32(int32 &); - status_t RemoveUint32(uint32 &); - status_t RemoveFloat(float &); - status_t RemoveDouble(double &); - status_t RemoveString(char *, size_t); - status_t RemoveData(void *, size_t); - status_t RemoveMessage(BMessage &); - status_t RemoveInt64(int64 &); - status_t RemoveUint64(uint64 &); + status_t InitCheck(); - // Accessors. - unsigned char* Data() const; - size_t Size() const; - size_t BytesRemaining() const; + status_t AppendInt8(int8 data); + status_t AppendUint8(uint8 data); + status_t AppendInt16(int16 data); + status_t AppendUint16(uint16 data); + status_t AppendInt32(int32 data); + status_t AppendUint32(uint32 data); + status_t AppendFloat(float data); + status_t AppendDouble(double data); + status_t AppendString(const char* data); + status_t AppendData(const void* data, size_t size); + status_t AppendMessage(const BMessage& data); + status_t AppendInt64(int64 data); + status_t AppendUint64(uint64 data); - private: - virtual void _ReservedBNetBufferFBCCruft1(); - virtual void _ReservedBNetBufferFBCCruft2(); - virtual void _ReservedBNetBufferFBCCruft3(); - virtual void _ReservedBNetBufferFBCCruft4(); - virtual void _ReservedBNetBufferFBCCruft5(); - virtual void _ReservedBNetBufferFBCCruft6(); + status_t RemoveInt8(int8& data); + status_t RemoveUint8(uint8& data); + status_t RemoveInt16(int16& data); + status_t RemoveUint16(uint16& data); + status_t RemoveInt32(int32& data); + status_t RemoveUint32(uint32& data); + status_t RemoveFloat(float& data); + status_t RemoveDouble(double& data); + status_t RemoveString(char* data, size_t size); + status_t RemoveData(void* data, size_t size); + status_t RemoveMessage(BMessage& data); + status_t RemoveInt64(int64& data); + status_t RemoveUint64(uint64& data); + + unsigned char* Data() const; + size_t Size() const; + size_t BytesRemaining() const; + + inline DynamicBuffer* GetImpl() const; + +protected: + status_t fInit; + +private: + virtual void _ReservedBNetBufferFBCCruft1(); + virtual void _ReservedBNetBufferFBCCruft2(); + virtual void _ReservedBNetBufferFBCCruft3(); + virtual void _ReservedBNetBufferFBCCruft4(); + virtual void _ReservedBNetBufferFBCCruft5(); + virtual void _ReservedBNetBufferFBCCruft6(); + + DynamicBuffer* fImpl; + int32 __ReservedBNetBufferFBCCruftData[8]; - // Private class helpers. - status_t clone(const BNetBuffer&); - status_t dpop(int32, int32, void*); - status_t dpush(int32, int32, const void*); - status_t resize(int32 newSize, bool regenStack = false); - - status_t fInit; - uint8* fData; - int32 fDataSize; - int32 fStackSize; - int32 fCapacity; - int32 _reserved[5]; }; -#endif // _NETBUFFER_H + +inline DynamicBuffer* +BNetBuffer::GetImpl() const +{ + return fImpl; +} + +#endif // _NET_BUFFER_H diff --git a/src/kits/network/libnetapi/Jamfile b/src/kits/network/libnetapi/Jamfile index 3a9e198958..d5cd401ed6 100644 --- a/src/kits/network/libnetapi/Jamfile +++ b/src/kits/network/libnetapi/Jamfile @@ -6,6 +6,7 @@ UsePrivateHeaders net ; local netapi_sources = init.cpp + DynamicBuffer.cpp NetEndpoint.cpp NetAddress.cpp NetBuffer.cpp diff --git a/src/kits/network/libnetapi/NetBuffer.cpp b/src/kits/network/libnetapi/NetBuffer.cpp index fb69c97462..5c31d6bfa4 100644 --- a/src/kits/network/libnetapi/NetBuffer.cpp +++ b/src/kits/network/libnetapi/NetBuffer.cpp @@ -1,889 +1,435 @@ /* - * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. + * Copyright 2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: - * Scott T. Mansfield, thephantom@mac.com + * Bruno Albuquerque, bga@bug-br.org.br */ -/*! - Remarks: - * This is basically a fancy-schmancy FIFO stack manager. Thusly, it is - considered an error if data is not popped off a particular instance's - stack in the order it was pushed on. - * We could possibly implement this class as a thin wrapper around the - BMessage class, but I'm not sure what kind of payload the latter class - brings to the party, so we'll do our own stack management. We also - cannot be sure that BMessage behaves as described above down the road. - * Never use hot wax to soothe enraged lobsters. -*/ - #include #include -#include +#include -#include +#include "DynamicBuffer.h" +#include "NetBuffer.h" +#include -/* - * Parametric ctor initialization list defaults. - */ -#define CTOR_INIT_LIST \ - BArchivable( ), \ - fInit( B_NO_INIT ), \ - fData( NULL ), \ - fDataSize( 0 ), \ - fStackSize( 0 ), \ - fCapacity( 0 ) - - -/* - * Markers that surround a record in an instance's stack. - */ -#define DATA_START_MARKER 0x01c0ffee -#define DATA_END_MARKER 0xbeefeeee - - -/* BNetBuffer - *=--------------------------------------------------------------------------=* - * Purpose: - * Class ctor. - * - * Input parameter: - * size : Initial size of buffer (default is zero). - * - * Remarks: - * This bad boy doubles up as the default ctor. - */ -BNetBuffer::BNetBuffer( size_t size ) - : CTOR_INIT_LIST +BNetBuffer::BNetBuffer(size_t size) : + BArchivable(), + fInit(B_NO_INIT) { - fInit = ( resize( size ) == B_OK ) ? B_OK : B_NO_INIT; + fImpl = new (std::nothrow) DynamicBuffer(size); + if (fImpl != NULL) + fInit = fImpl->InitCheck(); } -/* BNetBuffer - *=--------------------------------------------------------------------------=* - * Purpose: - * Class copy ctor. - * - * Input parameter: - * refparam : Instance to copy. - */ -BNetBuffer::BNetBuffer( const BNetBuffer& refparam ) - : CTOR_INIT_LIST +BNetBuffer::~BNetBuffer() { - fInit = ( clone( refparam ) == B_OK ) ? B_OK : B_NO_INIT; + delete fImpl; } -/* BNetBuffer - *=--------------------------------------------------------------------------=* - * Purpose: - * Ctor to instantiate from serialized data (BMessage). - * - * Input parameter: - * archive : Serialized object to instantiate from. - */ -BNetBuffer::BNetBuffer( BMessage* archive ) - : CTOR_INIT_LIST +BNetBuffer::BNetBuffer(const BNetBuffer& buffer) : + BArchivable(), + fInit(B_NO_INIT) { - const unsigned char* msgDataPtr; - ssize_t msgNBytes; - - int32 dataSize; - int32 stackSize; - int32 capacity; - - if ( archive->FindInt32( "bnbuff_datasize", &dataSize ) != B_OK ) - { - return; - } - - if ( archive->FindInt32( "bnbuff_stacksize", &stackSize ) != B_OK ) - { - return; - } - - if ( archive->FindInt32( "bnbuff_capacity", &capacity ) != B_OK ) - { - return; - } - - if ( archive->FindData( "bnbuff_stack", B_RAW_TYPE, - ( const void** )&msgDataPtr, &msgNBytes ) != B_OK ) - { - return; - } - - if ( capacity ) - { - if ( resize( capacity, true ) != B_OK ) - { - return; - } - - memcpy( fData, msgDataPtr, stackSize ); - } - - fDataSize = dataSize; - fStackSize = stackSize; - fCapacity = capacity; - - fInit = B_OK; + fImpl = new (std::nothrow) DynamicBuffer(*buffer.GetImpl()); + if (fImpl != NULL) + fInit = fImpl->InitCheck(); } -/* ~BNetBuffer - *=--------------------------------------------------------------------------=* - * Purpose: - * Class dtor. - */ -BNetBuffer::~BNetBuffer( void ) +BNetBuffer::BNetBuffer(BMessage* archive) : + BArchivable(), + fInit(B_NO_INIT) { - if ( fData != NULL ) - { - delete fData; - fData = NULL; - } + const unsigned char* bufferPtr; + ssize_t bufferSize; + + if (archive->FindData("buffer", B_RAW_TYPE, (const void**)&bufferPtr, + &bufferSize) == B_OK) { + fImpl = new (std::nothrow) DynamicBuffer(bufferSize); + if (fImpl != NULL) { + status_t result = fImpl->Insert(bufferPtr, bufferSize); + if (result == B_OK) + fInit = fImpl->InitCheck(); + else + fInit = result; + } + } +} - fDataSize = fStackSize = fCapacity = 0; - - fInit = B_NO_INIT; +BNetBuffer& +BNetBuffer::operator=(const BNetBuffer& buffer) +{ + fImpl = new (std::nothrow) DynamicBuffer(*buffer.GetImpl()); + if (fImpl != NULL) + fInit = fImpl->InitCheck(); + + return *this; } -/* operator= - *=--------------------------------------------------------------------------=* - * Purpose: - * Class' assignment operator. - * - * Input parameter: - * refparam : Instance to assign from. - */ -BNetBuffer& BNetBuffer::operator=( const BNetBuffer& refparam ) +status_t +BNetBuffer::Archive(BMessage* into, bool deep) const { - fInit = clone( refparam ); - - return *this; + if (fInit != B_OK) + return B_NO_INIT; + + if (into->AddData("buffer", B_RAW_TYPE, fImpl->Data(), + fImpl->BytesRemaining()) != B_OK) + return B_ERROR; + + return B_OK; } -/* InitCheck - *=--------------------------------------------------------------------------=* - * Purpose: - * Determine whether or not this instance is properly initialized. - * - * Returns: - * B_OK if this instance is initialized, B_ERROR if not. - */ -status_t BNetBuffer::InitCheck( void ) +BArchivable* +BNetBuffer::Instantiate(BMessage* archive) { - return ( fInit == B_OK ) ? B_OK : B_ERROR; -} - - -/* Archive - *=--------------------------------------------------------------------------=* - * Purpose: - * Serialize this instance into the passed BMessage parameter. - * - * Input parameter: - * deep : [ignored] default==true. - * - * Output parameter: - * into : BMessage object to serialize into. - * - * Returns: - * B_OK/BERROR on success/failure. Returns B_NO_INIT if instance not - * properly initialized. - */ -status_t BNetBuffer::Archive( BMessage* into, bool deep ) const -{ - if ( fInit != B_OK ) - { - return B_NO_INIT; - } - - if ( into->AddInt32( "bnbuff_datasize", fDataSize ) ) - { - return B_ERROR; - } - - if ( into->AddInt32( "bnbuff_stacksize", fStackSize ) ) - { - return B_ERROR; - } - - if ( into->AddInt32( "bnbuff_capacity", fCapacity ) ) - { - return B_ERROR; - } - - if ( into->AddData( "bnbuff_stack", B_RAW_TYPE, fData, fStackSize ) != B_OK ) - //STM: Should we store the *whole* stack instead?......^^^^^^^^^^fCapacity - { - return B_ERROR; - } - - return B_OK; -} - - -/* Instantiate - *=--------------------------------------------------------------------------=* - * Purpose: - * Un-serialize and instantiate from the passed BMessage parameter. - * - * Input parameter: - * archive : Archived BMessage object for (de)serialization. - * - * Returns: - * NULL if a BNetBuffer instance can not be initialized, otherwise - * a new BNetBuffer object instantiated from the BMessage parameter. - */ -BArchivable* BNetBuffer::Instantiate( BMessage* archive ) -{ - if ( !validate_instantiation( archive, "BNetBuffer" ) ) - { + if (!validate_instantiation(archive, "BNetBuffer")) { return NULL; } - BNetBuffer* bnb = new BNetBuffer( archive ); - if ( bnb == NULL ) - { + BNetBuffer* buffer = new BNetBuffer(archive); + if (buffer == NULL) + return NULL; + + if (buffer->InitCheck() != B_OK) { + delete buffer; return NULL; } - if ( bnb->InitCheck( ) != B_OK ) - { - delete bnb; - return NULL; - } - - return bnb; + return buffer; } -/* AppendXXX - *=--------------------------------------------------------------------------=* - * Purpose: - * Append some data to this buffer (think PUSHing onto a FIFO stack). - * - * Returns: - * B_OK/B_ERROR for success/failure. B_NO_INIT if instance not properly - * initialized or stuck in some unknown state during construction. - * - * Remarks: - * * Where appropriate numeric data such as (u)int16, et al, are converted - * to network byte order during storage, no need to do this in advance. - */ -status_t BNetBuffer::AppendInt8( int8 Data ) +status_t +BNetBuffer::InitCheck() { - return dpush( B_INT8_TYPE, sizeof( int8 ), &Data ); + return fInit; } -status_t BNetBuffer::AppendUint8( uint8 Data ) + +status_t +BNetBuffer::AppendInt8(int8 data) { - return dpush( B_UINT8_TYPE, sizeof( uint8 ), &Data ); + return AppendData((const void*)&data, sizeof(int8)); } -status_t BNetBuffer::AppendInt16( int16 Data ) + +status_t +BNetBuffer::AppendUint8(uint8 data) { - int16 locData = B_HOST_TO_BENDIAN_INT16( Data ); - return dpush( B_INT16_TYPE, sizeof( int16 ), &locData ); + return AppendData((const void*)&data, sizeof(int8)); } -status_t BNetBuffer::AppendUint16( uint16 Data ) + +status_t +BNetBuffer::AppendInt16(int16 data) { - uint16 locData = B_HOST_TO_BENDIAN_INT16( Data ); - return dpush( B_UINT16_TYPE, sizeof( uint16 ), &locData ); + int16 be_data = B_HOST_TO_BENDIAN_INT16(data); + return AppendData((const void*)&be_data, sizeof(int16)); } -status_t BNetBuffer::AppendInt32( int32 Data ) + +status_t +BNetBuffer::AppendUint16(uint16 data) { - int32 locData = B_HOST_TO_BENDIAN_INT32( Data ); - return dpush( B_INT32_TYPE, sizeof( int32 ), &locData ); + uint16 be_data = B_HOST_TO_BENDIAN_INT16(data); + return AppendData((const void*)&be_data, sizeof(uint16)); } -status_t BNetBuffer::AppendUint32( uint32 Data ) + +status_t +BNetBuffer::AppendInt32(int32 data) { - uint32 locData = B_HOST_TO_BENDIAN_INT32( Data ); - return dpush( B_UINT32_TYPE, sizeof( uint32 ), &locData ); + int32 be_data = B_HOST_TO_BENDIAN_INT32(data); + return AppendData((const void*)&be_data, sizeof(int32)); } -status_t BNetBuffer::AppendInt64( int64 Data ) + +status_t +BNetBuffer::AppendUint32(uint32 data) { - int64 locData = B_HOST_TO_BENDIAN_INT64( Data ); - return dpush( B_INT64_TYPE, sizeof( int64 ), &locData ); + uint32 be_data = B_HOST_TO_BENDIAN_INT32(data); + return AppendData((const void*)&be_data, sizeof(uint32)); } -status_t BNetBuffer::AppendUint64( uint64 Data ) + +status_t +BNetBuffer::AppendFloat(float data) { - uint64 locData = B_HOST_TO_BENDIAN_INT64( Data ); - return dpush( B_UINT64_TYPE, sizeof( uint64 ), &locData ); + return AppendData((const void*)&data, sizeof(float)); } -status_t BNetBuffer::AppendFloat( float Data ) + +status_t +BNetBuffer::AppendDouble(double data) { - return dpush( B_FLOAT_TYPE, sizeof( float ), &Data ); + return AppendData((const void*)&data, sizeof(double)); } -status_t BNetBuffer::AppendDouble( double Data ) + +status_t +BNetBuffer::AppendString(const char* data) { - return dpush( B_DOUBLE_TYPE, sizeof( double ), &Data ); + return AppendData((const void*)data, strlen(data) + 1); } -status_t BNetBuffer::AppendString( const char* Data ) + +status_t +BNetBuffer::AppendData(const void* data, size_t size) { - return dpush( B_STRING_TYPE, strlen( Data ), Data ); + return fImpl->Insert(data, size); } -status_t BNetBuffer::AppendData( const void* Data, size_t Length ) + +status_t +BNetBuffer::AppendMessage(const BMessage& data) { - return dpush( B_RAW_TYPE, Length, Data ); + size_t dataSize = data.FlattenedSize(); + if (dataSize == 0) + return B_ERROR; + + char* flattenedData = new (std::nothrow) char[dataSize]; + if (flattenedData == NULL) + return B_NO_MEMORY; + + status_t result = B_OK; + if (data.Flatten(flattenedData, dataSize) == B_OK) + result = AppendData((const void*)&flattenedData, dataSize); + + delete[] flattenedData; + + return result; } -status_t BNetBuffer::AppendMessage( const BMessage& Msg ) + +status_t +BNetBuffer::AppendInt64(int64 data) { - status_t result; - ssize_t msgLen; - char* msgData; - - msgLen = Msg.FlattenedSize( ); - if ( msgLen == 0 ) - { - //STM: It's possible, but SHOULD we store an empty BMessage? - //STM: Is an empty BMessage instance even legit in Be/OBOS? - return B_ERROR; - } - - if ( ( msgData = new char[msgLen] ) == NULL ) - { - return B_ERROR; //STM: B_NO_MEM??? - } - - // Don't get tripped on this, just trying to err on the side of caution. - result = B_ERROR; - - if ( Msg.Flatten( msgData, msgLen ) == B_OK ) - { - result = dpush( B_MESSAGE_TYPE, msgLen, msgData ); - } - - delete[] msgData; - return result; + int64 be_data = B_HOST_TO_BENDIAN_INT64(data); + return AppendData((const void*)&be_data, sizeof(int64)); } -/* RemoveXXXX - *=--------------------------------------------------------------------------=* - * Purpose: - * Remove some data from this buffer, think POPping from a FIFO stack. - * - * Returns: - * B_OK/B_ERROR for success/failure. B_NO_INIT if instance not properly - * initialized or stuck in some unknown state during construction. - * - * Remarks: - * Where appropriate numeric data such as (u)int16, et al, are converted - * from network byte order. No need to do this ipso post facto. - */ -status_t BNetBuffer::RemoveInt8( int8& Data ) +status_t +BNetBuffer::AppendUint64(uint64 data) { - return dpop( B_INT8_TYPE, sizeof( int8 ), &Data ); + uint64 be_data = B_HOST_TO_BENDIAN_INT64(data); + return AppendData((const void*)&be_data, sizeof(uint64)); } -status_t BNetBuffer::RemoveUint8( uint8& Data ) + +status_t +BNetBuffer::RemoveInt8(int8& data) { - return dpop( B_UINT8_TYPE, sizeof( uint8 ), &Data ); + return RemoveData((void*)&data, sizeof(int8)); } -status_t BNetBuffer::RemoveInt16( int16& Data ) + +status_t +BNetBuffer::RemoveUint8(uint8& data) { - // dpop will convert this bad boy from network to host byte order. - return dpop( B_INT16_TYPE, sizeof( int16 ), &Data ); + return RemoveData((void*)&data, sizeof(uint8)); } -status_t BNetBuffer::RemoveUint16( uint16& Data ) + +status_t +BNetBuffer::RemoveInt16(int16& data) { - // dpop will convert this beast from network to host byte order. - return dpop( B_UINT16_TYPE, sizeof( uint16 ), &Data ); + int16 be_data; + status_t result = RemoveData((void*)&be_data, sizeof(int16)); + if (result != B_OK) + return result; + + data = B_BENDIAN_TO_HOST_INT16(be_data); + + return B_OK; } -status_t BNetBuffer::RemoveInt32( int32& Data ) + +status_t +BNetBuffer::RemoveUint16(uint16& data) { - // dpop will convert this thang from network to host byte order. - return dpop( B_INT32_TYPE, sizeof( int32 ), &Data ); + uint16 be_data; + status_t result = RemoveData((void*)&be_data, sizeof(uint16)); + if (result != B_OK) + return result; + + data = B_BENDIAN_TO_HOST_INT16(be_data); + + return B_OK; } -status_t BNetBuffer::RemoveUint32( uint32& Data ) + +status_t +BNetBuffer::RemoveInt32(int32& data) { - // dpop will convert this variable from network to host byte order. - return dpop( B_UINT32_TYPE, sizeof( uint32 ), &Data ); + int32 be_data; + status_t result = RemoveData((void*)&be_data, sizeof(int32)); + if (result != B_OK) + return result; + + data = B_BENDIAN_TO_HOST_INT32(be_data); + + return B_OK; } -status_t BNetBuffer::RemoveInt64( int64& Data ) + +status_t +BNetBuffer::RemoveUint32(uint32& data) { - // dpop will convert this bag-o-bits from network to host byte order. - return dpop( B_INT64_TYPE, sizeof( int64 ), &Data ); + uint32 be_data; + status_t result = RemoveData((void*)&be_data, sizeof(uint32)); + if (result != B_OK) + return result; + + data = B_BENDIAN_TO_HOST_INT32(be_data); + + return B_OK; } -status_t BNetBuffer::RemoveUint64( uint64& Data ) + +status_t +BNetBuffer::RemoveFloat(float& data) { - // dpop will convert this construct from network to host byte order. - return dpop( B_UINT64_TYPE, sizeof( uint64 ), &Data ); + return RemoveData((void*)&data, sizeof(float)); } -status_t BNetBuffer::RemoveFloat( float& Data ) + +status_t +BNetBuffer::RemoveDouble(double& data) { - return dpop( B_FLOAT_TYPE, sizeof( float ), &Data ); + return RemoveData((void*)&data, sizeof(double)); } -status_t BNetBuffer::RemoveDouble( double& Data ) + +status_t +BNetBuffer::RemoveString(char* data, size_t size) { - return dpop( B_DOUBLE_TYPE, sizeof( double ), &Data ); + // TODO(bga): Should we do anything specific to handle the terminating + // NULL byte? + return RemoveData((void*)data, size); } -status_t BNetBuffer::RemoveString( char* Data, size_t Length ) + +status_t +BNetBuffer::RemoveData(void* data, size_t size) { - return dpop( B_STRING_TYPE, Length, Data ); + return fImpl->Remove(data, size); } -status_t BNetBuffer::RemoveData( void* Data, size_t Length ) + +status_t +BNetBuffer::RemoveMessage(BMessage& data) { - return dpop( B_RAW_TYPE, Length, Data ); + unsigned char* bufferPtr = fImpl->Data(); + + if (*(int32*)bufferPtr != B_MESSAGE_TYPE) + return B_ERROR; + + + bufferPtr += sizeof(int32); + int32 dataSize = *(int32*)bufferPtr; + + char* flattenedData = new (std::nothrow) char[dataSize]; + if (flattenedData == NULL) + return B_NO_MEMORY; + + status_t result = RemoveData(flattenedData, dataSize); + if (result == B_OK) + result = data.Unflatten(flattenedData); + + delete[] flattenedData; + + return result; } -status_t BNetBuffer::RemoveMessage( BMessage& message ) + +status_t +BNetBuffer::RemoveInt64(int64& data) { - status_t result; - int32 v; - unsigned char* stackPtr = fData; - char* msgData; - - /* - * We have to cheat a little bit here and peek ahead of dpop so we can - * get at the size parameter. Perform basic checks along the way so we - * can make sure that we really get to the size parameter and not some - * bogus value. Redundant, but necessary. - */ - v = *( int32 * )stackPtr; - if ( v != DATA_START_MARKER ) - { - return B_ERROR; - } - - stackPtr += sizeof( int32 ); - v = *( int32 * )stackPtr; - if ( v != B_MESSAGE_TYPE ) - { - return B_ERROR; - } - - // Snarf the data size. - stackPtr += sizeof( int32 ); - v = *( int32 * )stackPtr; - - if ( ( msgData = new char[v] ) == NULL ) - { - return B_ERROR; //STM: B_NO_MEM??? - } - - if ( dpop( B_MESSAGE_TYPE, v, msgData ) != B_OK ) - { - delete msgData; - return B_ERROR; - } - - result = message.Unflatten( msgData ); - delete msgData; - return result; + int64 be_data; + status_t result = RemoveData((void*)&be_data, sizeof(int64)); + if (result != B_OK) + return result; + + data = B_BENDIAN_TO_HOST_INT64(be_data); + + return B_OK; } -/* Data - *=--------------------------------------------------------------------------=* - * Purpose: - * Class accessor. - * - * Returns: - * Pointer to class' data suitable for those functions and methods that - * expect some kind of "generic" pointer. - * - * Remarks: - * * This is WEAK and WRONG, as it allows non-members to directly - * manipulate an instance's member data without the usual checks in - * place. At the very least the return value should be const. Ideally, - * this method should not exist. - */ -unsigned char* BNetBuffer::Data( void ) const +status_t +BNetBuffer::RemoveUint64(uint64& data) { - // Have I mentioned that this is a Really Bad Thing to do? - return fData; - // In case I missed it: returning a non-const pointer to our member data - // is not a good thing. Caveat emptor. + uint64 be_data; + status_t result = RemoveData((void*)&be_data, sizeof(uint64)); + if (result != B_OK) + return result; + + data = B_BENDIAN_TO_HOST_INT64(be_data); + + return B_OK; } -/* Size - *=--------------------------------------------------------------------------=* - * Purpose: - * Class accessor. - * - * Returns: - * How many bytes of data are contained. This *does not* include the - * overhead of the stack control variables (delineators and size). - */ -size_t BNetBuffer::Size( void ) const +unsigned char* +BNetBuffer::Data() const { - return fDataSize; + return fImpl->Data(); } -/* BytesRemaining - *=--------------------------------------------------------------------------=* - * Purpose: - * Class accessor ...erm... sort of. - * - * Returns: - * How much capacity this instance has left to store data. - * - * Remarks: - * This method is essentially meaningless as the class' storage capacity - * will grow (or shrink) as necessary (that's an obfuscated way to say - * "dynamically re-allocated" boys and girls). Do not rely on this - * particular method in normal use as it refers to a moving target. - */ -size_t BNetBuffer::BytesRemaining( void ) const +size_t +BNetBuffer::Size() const { - return ( fCapacity - fStackSize ); + return fImpl->Size(); } -/* clone - *=--------------------------------------------------------------------------=* - * Purpose: - * Private copy helper method. - * - * Input parameter: - * RefParam: Instance to clone. - * - * Returns: - * status_t indicating success or point of failure (see resize()). - * B_NO_INIT if RefParam not properly initialized. - */ -status_t BNetBuffer::clone( const BNetBuffer& RefParam ) +size_t +BNetBuffer::BytesRemaining() const { - if ( !RefParam.fInit ) - { - return B_NO_INIT; - } - - if ( resize( RefParam.fCapacity, true ) != B_OK ) - { - return B_ERROR; - } - - fDataSize = RefParam.fDataSize; - fStackSize = RefParam.fStackSize; - memcpy( fData, RefParam.fData, fStackSize ); - - return B_OK; + return fImpl->BytesRemaining(); } -/* dpop - *=--------------------------------------------------------------------------=* - * Purpose: - * Pop some data from our stack. - * - * Input parameters: - * Type : Expected data type for this record. - * Length : Expected data size for this record. - * - * Output parameter: - * Data : Recepticle for popped data. You are responsible for - * insuring that this is large enough to hold your - * intended data. If this parameter is NULL, you'll get - * back a B_ERROR. If the space allocated that this - * parameter points to is not sufficient to contain the - * intended data, you'll likely over-run something else - * in user-space and piss off a few folks in the process. - * - * Returns: - * B_OK/B_ERROR on success/failure. - * B_NO_INIT if this instance not properly initialized. - */ -status_t BNetBuffer::dpop( int32 Type, int32 Length, void* Data ) -{ - if ( fInit != B_OK ) - { - return B_NO_INIT; - } - - if ( Data == NULL ) - { - return B_ERROR; - } - - unsigned char* stackPtr = fData; - unsigned char* userDataPtr; - int32 int32size = sizeof( int32 ); // <-- Performance: called a lot here. - int32 recordSize = ( ( int32size * 4 ) + Length ); - int32 tmp; - - // Validate the start marker. - tmp = *( int32 * )stackPtr; - if ( tmp != (int32) DATA_START_MARKER ) - { - return B_ERROR; - } - - // Validate the data type. - stackPtr += int32size; - tmp = *( int32 * )stackPtr; - if ( tmp != Type ) - { - return B_ERROR; - } - - // Validate the data size. - stackPtr += int32size; - tmp = *( int32 * )stackPtr; - if ( tmp != Length ) - { - return B_ERROR; - } - - // Stash a pointer to the contained user data, used when we really "pop." - stackPtr += int32size; - userDataPtr = stackPtr; - - // Validate the end marker. - stackPtr += Length; - tmp = *( int32 * )stackPtr; - if ( tmp != (int32) DATA_END_MARKER ) - { - return B_ERROR; - } - - // Point to the next entry in the stack. - stackPtr += int32size; - - // Extract the contained data. - memcpy( Data, userDataPtr, Length ); - - // Convert from network byte order if necessary. - switch ( Type ) - { - case B_INT16_TYPE: - case B_UINT16_TYPE: - *( uint16 * )Data = B_BENDIAN_TO_HOST_INT16( *( uint16 * )Data ); - break; - - case B_INT32_TYPE: - case B_UINT32_TYPE: - *( uint32 * )Data = B_BENDIAN_TO_HOST_INT32( *( uint32 * )Data ); - break; - - case B_INT64_TYPE: - case B_UINT64_TYPE: - *( uint64 * )Data = B_BENDIAN_TO_HOST_INT64( *( uint64 * )Data ); - break; - - default: - break; - } - - // Condense the stack. - fStackSize -= recordSize; - memmove( fData, stackPtr, fStackSize ); - - // Zero out the unused area of the stack where we memmove'd from. - memset( &fData[fStackSize], 0, ( fCapacity - fStackSize ) ); - - // Update the extents. - fCapacity += recordSize; - fDataSize -= Length; - - return B_OK; -} - - -/* dpush - *=--------------------------------------------------------------------------=* - * Purpose: - * Push some data onto our buffer. - * - * Input parameters: - * Type : Data type for this record. - * Length : Data length for this record. - * Data : Pointer to data to store. NO-OP (B_ERROR) if NULL. - * - * Returns: - * B_OK/B_ERROR on success/failure. - * B_NO_INIT if this instance not properly initialized. - * - * Remarks: - * * No need to worry about host-to-network byte ordering conversion -- - * since this is a /private/ helper said conversion, where applicable, - * takes place in our caller (see AddIntXX if you haven't already passed - * them on your way down to this humble helper). - */ -status_t BNetBuffer::dpush( int32 Type, int32 Length, const void* Data ) -{ - if ( fInit != B_OK ) - { - return B_NO_INIT; - } - - if ( Data == NULL ) - { - return B_ERROR; - } - - int32 int32size = sizeof( int32 ); // <--Performance: called a lot here. - int32 recordSize = ( ( int32size * 4 ) + Length ); - - if ( resize( fCapacity + recordSize ) != B_OK ) - { - return B_ERROR; - } - - unsigned char* stackPtr = &fData[fStackSize]; - *( int32 * )stackPtr = DATA_START_MARKER; - - stackPtr += int32size; - *( int32 * )stackPtr = Type; - - stackPtr += int32size; - *( int32 * )stackPtr = Length; - - stackPtr += int32size; - memcpy( stackPtr, Data, Length ); - - stackPtr += Length; - *( int32 * )stackPtr = DATA_END_MARKER; - - // Groovy! All stored, dot our t's and cross our i's. - fDataSize += Length; - fStackSize += recordSize; - - return B_OK; -} - - -/* resize - *=--------------------------------------------------------------------------=* - * Purpose: - * Grow the internal data buffer to accommodate the requested size. - * - * //STM: What about shrinking the buffer to conserve resources? - * - * Input parameter: - * NewSize : New size of data buffer. Duh. - * RegenStack : If true, do not try to preserve the existing stack. - * Default is false (preserve existing data). - * - * Returns: - * B_OK: Success. - * B_NO_MEMORY: if we cannot allocate memory for the data buffer. - * - * Remarks: - * * In keeping with the "contract programming" development model: this is - * a "safe copy" method in that the class' existing member data will not - * be disturbed in the event of failure. When our caller gets back a - * success status (B_OK), said caller is guaranteed that all is well. - * Laterally, in the event this method returns failure, the caller is - * guaranteed that the class' existing member data is left untouched, - * thereby preserving the existing instance's integrity. - * - * * Buffer size is adjusted on a 16-byte granularity to keep from beating - * the bleep out of the memory pool (can you say "fragmentation" boys and - * girls?). To tweak the granularity, change the GRANULARITY token at the - * beginning of this method. For best results, GRANULARITY should be a - * power of two, thankyouverymuch. - * - * * 'RegenStack' and its intented behavior is a bit of a double-negative. - * May have to change this to eliminate said double negative if it proves - * to be too confusing. - */ -status_t BNetBuffer::resize( int32 NewSize, bool RegenStack ) -{ -#define GRANULARITY 16 - - unsigned char* newData; - int32 newCapacity; - - newCapacity = ( ( ( NewSize / GRANULARITY ) + 1 ) * GRANULARITY ); - - // Don't waste cycles or thrash the memory pool if we don't need to... - if ( newCapacity <= fCapacity ) - { - return B_OK; - } - -/* STM: If we decide to shrink as well as grow, then replace above with: - if ( newCapacity == fCapacity ) - { - return B_OK; - } -*/ - - newData = new unsigned char[newCapacity]; - if ( newData == NULL ) - { - return B_NO_MEMORY; - } - - // Paranoid? Pffffsh. You bet. :-) - memset( newData, 0, newCapacity ); - - if ( fData != NULL ) - { - if ( !RegenStack ) - { - memcpy( newData, fData, fStackSize ); - } - - delete fData; - } - - fData = newData; - fCapacity = newCapacity; - - return B_OK; - -#undef GRANULARITY -} - - -/* Reserved methods, for future evolution */ - -void BNetBuffer::_ReservedBNetBufferFBCCruft1() -{ -} - -void BNetBuffer::_ReservedBNetBufferFBCCruft2() -{ -} - -void BNetBuffer::_ReservedBNetBufferFBCCruft3() -{ -} - -void BNetBuffer::_ReservedBNetBufferFBCCruft4() -{ -} - -void BNetBuffer::_ReservedBNetBufferFBCCruft5() -{ -} - -void BNetBuffer::_ReservedBNetBufferFBCCruft6() +void +BNetBuffer::_ReservedBNetBufferFBCCruft1() { } -/*=------------------------------------------------------------------- End -=*/ +void +BNetBuffer::_ReservedBNetBufferFBCCruft2() +{ +} + + +void +BNetBuffer::_ReservedBNetBufferFBCCruft3() +{ +} + + +void +BNetBuffer::_ReservedBNetBufferFBCCruft4() +{ +} + + +void +BNetBuffer::_ReservedBNetBufferFBCCruft5() +{ +} + + +void +BNetBuffer::_ReservedBNetBufferFBCCruft6() +{ +}