R – Send a structure through a socket using tpl for serialization using c


After reading a few related questions I've decided to use the tpl library to serialize my structures in order to send and receive them through sockets. I'm having trouble understanding how to send and receive the tpl images using sockets. I get a segfault error on the server side when I call the tpl_dump function.

I know the sockets are working on both end because I was using the code to previously send strings back and forth. I was also able to use tpl to create and read an tpl image on the client without any issues.

This isn't the structure I eventually want to be sending back and forth, but I hope to figure this sample out so I can do this in the future. I know I'm mishandling something between the incoming buffer and the tpl_dump. I'm still learning C (as evidenced by my previous questions) so I apologize if I have glaring errors in my code.

The issues Nikolai pointed out have been corrected in the code below. However the server code logs error: tpl_load to non-root node and still segfaults at tpl_unpack(tn, 0);

Client Code:

tpl_node *tn;

void *addr;
size_t len;

struct ci {
        char c;
        int i;
struct ci sample = {'a', 1};
tn = tpl_map("S(ci)", &sample); /* pass structure address */
tpl_pack(tn, 0);
tpl_dump(tn, TPL_MEM, &addr, &len );

send(sockfd, addr, len, 0);

Server Code:

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {

//error handling

} else {
    tpl_node *tn;

    struct ci {
        char c;
        int i;

struct ci recieve;

tpl_map("S(ci)", &recieve);
tpl_load(tn, TPL_MEM, &buf, &nbytes );
tpl_unpack(tn, 0);

In case this will come in handy – tpl user's guide

Best Solution

It looks like you are misusing the tpl_dump, at least on the client - the second argument is supposed to be void**, not int*. The macro stores address of the allocated buffer into your addr integer, so you are sending address (plus some garbage), not data to the server. The sequence of calls on the server side also look out of order.

Looking closer at your source:

  • remove ampersands (&) from buf and len; the tpl_load expects void* and size_t;
  • you need to free() the memory when you're done;
  • you need to watch out for short socket reads - you might get less (or more) then you sent on a read from TCP socket.

Here's a simple complete example without sockets:

#include <stdlib.h>
#include <stdio.h>
#include "tpl.h"

int main( int argc, char* argv[] )
    char* buffer;
    size_t i, len;
    tpl_node *tn;
    struct ci { char c; int i; } s = {'a', 1}, s1;

    printf( "input {%c,%d}\n", s.c, s.i );

    tn = tpl_map( "S(ci)", &s );  /* pass structure address */
    tpl_pack( tn, 0 );
    tpl_dump( tn, TPL_MEM, &buffer, &len );
    tpl_free( tn );

    printf( "size = %lu\n", len );

    tn = tpl_map( "S(ci)", &s1 );
    tpl_load( tn, TPL_MEM, buffer, len );
    tpl_unpack( tn, 0 );
    tpl_free( tn );
    free( buffer );

    printf( "output {%c,%d}\n", s1.c, s1.i );
    return 0;