Data serialization

I recently needed a reliable way to pass binary information between two processes through an IPC mechanism. One of the programs (P1) consumes data from a DB2 database which is kinda complex to work with when the code is written in C, so, I ended up looking for a way to remove this (unnecessary) complexity by writing a Perl (P2) script much more user friendly when comes to working with database connections.

The query was as simple as

SELECT int1, long1, chars FROM table

which means that a simple C structure would be enough to map the entire selected fields

typedef struct rem_data
{
        int i;
	long l;
	char sz[10];
} rem_data_t;

P1 works as a TCP/IP server listening at port 7007. P2 connects to that endpoint, executes the query and packs the resulting row as a binary data packet to finally send it through the opened socket. P1 deserializes the bytes received to build the structure rem_data.

P1 is possibly long but self-explanatory :).

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct rem_data
{
	int i;
	long l;
	char sz[10];
} rem_data_t;

typedef unsigned int _uint;
typedef void * (*dflt_func_ptr_t) (void *);

void *deserializer (void *param);
static void *listener(void *param);
pthread_t *ip_start_listener(_uint port, void * (*callback) (void *));

int main(int argc, char **argv)
{
      ip_start_listener(7007, deserializer);

      /*
       * OK, it's busy wait :D
       */ 
      for(;;);
}

void *deserializer (void *param)
{
	rem_data_t data;
	int offset		= 0;
	char *rdata		= (char *) param;

	memcpy(&data.i, &rdata[offset], sizeof(data.i));
	offset			+= sizeof(data.i);

	memcpy(&data.l, &rdata[offset], sizeof(data.l));
	offset			+= sizeof(data.l);

	memcpy(&data.sz, &rdata[offset], sizeof(data.sz));

	printf("data: i %dn", data.i);
	printf("data: l %dn", data.l);
	printf("data: sz %sn", data.sz);
}

pthread_t *ip_start_listener(_uint port, dflt_func_ptr_t callback)
{
	int sock_fd, opt = 1;
	struct sockaddr_in server;
	pthread_t *listener_thread	= NULL;

	if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
//		LOG(L_ERROR, "%s | socket(): %s", __FUNCTION__, strerror(errno));
		return NULL;
	}

	setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));

	server.sin_family 	= AF_INET;
	server.sin_port 	= htons(port);
	server.sin_addr.s_addr 	= INADDR_ANY;

	bzero(&(server.sin_zero), 8);

	if(bind(sock_fd, (struct sockaddr*)&server, sizeof(struct sockaddr)) == -1)
	{
//		LOG(L_ERROR, "%s | bind(): %sn", __FUNCTION__, strerror(errno));
		return NULL;
	}

	if(listen(sock_fd, 1000) == -1)
	{
//		LOG(L_ERROR, "ip_start_listener.listen(): %sn", strerror(errno));
		return NULL;
	}

	listener_thread		= malloc(sizeof(pthread_t));

	if (pthread_create(listener_thread, NULL, listener, (void *) ( void*[] ) { (void*) &sock_fd, (void*) callback } ) != 0)
	{
//		LOG(L_ERROR, "%s | pthread_create(): %sn", __FUNCTION__, strerror(errno));
		return NULL;
	}

	return listener_thread;
}

static void *listener(void *param)
{
	struct sockaddr_in client;
	_uint sin_size, *params		=  param;
	int client_fd, *sock_fd 	= (int *) params[0];
	dflt_func_ptr_t callback	= (dflt_func_ptr_t) params[1];

	/*
	 *  no buffering for standard output
	 */
	setbuf(stdout, NULL);
	sin_size = sizeof(struct sockaddr_in);

	for(;;)
	{
		char buffer[1024];

		if ((client_fd = accept(*sock_fd, (struct sockaddr *) &client, &sin_size)) == -1)
		{
//		    LOG(L_ERROR, "%s | accept(): %sn", __FUNCTION__, strerror(errno));
		    continue;
		}

//		LOG(L_DEBUG, "Connection from %sn",  inet_ntoa(client.sin_addr));

		read(client_fd, buffer, sizeof(buffer));

		callback(buffer);

		close(client_fd);
	}

	return NULL;
}

Compile it with

$  gcc server.c -o server -lpthread

P2 is more than simple. In case you don’t know the pack() function, here is very well explained.

#!/usr/bin/perl

use warnings;
use strict;

use IO::Socket;


my $sock 	= IO::Socket::INET->new('localhost:7007');

# Assume that the data retrieving logic is implemented here
$sock->write(pack("i l Z11", 111, 999,'hola'));

$sock->close();

And then, we just run it.

$ ./server &
$ perl pack.pl

And P1’s output should be

data: i 111
data: l 999
data: sz hola

Garbage generator

When your teacher asks you to write a script that randomly mixes grammatical parts of a sentence because you didn’t did your homework is what causes this kind of post.

Actually there were more restrictions. I had to do it in less than 10 minutes, the resulting sentence needed to be understandable despite the possible genre errors and finally, the sentence should be generated in Spanish.

The script is made in Perl. It was easy to build and luckily took me less than 10 minutes to entirely write both the code and the feeders (the files with the words to build the sentence).

[perl]
#!/usr/bin/perl

use warnings;
use strict;

sub main()
{
my @articles = open_file($ARGV[0]);
my @subjects = open_file($ARGV[1]);
my @verbs = open_file($ARGV[2]);
my @complements = open_file($ARGV[3]);

my %rules = ( ‘a’ => @articles,
‘s’ => @subjects,
‘v’ => @verbs,
‘c’ => @complements);

my @expr = split(/+/, $ARGV[4]);

for my $token ( @expr )
{
my $index = int(rand(scalar(@{$rules{$token}})));

my $word = @{$rules{$token}}[$index];
$word =~ s/n+/ /g;
print $word;
}

print “n”;

}

sub open_file($)
{
my $file = shift;

open(FILE, “< $file") || die "Error: $!n"; return ;
}

&main();
[/perl]

The program receives 5 parameters from command line: the articles file, the subjects file, the verbs file, the complements file and the expression which determines how to build the sentences combining the words.

[bash]

$ perl random-sentence.pl articles subjects verbs complements “a+s+v+c”

[/bash]

The above call produces mostly nonsense and funny sentences like:

– el edificio duerme todo al pedo
– un alumno estudia como la mierda
– la puerta rie
– las perro habla todo al pedo
– una profesor come cualquier cosa

It was a funny thing to do. I don’t know if the script worth a post in my blog but here it is and I laughed a lot 😀

New domain, new stuff to write, new language

My mother language is Spanish but everything related to my career as a computer engineer is written in English so there is an obvious need to learn to speak English and, this is me writing my very first post completely in English.

Eventually I’ll become more fluent and I will stop making grammatical errors but until that happens, I ask you to be patient because I’m pretty sure the main idea of what I’m trying to say will be very understandable, like this paragraph for instance 😀

I’m working to upload my projects to github. Those projects are going to get published here. The idea is to share what I learned all these years of playing around with computers and software.

Well, that’s it 🙂