2011-12-21 09:55:05 +00:00
/*
Serval Distributed Numbering Architecture ( DNA )
Copyright ( C ) 2010 Paul Gardner - Stephen
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
2012-12-03 23:26:24 +00:00
# include "mem.h"
2012-02-23 02:15:42 +00:00
# include "serval.h"
2012-08-22 00:51:38 +00:00
# include "overlay_buffer.h"
2011-08-08 06:41:05 +00:00
2012-08-22 00:51:38 +00:00
/*
When writing to a buffer , sizeLimit may place an upper bound on the amount of space to use
When reading from a buffer , sizeLimit should first be set to the length of any existing data .
In either case , functions that don ' t take an offset use and advance the position .
*/
struct overlay_buffer * ob_new ( void )
2011-08-08 06:41:05 +00:00
{
2012-08-22 00:51:38 +00:00
struct overlay_buffer * ret = calloc ( sizeof ( struct overlay_buffer ) , 1 ) ;
2011-08-08 06:41:05 +00:00
if ( ! ret ) return NULL ;
2012-08-22 00:51:38 +00:00
2011-08-08 06:41:05 +00:00
ob_unlimitsize ( ret ) ;
return ret ;
}
2012-07-18 05:00:16 +00:00
// index an existing static buffer.
// and allow other callers to use the ob_ convenience methods for reading and writing up to size bytes.
2012-08-22 00:51:38 +00:00
struct overlay_buffer * ob_static ( unsigned char * bytes , int size ) {
struct overlay_buffer * ret = calloc ( sizeof ( struct overlay_buffer ) , 1 ) ;
2012-07-18 05:00:16 +00:00
if ( ! ret ) return NULL ;
ret - > bytes = bytes ;
2012-08-22 00:51:38 +00:00
ret - > allocSize = size ;
ret - > allocated = 0 ;
ob_unlimitsize ( ret ) ;
2012-07-18 05:00:16 +00:00
return ret ;
}
2012-08-22 00:51:38 +00:00
// create a new overlay buffer from an existing piece of another buffer.
// Both buffers will point to the same memory region.
// It is up to the caller to ensure this buffer is not used after the parent buffer is freed.
struct overlay_buffer * ob_slice ( struct overlay_buffer * b , int offset , int length ) {
2012-10-15 05:06:36 +00:00
if ( offset + length > b - > allocSize ) {
WHY ( " Buffer isn't long enough to slice " ) ;
return NULL ;
}
2012-08-27 00:34:59 +00:00
2012-08-22 00:51:38 +00:00
struct overlay_buffer * ret = calloc ( sizeof ( struct overlay_buffer ) , 1 ) ;
2012-08-27 00:34:59 +00:00
if ( ! ret )
return NULL ;
2012-08-22 00:51:38 +00:00
ret - > bytes = b - > bytes + offset ;
ret - > allocSize = length ;
ret - > allocated = 0 ;
ob_unlimitsize ( ret ) ;
return ret ;
}
struct overlay_buffer * ob_dup ( struct overlay_buffer * b ) {
struct overlay_buffer * ret = calloc ( sizeof ( struct overlay_buffer ) , 1 ) ;
ret - > sizeLimit = b - > sizeLimit ;
ret - > position = b - > position ;
ret - > checkpointLength = b - > checkpointLength ;
2012-08-27 00:34:59 +00:00
if ( b - > bytes & & b - > allocSize ) {
// duplicate any bytes that might be relevant
2012-08-22 00:51:38 +00:00
int byteCount = b - > sizeLimit ;
2012-08-27 00:34:59 +00:00
if ( byteCount < b - > position )
byteCount = b - > position ;
2012-08-22 00:51:38 +00:00
if ( byteCount > b - > allocSize )
byteCount = b - > allocSize ;
ob_append_bytes ( ret , b - > bytes , byteCount ) ;
}
return ret ;
}
int ob_free ( struct overlay_buffer * b )
2011-08-08 06:41:05 +00:00
{
if ( ! b ) return WHY ( " Asked to free NULL " ) ;
2012-08-22 00:51:38 +00:00
if ( b - > bytes & & b - > allocated ) free ( b - > bytes ) ;
2011-08-08 06:41:05 +00:00
b - > bytes = NULL ;
b - > allocSize = 0 ;
b - > sizeLimit = 0 ;
free ( b ) ;
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_checkpoint ( struct overlay_buffer * b )
2011-08-08 06:41:05 +00:00
{
if ( ! b ) return WHY ( " Asked to checkpoint NULL " ) ;
2012-08-22 00:51:38 +00:00
b - > checkpointLength = b - > position ;
2011-08-08 06:41:05 +00:00
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_rewind ( struct overlay_buffer * b )
2011-08-08 06:41:05 +00:00
{
if ( ! b ) return WHY ( " Asked to rewind NULL " ) ;
2012-08-22 00:51:38 +00:00
b - > position = b - > checkpointLength ;
2011-08-08 06:41:05 +00:00
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_limitsize ( struct overlay_buffer * b , int bytes )
2011-08-08 06:41:05 +00:00
{
if ( ! b ) return WHY ( " Asked to limit size of NULL " ) ;
2012-08-22 00:51:38 +00:00
if ( b - > position > bytes ) return WHY ( " Length of data in buffer already exceeds size limit " ) ;
2011-08-08 06:41:05 +00:00
if ( b - > checkpointLength > bytes ) return WHY ( " Checkpointed length of data in buffer already exceeds size limit " ) ;
2012-08-22 00:51:38 +00:00
if ( b - > bytes & & ( ! b - > allocated ) & & bytes > b - > allocSize ) return WHY ( " Size limit exceeds buffer size " ) ;
2012-07-18 05:00:16 +00:00
if ( bytes < 0 ) return WHY ( " Can't limit buffer to a negative size " ) ;
2011-08-08 06:41:05 +00:00
b - > sizeLimit = bytes ;
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_unlimitsize ( struct overlay_buffer * b )
2011-08-08 06:41:05 +00:00
{
if ( ! b ) return WHY ( " b is NULL " ) ;
b - > sizeLimit = - 1 ;
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_makespace ( struct overlay_buffer * b , int bytes )
2011-08-08 06:41:05 +00:00
{
2012-08-22 00:51:38 +00:00
if ( b - > sizeLimit ! = - 1 & & b - > position + bytes > b - > sizeLimit ) {
2012-07-18 05:00:16 +00:00
if ( debug & DEBUG_PACKETFORMATS ) WHY ( " Asked to make space beyond size limit " ) ;
2012-08-22 00:51:38 +00:00
return - 1 ;
2011-08-08 06:41:05 +00:00
}
2012-08-22 00:51:38 +00:00
// already enough space?
if ( b - > position + bytes < b - > allocSize )
return 0 ;
if ( b - > bytes & & ! b - > allocated )
2012-07-18 05:00:16 +00:00
return WHY ( " Can't resize a static buffer " ) ;
2012-03-22 20:36:57 +00:00
if ( 0 )
2012-08-22 00:51:38 +00:00
DEBUGF ( " ob_makespace(%p,%d) \n b->bytes=%p,b->position=%d,b->allocSize=%d \n " ,
b , bytes , b - > bytes , b - > position , b - > allocSize ) ;
int newSize = b - > position + bytes ;
if ( newSize < 64 ) newSize = 64 ;
if ( newSize & 63 ) newSize + = 64 - ( newSize & 63 ) ;
if ( newSize > 1024 ) {
if ( newSize & 1023 ) newSize + = 1024 - ( newSize & 1023 ) ;
}
if ( newSize > 65536 ) {
if ( newSize & 65535 ) newSize + = 65536 - ( newSize & 65535 ) ;
}
if ( 0 ) DEBUGF ( " realloc(b->bytes=%p,newSize=%d) " , b - > bytes , newSize ) ;
/* XXX OSX realloc() seems to be able to corrupt things if the heap is not happy when calling realloc(), making debugging memory corruption much harder.
So will do a three - stage malloc , bcopy , free to see if we can tease the bug out that way . */
/*
unsigned char * r = realloc ( b - > bytes , newSize ) ;
if ( ! r ) return WHY ( " realloc() failed " ) ;
b - > bytes = r ;
*/
2012-03-22 20:36:57 +00:00
# ifdef MALLOC_PARANOIA
2012-03-22 06:40:27 +00:00
# warning adding lots of padding to try to catch overruns
2012-08-22 00:51:38 +00:00
if ( b - > bytes ) {
int i ;
int corrupt = 0 ;
for ( i = 0 ; i < 4096 ; i + + ) if ( b - > bytes [ b - > allocSize + i ] ! = 0xbd ) corrupt + + ;
if ( corrupt ) {
WHYF ( " !!!!!! %d corrupted bytes in overrun catch tray " , corrupt ) ;
dump ( " overrun catch tray " , & b - > bytes [ b - > allocSize ] , 4096 ) ;
sleep ( 3600 ) ;
}
}
unsigned char * new = malloc ( newSize + 4096 ) ;
if ( ! new ) return WHY ( " realloc() failed " ) ;
{
int i ;
for ( i = 0 ; i < 4096 ; i + + ) new [ newSize + i ] = 0xbd ;
}
2012-03-22 20:36:57 +00:00
# else
2012-08-22 00:51:38 +00:00
unsigned char * new = malloc ( newSize ) ;
2012-03-22 20:36:57 +00:00
# endif
2012-08-22 00:51:38 +00:00
bcopy ( b - > bytes , new , b - > position ) ;
if ( b - > bytes ) free ( b - > bytes ) ;
b - > bytes = new ;
b - > allocated = 1 ;
b - > allocSize = newSize ;
return 0 ;
2011-08-08 06:41:05 +00:00
}
2012-03-22 06:03:25 +00:00
2012-07-18 05:00:16 +00:00
/*
Functions that append data and increase the size of the buffer if possible / required
*/
2012-08-22 00:51:38 +00:00
int ob_append_byte ( struct overlay_buffer * b , unsigned char byte )
2011-09-03 21:06:39 +00:00
{
if ( ob_makespace ( b , 1 ) ) return WHY ( " ob_makespace() failed " ) ;
2012-08-22 00:51:38 +00:00
b - > bytes [ b - > position + + ] = byte ;
2011-09-03 21:06:39 +00:00
return 0 ;
}
2012-08-22 00:51:38 +00:00
unsigned char * ob_append_space ( struct overlay_buffer * b , int count )
2012-04-13 16:44:41 +00:00
{
2012-10-15 05:06:36 +00:00
if ( ob_makespace ( b , count ) ) {
WHY ( " ob_makespace() failed " ) ;
return NULL ;
}
2012-04-13 16:44:41 +00:00
2012-08-22 00:51:38 +00:00
unsigned char * r = & b - > bytes [ b - > position ] ;
b - > position + = count ;
2012-04-13 16:44:41 +00:00
return r ;
}
2012-08-22 00:51:38 +00:00
int ob_append_bytes ( struct overlay_buffer * b , unsigned char * bytes , int count )
2011-08-08 06:41:05 +00:00
{
if ( ob_makespace ( b , count ) ) return WHY ( " ob_makespace() failed " ) ;
2012-08-22 00:51:38 +00:00
bcopy ( bytes , & b - > bytes [ b - > position ] , count ) ;
b - > position + = count ;
2011-08-08 06:41:05 +00:00
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_append_ui16 ( struct overlay_buffer * b , uint16_t v )
2011-08-08 06:41:05 +00:00
{
2012-08-22 00:51:38 +00:00
if ( ob_makespace ( b , 2 ) ) return WHY ( " ob_makespace() failed " ) ;
b - > bytes [ b - > position ] = ( v > > 8 ) & 0xFF ;
b - > bytes [ b - > position + 1 ] = v & 0xFF ;
b - > position + = 2 ;
return 0 ;
2011-08-08 06:41:05 +00:00
}
2012-08-22 00:51:38 +00:00
int ob_append_ui32 ( struct overlay_buffer * b , uint32_t v )
2011-08-08 06:41:05 +00:00
{
2012-08-22 00:51:38 +00:00
if ( ob_makespace ( b , 4 ) ) return WHY ( " ob_makespace() failed " ) ;
b - > bytes [ b - > position ] = ( v > > 24 ) & 0xFF ;
b - > bytes [ b - > position + 1 ] = ( v > > 16 ) & 0xFF ;
b - > bytes [ b - > position + 2 ] = ( v > > 8 ) & 0xFF ;
b - > bytes [ b - > position + 3 ] = v & 0xFF ;
b - > position + = 4 ;
return 0 ;
2011-08-08 06:41:05 +00:00
}
2011-08-17 01:22:17 +00:00
2012-08-22 00:51:38 +00:00
int ob_append_rfs ( struct overlay_buffer * b , int l )
2011-08-17 01:22:17 +00:00
{
/* Encode the specified length and append it to the buffer */
if ( l < 0 | | l > 0xffff ) return - 1 ;
2012-07-18 05:00:16 +00:00
2011-08-17 01:22:17 +00:00
/* First work out how long the field needs to be, then write dummy bytes
2012-07-18 05:00:16 +00:00
and use ob_patch_rfs to set the value . That way we have only one
lot of code that does the encoding . */
2012-08-22 00:51:38 +00:00
b - > var_length_offset = b - > position ;
2011-08-17 01:22:17 +00:00
b - > var_length_bytes = rfs_length ( l ) ;
2012-07-18 05:00:16 +00:00
2011-08-17 01:22:17 +00:00
unsigned char c [ 3 ] = { 0 , 0 , 0 } ;
if ( ob_append_bytes ( b , c , b - > var_length_bytes ) ) {
b - > var_length_offset = 0 ;
return - 1 ;
}
2012-07-18 05:00:16 +00:00
2011-08-17 01:22:17 +00:00
return ob_patch_rfs ( b , l ) ;
2012-07-18 05:00:16 +00:00
}
/*
Functions that read / write data within the existing length limit
*/
2012-08-22 00:51:38 +00:00
// make sure a range of bytes is valid for reading
int test_offset ( struct overlay_buffer * b , int start , int length ) {
if ( ! b ) return - 1 ;
if ( start < 0 ) return - 1 ;
if ( b - > sizeLimit > = 0 & & start + length > b - > sizeLimit ) return - 1 ;
if ( start + length > b - > allocSize ) return - 1 ;
2012-07-18 05:00:16 +00:00
return 0 ;
}
2011-08-17 01:22:17 +00:00
2012-08-22 00:51:38 +00:00
int ob_getbyte ( struct overlay_buffer * b , int ofs )
2012-07-18 05:00:16 +00:00
{
2012-08-22 00:51:38 +00:00
if ( test_offset ( b , ofs , 1 ) )
return - 1 ;
return b - > bytes [ ofs ] ;
}
int ob_get_bytes ( struct overlay_buffer * b , unsigned char * buff , int len ) {
if ( test_offset ( b , b - > position , len ) )
return - 1 ;
bcopy ( b - > bytes + b - > position , buff , len ) ;
b - > position + = len ;
2012-07-18 05:00:16 +00:00
return 0 ;
}
2012-08-22 00:51:38 +00:00
unsigned char * ob_get_bytes_ptr ( struct overlay_buffer * b , int len ) {
if ( test_offset ( b , b - > position , len ) )
return NULL ;
unsigned char * ret = b - > bytes + b - > position ;
b - > position + = len ;
return ret ;
}
uint32_t ob_get_ui32 ( struct overlay_buffer * b )
2012-07-18 05:00:16 +00:00
{
2012-08-22 00:51:38 +00:00
if ( test_offset ( b , b - > position , 4 ) )
return 0xFFFFFFFF ; // ... unsigned
uint32_t ret = b - > bytes [ b - > position ] < < 24
| b - > bytes [ b - > position + 1 ] < < 16
| b - > bytes [ b - > position + 2 ] < < 8
| b - > bytes [ b - > position + 3 ] ;
b - > position + = 4 ;
return ret ;
2012-07-18 05:00:16 +00:00
}
2012-08-22 00:51:38 +00:00
uint16_t ob_get_ui16 ( struct overlay_buffer * b )
2012-07-18 05:00:16 +00:00
{
2012-08-22 00:51:38 +00:00
if ( test_offset ( b , b - > position , 2 ) )
return 0xFFFF ; // ... unsigned
uint16_t ret = b - > bytes [ b - > position ] < < 8
| b - > bytes [ b - > position + 1 ] ;
b - > position + = 2 ;
return ret ;
}
2012-07-18 05:00:16 +00:00
2012-08-22 00:51:38 +00:00
int ob_get ( struct overlay_buffer * b ) {
if ( test_offset ( b , b - > position , 1 ) )
return - 1 ;
return b - > bytes [ b - > position + + ] ;
2011-08-17 01:22:17 +00:00
}
int rfs_length ( int l )
{
if ( l < 0 ) return - 1 ;
if ( l < 250 ) return 1 ;
else if ( l < ( 255 + 250 + ( 256 * 4 ) ) ) return 2 ;
else if ( l < = 0xffff ) return 3 ;
else return - 1 ;
}
int rfs_encode ( int l , unsigned char * b )
{
if ( l < 250 ) { b [ 0 ] = l ; }
else if ( l < ( 255 + 250 + ( 256 * 4 ) ) ) {
2012-05-07 07:20:49 +00:00
l - = 250 ;
int page = ( l > > 8 ) ;
l & = 0xff ;
b [ 0 ] = RFS_PLUS250 + page ;
b [ 1 ] = l ;
2011-08-17 01:22:17 +00:00
} else {
b [ 0 ] = RFS_3BYTE ;
b [ 1 ] = l > > 8 ;
b [ 2 ] = l & 0xff ;
}
return 0 ;
}
int rfs_decode ( unsigned char * b , int * ofs )
{
int rfs = b [ * ofs ] ;
switch ( rfs ) {
case RFS_PLUS250 : case RFS_PLUS456 : case RFS_PLUS762 : case RFS_PLUS1018 : case RFS_PLUS1274 :
rfs = 250 + 256 * ( rfs - RFS_PLUS250 ) + b [ + + ( * ofs ) ] ;
break ;
case RFS_3BYTE : rfs = ( b [ ( * ofs ) + 1 ] < < 8 ) + b [ ( * ofs ) + 2 ] ; ( * ofs ) + = 2 ;
default : /* Length is natural value of field, so nothing to do */
break ;
}
( * ofs ) + + ;
return rfs ;
}
2012-08-16 06:55:20 +00:00
// move the data at offset, by shift bytes
2012-08-22 00:51:38 +00:00
int ob_indel_space ( struct overlay_buffer * b , int offset , int shift )
2011-08-17 01:22:17 +00:00
{
2012-08-22 00:51:38 +00:00
if ( offset > = b - > position ) return - 1 ;
2012-08-16 06:55:20 +00:00
if ( shift > 0 & & ob_makespace ( b , shift ) ) return - 1 ;
2012-08-22 00:51:38 +00:00
bcopy ( & b - > bytes [ offset ] , & b - > bytes [ offset + shift ] , b - > position - offset ) ;
b - > position + = shift ;
2011-08-17 01:22:17 +00:00
return 0 ;
}
2012-08-22 00:51:38 +00:00
int ob_patch_rfs ( struct overlay_buffer * b , int l )
2011-08-17 01:22:17 +00:00
{
2012-07-12 00:50:13 +00:00
if ( l = = COMPUTE_RFS_LENGTH ) {
// assume the payload has been written, we can now calculate the actual length
2012-08-22 00:51:38 +00:00
l = b - > position - ( b - > var_length_offset + b - > var_length_bytes ) ;
2012-07-12 00:50:13 +00:00
}
2011-08-17 01:22:17 +00:00
if ( l < 0 | | l > 0xffff ) return - 1 ;
/* Adjust size of field */
int new_size = rfs_length ( l ) ;
2012-08-16 06:55:20 +00:00
int shift = new_size - b - > var_length_bytes ;
2012-04-15 20:36:43 +00:00
if ( shift ) {
if ( debug & DEBUG_PACKETCONSTRUCTION ) {
2012-07-31 06:50:48 +00:00
DEBUGF ( " Patching RFS for rfs_size=%d (was %d), so indel %d btyes " ,
2012-04-15 20:36:43 +00:00
new_size , b - > var_length_bytes , shift ) ;
dump ( " before indel " ,
& b - > bytes [ b - > var_length_offset ] ,
2012-08-22 00:51:38 +00:00
b - > position - b - > var_length_offset ) ;
2012-04-15 20:36:43 +00:00
}
2012-08-16 06:55:20 +00:00
if ( ob_indel_space ( b , b - > var_length_offset + b - > var_length_bytes , shift ) ) return - 1 ;
2012-04-15 20:36:43 +00:00
if ( debug & DEBUG_PACKETCONSTRUCTION ) {
dump ( " after indel " ,
& b - > bytes [ b - > var_length_offset ] ,
2012-08-22 00:51:38 +00:00
b - > position - b - > var_length_offset ) ;
2012-04-15 20:36:43 +00:00
}
}
2011-08-17 01:22:17 +00:00
if ( rfs_encode ( l , & b - > bytes [ b - > var_length_offset ] ) ) return - 1 ;
2012-04-15 20:36:43 +00:00
if ( debug & DEBUG_PACKETCONSTRUCTION ) {
dump ( " after patch " ,
& b - > bytes [ b - > var_length_offset ] ,
2012-08-22 00:51:38 +00:00
b - > position - b - > var_length_offset ) ;
2012-04-15 20:36:43 +00:00
}
2011-08-17 01:22:17 +00:00
return 0 ;
}
2011-09-05 02:49:53 +00:00
int asprintable ( int c )
{
if ( c < ' ' ) return ' . ' ;
if ( c > 0x7e ) return ' . ' ;
return c ;
}
2012-08-22 00:51:38 +00:00
int ob_dump ( struct overlay_buffer * b , char * desc )
2011-09-05 02:49:53 +00:00
{
2012-08-22 00:51:38 +00:00
DEBUGF ( " overlay_buffer '%s' at %p : length=%d " , desc , b , b - > position ) ;
dump ( NULL , b - > bytes , b - > position ) ;
2011-09-05 02:49:53 +00:00
return 0 ;
}