crpcxdr

Does this RPC xdr copy make sense?


I have this RPC structure T_Struct that came from the wire. I would like to make a copy of it, but I do not want to write a separate function to deal with all structures, allocations, and arrays of its members (especially that I will have to do the same thing for tones of other structures.)

Since I have already a way to decode, encode, and free, would it make sense to have something like that:

void copy_T_Struct( T_Struct* destination, T_Struct* source )
{
   XDR xdr ;

   /* Is there a way I can know the size of the buffer for the struct? */
   char buffer[ 10240 ] ;

   xdrmem_create( &xdr, buffer, sizeof( buffer ), XDR_ENCODE ) ;
   ( *xdr_T_Struct )( &xdr, source ) ; /* serialize to buffer */
   xdr.x_op = XDR_DECODE ;
   memset( destination, 0, sizeof( *destination )) ; /* without it I see segfault */
   ( *xdr_T_Struct )( &xdr, destination ) ; /* serialize back to T_Struct */
   xdr_destroy( &xdr ) ;
}

I understand that at the end, I will also be able to call xdr_free((xdrproc_t)xdr_T_Struct, (char *)destination ) ;


Solution

  • Here is the final solution. Notice that this is a C version.

    Uses static reallocatable buffer. Example of us below.

    xdr_copy.h

    #define XDR_COPY( T, d, s ) xdr_copy_(( xdrproc_t )xdr_##T, ( char* )d, ( const char* )s, sizeof( T ))
    extern bool_t xdr_copy( xdrproc_t proc, char* d, const char* s ) ;
    extern bool_t xdr_copy_( xdrproc_t proc, char* d, const char* s, const unsigned size ) ;
    

    xdr_copy.c

    ... /* removing all #includes for clarity */
    #define XDR_BUFFER_SIZE   ( 100 * 1024 )
    #define XDR_BUFFER_DELTA  ( 10 * 1024 )
    
    static char*    xdr_buffer = NULL ;
    static unsigned xdr_buffer_size = 0 ;
    
    static char* xdr_buffer_realloc( const unsigned delta )
    {
       char* rv = realloc( xdr_buffer, xdr_buffer_size + delta ) ;
    
       if ( rv )
       {
          xdr_buffer_size += delta ;
          xdr_buffer = rv ;
       }
    
       return rv ;
    }
    
    static char* get_xdr_buffer()
    {
       if ( !xdr_buffer )
          xdr_buffer = xdr_buffer_realloc( XDR_BUFFER_SIZE ) ;
    
      return xdr_buffer ;
    }
    
    bool_t xdr_copy( xdrproc_t proc, char* d, const char* s )
    {
       XDR   x ;
       char* buffer = get_xdr_buffer() ;
    
       while ( buffer )
       {
          xdrmem_create( &x, buffer, xdr_buffer_size, XDR_ENCODE ) ;
          if (( *proc )( &x, ( caddr_t* )s ))
          {
             xdr_destroy( &x ) ;
             xdrmem_create( &x, buffer, xdr_buffer_size, XDR_DECODE ) ;
             ( *proc )( &x, ( caddr_t* )d ) ;
             break ;
          }
          else
          {
             buffer = xdr_buffer_realloc( XDR_BUFFER_DELTA ) ;
             xdr_destroy( &x ) ;
          }
       }
    
       if ( buffer )
       {
          xdr_destroy( &x ) ;
          return 1 ;
       }
       else
          return 0 ;
    }
    
    bool_t xdr_copy_( xdrproc_t proc, char* d, const char* s, const unsigned size )
    {
       memset( d, 0, size ) ;
       return xdr_copy( proc, d, s ) ;
    }
    

    Example

    MyRPCArgs copy ;
    
    if ( !XDR_COPY( MyRPCArgs, &copy, source_ptr ))
       ... /* report memory allocation issue */