
/*
	marshaling-burffer.c -- Marshaling Buffer library.
	Created on: 2008/11/28 11:45:58
	~yas/dsys/highscore/tcp/marshaling-burffer.c
*/

#include <stdio.h>	/* fprintf(), stderr */
#include <stdlib.h>	/* malloc() */
#include <arpa/inet.h>	/* htonl(), htons() */
#include <string.h>	/* memcpy() */

#include "marshaling-burffer.h"

int marbuf_init( marbuf_t *mb, size_t buflen ) {
	if( (mb->mb_buf = malloc(buflen)) == NULL ) {
	    return( 0 );
	}
	mb->mb_buflen  = buflen;
	mb->mb_bytes   = 0;
	mb->mb_current = mb->mb_buf;
}

void marbuf_final( marbuf_t *mb ) {
	free( mb->mb_buf );
	mb->mb_buf     = 0;
	mb->mb_buflen  = 0;
	mb->mb_bytes   = 0;
	mb->mb_current = 0;
}

int marbuf_receive_message( marbuf_t *mb, int socket ) {
    uint32_t msglen, msglen_net ;
	if( read(socket,&msglen_net,sizeof(msglen_net)) != sizeof(msglen_net) ) {
	    perror("read");
	    return( -1 );
	}
	msglen = ntohl( msglen_net );
	if( msglen > mb->mb_buflen ) {
	    fprintf(stderr,"message too large %u > %zu\n", msglen, mb->mb_buflen );
	    return( -1 );
	}
	if(  read(socket,mb->mb_buf,msglen) != msglen ) {
	    perror("read");
	    return( -1 );
	}
	mb->mb_bytes   = msglen;
	mb->mb_current = mb->mb_buf;
	return( msglen );
}

int marbuf_send_message( marbuf_t *mb, int socket ) {
    uint32_t msglen, msglen_net ;
 	msglen     = mb->mb_bytes;
	msglen_net = htonl(msglen);
	if( write(socket,&msglen_net,sizeof(msglen_net)) != sizeof(msglen_net) ) {
	    perror("write");
	    return( -1 );
	}
	if( write(socket,mb->mb_buf,msglen) != msglen )	{
	    perror("read");
	    return( -1 );
	}
	mb->mb_bytes   = 0;
	mb->mb_current = mb->mb_buf;
	return( msglen );
}

int marbuf_marshal_int( marbuf_t *mb, int data ) {
    uint32_t data_net ;
	if( mb->mb_bytes + sizeof(data_net) > mb->mb_buflen )
	    return( 0 );
	data_net =  htonl( data );
	memcpy( mb->mb_current, &data_net, sizeof(data_net) );
	mb->mb_current += sizeof(data_net);
	mb->mb_bytes   += sizeof(data_net);
	return( 1 );
}

int marbuf_unmarshal_int( marbuf_t *mb, int *datap ) {
    uint32_t data_net ;
	if( mb->mb_bytes + sizeof(data_net) > mb->mb_buflen )
	    return( 0 );
	memcpy( &data_net, mb->mb_current, sizeof(data_net) );
	*datap =  ntohl( data_net );
	mb->mb_current += sizeof(data_net);
	mb->mb_bytes   += sizeof(data_net);
	return( 1 );
}

int marbuf_marshal_byte_array( marbuf_t *mb, char data[], int data_len ) {
	if( mb->mb_bytes + data_len > mb->mb_buflen )
	    return( 0 );
	memcpy( mb->mb_current, data, data_len );
	mb->mb_current += data_len;
	mb->mb_bytes   += data_len;
	return( 1 );
}

int marbuf_unmarshal_byte_array( marbuf_t *mb, char data[], int data_len ) {
	if( mb->mb_bytes + data_len > mb->mb_buflen )
	    return( 0 );
	memcpy( data, mb->mb_current, data_len );
	mb->mb_current += data_len;
	mb->mb_bytes   += data_len;
	return( 1 );
}
