diff --git a/src/kits/network/libnetapi/Jamfile b/src/kits/network/libnetapi/Jamfile index 8ce02be6ca..0772653305 100644 --- a/src/kits/network/libnetapi/Jamfile +++ b/src/kits/network/libnetapi/Jamfile @@ -3,12 +3,12 @@ SubDir OBOS_TOP src kits net libnetapi ; UsePrivateHeaders net ; SharedLibrary netapi : - NetEndpoint.cpp +# NetEndpoint.cpp NetAddress.cpp NetBuffer.cpp NetDebug.cpp ; LinkSharedOSLibs libnetapi.so : - root net + root be libnet.so ; diff --git a/src/kits/network/libnetapi/NetAddress.cpp b/src/kits/network/libnetapi/NetAddress.cpp index 2d898a3bdf..cd878db6f6 100644 --- a/src/kits/network/libnetapi/NetAddress.cpp +++ b/src/kits/network/libnetapi/NetAddress.cpp @@ -8,7 +8,7 @@ * host byte order. * * In all mutators, address and port are converted from host to * network byte order. - * * Michael, no trouts were harmed during the creation of this class. + * * No trouts were harmed during the development of this class. *=--------------------------------------------------------------------------=* * Copyright (c) 2002, The OpenBeOS project. * @@ -35,8 +35,11 @@ #include #include -#include // STM: #include ??? +#include #include +#include + +#include #include /* @@ -197,7 +200,7 @@ BNetAddress::~BNetAddress( void ) * Hostname and/or port can be NULL; although having them both NULL would * be a pointless waste of CPU cycles. ;-) * - * The hostname output parameter can be a variety of things, but it this + * The hostname output parameter can be a variety of things, but in this * method we convert the IP address to a string. See the relevant * documentation about inet_ntoa() for details. * @@ -249,8 +252,9 @@ status_t BNetAddress::GetAddr( char* hostname, unsigned short* port ) const * * Remarks: * This method fills in the sin_addr, sin_family, and sin_port fields of - * the output parameter, all other fields are untouched. All numeric - * values are in network byte order. + * the output parameter, all other fields are untouched so we can work + * with both POSIX and non-POSIX versions of said struct. The port and + * address values added to the output parameter are in network byte order. */ status_t BNetAddress::GetAddr( struct sockaddr_in& sa ) const { @@ -309,7 +313,7 @@ status_t BNetAddress::GetAddr( in_addr& addr, unsigned short* port ) const * Returns: * B_OK if this instance is initialized, B_ERROR if not. */ -status_t BNetAddress::InitCheck( void ) const +status_t BNetAddress::InitCheck( void ) { return ( fInitialized == B_OK ) ? B_OK : B_ERROR; } @@ -337,10 +341,6 @@ status_t BNetAddress::Archive( BMessage* into, bool deep ) const return B_NO_INIT; } - //STM: When storing, should we store some kind of class name too... - //STM: Is there any way to deal with a complete failure here? (into - // not completely filled). - if ( into->AddInt8( "bnaddr_family", fFamily ) != B_OK ) { return B_ERROR; @@ -433,7 +433,6 @@ status_t BNetAddress::SetTo( const char* hostname, unsigned short port ) } else { - //STM: Print and/or log an error message? return B_ERROR; } } @@ -546,10 +545,9 @@ status_t BNetAddress::SetTo( const char* hostname, const char* protocol, ServiceEntry = getservbyname( service, protocol ); if ( ServiceEntry == NULL ) { - //STM: Print and/or log an error message? return B_ERROR; } - endservent( ); + // endservent( ); return SetTo( hostname, ServiceEntry->s_port ); } @@ -581,4 +579,3 @@ status_t BNetAddress::clone( const BNetAddress& RefParam ) } /*=------------------------------------------------------------------- End -=*/ - diff --git a/src/kits/network/libnetapi/NetBuffer.cpp b/src/kits/network/libnetapi/NetBuffer.cpp index 672eb22b87..c070f72fc6 100644 --- a/src/kits/network/libnetapi/NetBuffer.cpp +++ b/src/kits/network/libnetapi/NetBuffer.cpp @@ -1,257 +1,880 @@ -/****************************************************************************** -/ -/ File: NetBuffer.cpp -/ -/ Description: The Network API. -/ -/ Copyright 2002, OpenBeOS Project, All Rights Reserved. -/ -******************************************************************************/ +/*=--------------------------------------------------------------------------=* + * NetBuffer.cpp -- Implementation of the BNetBuffer class. + * + * Written by S.T. Mansfield (thephantom@mac.com) + * + * 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. + *=--------------------------------------------------------------------------=* + * Copyright (c) 2002, The OpenBeOS project. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *=--------------------------------------------------------------------------=* + */ + #include -#include #include +#include + #include -BNetBuffer::BNetBuffer(size_t size) - : fStatus(B_OK), - fData(NULL), - fSize(0), - fOffset(0) +/* + * Parametric ctor initialization list defaults. + */ +#define CTOR_INIT_LIST \ + BArchivable( ), \ + fInitialized( 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 defalt ctor. + */ +BNetBuffer::BNetBuffer( size_t size ) + : CTOR_INIT_LIST { - fStatus = Resize(size); + fInitialized = ( resize( size ) == B_OK ) ? B_OK : B_NO_INIT; } -BNetBuffer::BNetBuffer(const BNetBuffer & buffer) - : fStatus(B_OK), - fData(NULL), - fSize(0), - fOffset(0) + +/* BNetBuffer + *=--------------------------------------------------------------------------=* + * Purpose: + * Class copy ctor. + * + * Input parameter: + * refparam : Instance to copy. + */ +BNetBuffer::BNetBuffer( const BNetBuffer& refparam ) + : CTOR_INIT_LIST { - fStatus = AppendData(buffer.Data(), buffer.Size()); + fInitialized = ( clone( refparam ) == B_OK ) ? B_OK : B_NO_INIT; } -BNetBuffer::BNetBuffer(BMessage *archive) - : fStatus(B_OK), - fData(NULL), - fSize(0), - fOffset(0) + +/* BNetBuffer + *=--------------------------------------------------------------------------=* + * Purpose: + * Ctor to instantiate from serialized data (BMessage). + * + * Input parameter: + * archive : Serialized object to instantiate from. + */ +BNetBuffer::BNetBuffer( BMessage* archive ) + : CTOR_INIT_LIST { - // TODO - fStatus = B_ERROR; + status_t res; + 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; + + fInitialized = B_OK; } -BNetBuffer::~BNetBuffer() + +/* ~BNetBuffer + *=--------------------------------------------------------------------------=* + * Purpose: + * Class dtor. + */ +BNetBuffer::~BNetBuffer( void ) { - if (fData != NULL) - free(fData); + if ( fData != NULL ) + { + delete fData; + fData = NULL; + } + + fDataSize = fStackSize = fCapacity = 0; + + fInitialized = B_NO_INIT; } -status_t BNetBuffer::Archive(BMessage *into, bool deep) const + +/* operator= + *=--------------------------------------------------------------------------=* + * Purpose: + * Class' assignment operator. + * + * Input parameter: + * refparam : Instance to assign from. + */ +BNetBuffer& BNetBuffer::operator=( const BNetBuffer& refparam ) { - // TODO - return B_ERROR; + fInitialized = clone( refparam ); + + return *this; } -BArchivable *BNetBuffer::Instantiate(BMessage *archive) + +/* 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 ) { - // TODO - return NULL; + return ( fInitialized == B_OK ) ? B_OK : B_ERROR; } -BNetBuffer & BNetBuffer::operator = (const BNetBuffer & buffer) + +/* 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 { - Resize(0); - AppendData(buffer.Data(), buffer.Size()); - return *this; + if ( fInitialized != 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; } -status_t BNetBuffer::InitCheck() const + +/* 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 ) { - return fStatus; + if ( !validate_instantiation( archive, "BNetBuffer" ) ) + { + return NULL; + } + + BNetBuffer* bnb = new BNetBuffer( archive ); + if ( bnb == NULL ) + { + return NULL; + } + + if ( bnb->InitCheck( ) != B_OK ) + { + delete bnb; + return NULL; + } + + return bnb; } -const unsigned char * BNetBuffer::Data() const + +/* 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 ) { - return fData; + return dpush( B_INT8_TYPE, sizeof( int8 ), &Data ); } -unsigned char * BNetBuffer::Data() +status_t BNetBuffer::AppendUint8( uint8 Data ) { - return fData; + return dpush( B_UINT8_TYPE, sizeof( uint8 ), &Data ); } -size_t BNetBuffer::Size() const +status_t BNetBuffer::AppendInt16( int16 Data ) { - return fSize; + int16 locData = B_HOST_TO_BENDIAN_INT16( Data ); + return dpush( B_INT16_TYPE, sizeof( int16 ), &locData ); } -size_t BNetBuffer::BytesRemaining() const +status_t BNetBuffer::AppendUint16( uint16 Data ) { - return fSize - fOffset; + uint16 locData = B_HOST_TO_BENDIAN_INT16( Data ); + return dpush( B_UINT16_TYPE, sizeof( uint16 ), &locData ); } -status_t BNetBuffer::AppendInt8(int8 value) +status_t BNetBuffer::AppendInt32( int32 Data ) { - return AppendData(&value, sizeof(value)); + int32 locData = B_HOST_TO_BENDIAN_INT32( Data ); + return dpush( B_INT32_TYPE, sizeof( int32 ), &locData ); } -status_t BNetBuffer::AppendUInt8(uint8 value) +status_t BNetBuffer::AppendUint32( uint32 Data ) { - return AppendData(&value, sizeof(value)); + uint32 locData = B_HOST_TO_BENDIAN_INT32( Data ); + return dpush( B_UINT32_TYPE, sizeof( uint32 ), &locData ); } -status_t BNetBuffer::AppendInt16(int16 value) +status_t BNetBuffer::AppendInt64( int64 Data ) { - value = B_HOST_TO_BENDIAN_INT16(value); - return AppendData(&value, sizeof(value)); + int64 locData = B_HOST_TO_BENDIAN_INT64( Data ); + return dpush( B_INT64_TYPE, sizeof( int64 ), &locData ); } -status_t BNetBuffer::AppendUInt16(uint16 value) +status_t BNetBuffer::AppendUint64( uint64 Data ) { - value = B_HOST_TO_BENDIAN_INT16(value); - return AppendData(&value, sizeof(value)); + uint64 locData = B_HOST_TO_BENDIAN_INT64( Data ); + return dpush( B_UINT64_TYPE, sizeof( uint64 ), &locData ); } -status_t BNetBuffer::AppendInt32(int32 value) +status_t BNetBuffer::AppendFloat( float Data ) { - value = B_HOST_TO_BENDIAN_INT32(value); - return AppendData(&value, sizeof(value)); + return dpush( B_FLOAT_TYPE, sizeof( float ), &Data ); } -status_t BNetBuffer::AppendUInt32(uint32 value) +status_t BNetBuffer::AppendDouble( double Data ) { - value = B_HOST_TO_BENDIAN_INT32(value); - return AppendData(&value, sizeof(value)); + return dpush( B_DOUBLE_TYPE, sizeof( double ), &Data ); } -status_t BNetBuffer::AppendFloat(float value) +status_t BNetBuffer::AppendString( const char* Data ) { - return AppendData(&value, sizeof(value)); + return dpush( B_STRING_TYPE, strlen( Data ), Data ); } -status_t BNetBuffer::AppendDouble(double value) +status_t BNetBuffer::AppendData( const void* Data, size_t Length ) { - return AppendData(&value, sizeof(value)); + return dpush( B_RAW_TYPE, Length, Data ); } -status_t BNetBuffer::AppendString(const char * value) +status_t BNetBuffer::AppendMessage( const BMessage& Msg ) { - return AppendData(value, strlen(value) + 1); + 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; } -status_t BNetBuffer::AppendData(const void * data, size_t length) + +/* 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 ) { - if (Resize(fSize + length) == B_OK) { - memcpy(fData + fSize - length, data, length); - return B_OK; - } - return B_ERROR; + return dpop( B_INT8_TYPE, sizeof( int8 ), &Data ); } -status_t BNetBuffer::AppendInt64(int64 value) +status_t BNetBuffer::RemoveUint8( uint8& Data ) { - value = B_HOST_TO_BENDIAN_INT64(value); - return AppendData(&value, sizeof(value)); + return dpop( B_UINT8_TYPE, sizeof( uint8 ), &Data ); } -status_t BNetBuffer::AppendUInt64(uint64 value) +status_t BNetBuffer::RemoveInt16( int16& Data ) { - value = B_HOST_TO_BENDIAN_INT64(value); - return AppendData(&value, sizeof(value)); + // dpop will convert this bad boy from network to host byte order. + return dpop( B_INT16_TYPE, sizeof( int16 ), &Data ); } -status_t BNetBuffer::RemoveInt8(int8 & value) +status_t BNetBuffer::RemoveUint16( uint16& Data ) { - return RemoveData(&value, sizeof(value)); + // dpop will convert this beast from network to host byte order. + return dpop( B_UINT16_TYPE, sizeof( uint16 ), &Data ); } -status_t BNetBuffer::RemoveUInt8(uint8 & value) +status_t BNetBuffer::RemoveInt32( int32& Data ) { - return RemoveData(&value, sizeof(value)); + // dpop will convert this thang from network to host byte order. + return dpop( B_INT32_TYPE, sizeof( int32 ), &Data ); } -status_t BNetBuffer::RemoveInt16(int16 & value) +status_t BNetBuffer::RemoveUint32( uint32& Data ) { - status_t status = RemoveData(&value, sizeof(value)); - value = B_BENDIAN_TO_HOST_INT16(value); - return status; + // dpop will convert this variable from network to host byte order. + return dpop( B_UINT32_TYPE, sizeof( uint32 ), &Data ); } -status_t BNetBuffer::RemoveUInt16(uint16 & value) +status_t BNetBuffer::RemoveInt64( int64& Data ) { - status_t status = RemoveData(&value, sizeof(value)); - value = B_BENDIAN_TO_HOST_INT16(value); - return status; + // dpop will convert this bag-o-bits from network to host byte order. + return dpop( B_INT64_TYPE, sizeof( int64 ), &Data ); } -status_t BNetBuffer::RemoveInt32(int32 & value) +status_t BNetBuffer::RemoveUint64( uint64& Data ) { - status_t status = RemoveData(&value, sizeof(value)); - value = B_BENDIAN_TO_HOST_INT32(value); - return status; + // dpop will convert this construct from network to host byte order. + return dpop( B_UINT64_TYPE, sizeof( uint64 ), &Data ); } -status_t BNetBuffer::RemoveUInt32(uint32 & value) +status_t BNetBuffer::RemoveFloat( float& Data ) { - status_t status = RemoveData(&value, sizeof(value)); - value = B_BENDIAN_TO_HOST_INT32(value); - return status; + return dpop( B_FLOAT_TYPE, sizeof( float ), &Data ); } -status_t BNetBuffer::RemoveFloat(float & value) +status_t BNetBuffer::RemoveDouble( double& Data ) { - return RemoveData(&value, sizeof(value)); + return dpop( B_DOUBLE_TYPE, sizeof( double ), &Data ); } -status_t BNetBuffer::RemoveDouble(double & value) +status_t BNetBuffer::RemoveString( char* Data, size_t Length ) { - return RemoveData(&value, sizeof(value)); + return dpop( B_STRING_TYPE, Length, Data ); } -status_t BNetBuffer::RemoveString(char * value, size_t length) +status_t BNetBuffer::RemoveData( void* Data, size_t Length ) { - if (fOffset < fSize && length > 0) { - while (--length > 0 && fOffset < fSize && fData[fOffset] != 0) { - *value++ = fData[fOffset++]; - } - *value = 0; - return B_OK; - } - return B_ERROR; + return dpop( B_RAW_TYPE, Length, Data ); } -status_t BNetBuffer::RemoveData(void * data, size_t length) +status_t BNetBuffer::RemoveMessage( BMessage& message ) { - if (fOffset + length <= fSize) { - memcpy(data, fData + fOffset, length); - fOffset += length; - return B_OK; - } - return B_ERROR; + 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; } -status_t BNetBuffer::RemoveInt64(int64 & value) + +/* 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 status = RemoveData(&value, sizeof(value)); - value = B_BENDIAN_TO_HOST_INT64(value); - return status; + // 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. } -status_t BNetBuffer::RemoveUInt64(uint64 & value) + +/* 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 { - status_t status = RemoveData(&value, sizeof(value)); - value = B_BENDIAN_TO_HOST_INT64(value); - return status; + return fDataSize; } -status_t BNetBuffer::Resize(size_t size) + +/* 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 { - unsigned char * data = (unsigned char *) realloc(fData, (size + 16) & ~15); - if (data != NULL || size == 0) { - fData = data; - fSize = size; - return B_OK; - } - return B_ERROR; + return ( fCapacity - fStackSize ); } + + +/* 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 ) +{ + if ( !RefParam.fInitialized ) + { + 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; +} + + +/* 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 ( fInitialized != 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 != 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 != 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 ( fInitialized != 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 +} + + +/*=------------------------------------------------------------------- End -=*/ diff --git a/src/kits/network/libnetapi/NetDebug.cpp b/src/kits/network/libnetapi/NetDebug.cpp index 614710c7c4..e4b82172de 100644 --- a/src/kits/network/libnetapi/NetDebug.cpp +++ b/src/kits/network/libnetapi/NetDebug.cpp @@ -1,15 +1,187 @@ -#include +/*=--------------------------------------------------------------------------=* + * NetDebug.cpp -- Implementation of the BNetDebug class. + * + * Written by S.T. Mansfield (thephantom@mac.com) + * + * Remarks: + * * Although this would more properly be implemented as a namespace... + * * Do not burn the candle at both ends as it leads to the life of a + * hairdresser. + *=--------------------------------------------------------------------------=* + * Copyright (c) 2002, The OpenBeOS project. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *=--------------------------------------------------------------------------=* + */ + + +#include +#include +#include + #include -void BNetDebug::Enable(bool) { + +// Off by default cuz the BeBook sez so. +static bool g_IsEnabled = false; + + +/* Enable + *=--------------------------------------------------------------------------=* + * Purpose: + * Enable/disable debug message capability for your app. + * + * Input parameter: + * Enable : True/False to enable/disable debug message output. + * + * Remarks: + * This flag/setting is a per application basis, and not a per-instance + * occurrence as one would expect when instantiating an instance of + * this class. This is by design as /everything/ is static. Caveat + * Emptor. Needs to be dealt with in G.E. + */ +void BNetDebug::Enable( bool Enable ) +{ + g_IsEnabled = Enable; } -bool BNetDebug::IsEnabled() { - return false; + +/* IsEnabled + *=--------------------------------------------------------------------------=* + * Purpose: + * Quiz the enable/disable status. + * + * Returns: + * True/false if enabled/disabled. + */ +bool BNetDebug::IsEnabled( void ) +{ + return g_IsEnabled; } -void BNetDebug::Print(const char *msg) { + +/* Print + *=--------------------------------------------------------------------------=* + * Purpose: + * If enabled, spew forth a debug message. + * + * Input parameter: + * msg : The message to print. + * + * Remarks: + * * Basically a no-op if not enabled. + * * We're inheriting R5 (and Nettle's) behavior, so... + * * The output is always "debug: msg\n" Yes, kids, you read it right; + * you get a newline whether you want it or not! + * * If msg is empty, you get "debug: \n" + * * Message is always printed on stderr. Redirect accordingly. + */ +void BNetDebug::Print( const char* msg ) +{ + if ( g_IsEnabled ) + { + if ( msg == NULL ) + { + msg = ""; + } + + fprintf( stderr, "debug: %s\n", msg ); + } } -void BNetDebug::Dump(const char *data, size_t size, const char *title) { + +/* Dump + *=--------------------------------------------------------------------------=* + * Purpose: + * If enabled, spew forth a combination hex/ASCII dump of raw data. + * + * Input parameters: + * data : Data to dump. + * size : How many bytes of data to dump. + * title : Title to display in message header. + * + * Remarks: + * * Basically a no-op if not enabled. + * * We're inheriting R5 (and Nettle's) behavior, so... + * * The output is always "debug: msg\n" Yes, kids, you read it right; + * you get a newline whether you want it or not! + * * If msg is empty, you get "debug: \n" + * * Behavior is undefined if data or title is NULL. This is a + * possible design flaw in Nettle/R5. + * * Do not expect an output like this: + * 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF | abcdefghijklmnop + * 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF | abcdefghijklmnop + * 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF | abcdefghijklmnop + * 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF | abcdefghijklmnop + * because you ain't gettin' it. You will get a complete hex dump, + * /followed/ by an ASCII dump. More Glass Elevator stuff. + * * Nettle dumps to stdOUT, the BeBook says all output goes to stdERR, so + * the author chose to... + * * always print to stdERR. Redirect accordingly. + * * stderr is flushed after the dump is complete to keep things + * reasonably cohesive in appearance. This might be an expensive + * operation so use judiciously. + */ +void BNetDebug::Dump( const char* data, size_t size, const char* title ) +{ + int i; + char line[17]; + + if ( g_IsEnabled == false ) + { + return; + } + + fprintf( stderr, "----------\n%s\n(dumping %d bytes)\n", title, size ); + + memset( line, 0, sizeof( line ) ); + + while ( i < size ) + { + fprintf( stderr, "%02x ", ( unsigned char )data[i] ); + + line[i % 16] = ( isprint( data[i] ) ) ? data[i] : '.'; + + if ( ( i + 1 ) % 16 == 0 ) + { + fprintf( stderr, " | %s\n", line ); + memset( line, 0, sizeof( line ) ); + } + + i++; + } + + if ( ( i + 1 ) % 16 != 0 ) + { + while ( i % 16 != 0 ) + { + printf( " " ); + i++; + } + + fprintf( stderr, " | %s", line ); + } + + fprintf( stderr, "\n----------\n" ); + fflush( stderr ); } + + +/*=------------------------------------------------------------------- End -=*/ +