fun with microperl

clkao on 2006-04-17T22:00:51

I got dragged into an art project for helping out firefighting messaging between some small mipsel devices running linux.

The distribution comes with microperl in its package system, however it wasn't built with select() by default, which makes it pretty much useless for writing network applications. So I was hoping to cross-compile standard perl and modules to mips, but it seemed really painful. I gave up and ended up just enabling HAS_SELECT for the cross-compiled microperl.

Now I have to use Socket.pm to actually do the networking bit. It turned out lots of crucial bits are written in xs, so I reimplemented them in pure perl. (Ya, I know it's bad to pack platform-dependent structure manually)

So I have a tiny application controlling a local led display and buttons IO device, as well as broadcasting and processing events over network, all in a few hours after I get the microperl and socket working!

Anyway, it's quite fun hacking and I am looking forward to the show itself!


what fun -- embedded Perl!

n1vux on 2006-04-24T16:58:53

That sounds like quite a project. Do let us know how it turns out, links to reviews, after-reports, etc.

Using MicroPerl for embedded is a great idea. Microperl, not just for bootstrapping anymore.

microperl & sockets

yoleg on 2007-03-07T07:56:10

Hello clkao,

I am also interested in using Microperl with some networking functions. How did you port the functionalities from Socket.pm to Perl? Did you write them in C? from what I read in your post, you seem to have rewritten in Perl... When you write that it's not such a good thing to do it from perl because it's platform-dependent, does this refer to the CPU type or to the OS itself.

My goal is to add some local UNIX socket functionality (sockaddr_un) inside Microperl to be able to accept incoming connections from this socket from a C program. This allows me to send commands via the socket to the main Perl program, that is running as a userspace daemon (rather than spending quite some time to load the Perl interpreter each time, especially because I'm on a embedded platform). Do you still have the code you wrote in early 2006, so that I can try to base my work on this? That would be a great starting point!

Thanks...

Re:microperl & sockets

yoleg on 2007-03-09T16:22:09

Hello,

I finally could make it work by using the following code (that allows my code to be rather platform-independant, if I fill in properly the first bunch of variables):

my $PF_UNIX=1;
my $AF_UNIX=$PF_UNIX;
my $SOCK_STREAM=2;   # 1 for ix86, 2 for MIPS
my $SOMAXCONN=128;
my $sun_path_SIZE=2;
my $sun_family_SIZE=108;



#my $uaddr = sockaddr_un($SOCKFILE);   # Create a UNIX socket (local)... not used because this requires Socket.pm... instead, we will pack the sockaddr_un structure manually as done below


sub is_little_endian {
   return (unpack('c', pack('s', 1)));
}

my $sun_path_pack = "I";
($sun_path_SIZE == 1) && ($sun_path_pack = "C");
($sun_path_SIZE == 2) && ($sun_path_pack = (is_little_endian() ? "v" : "n"));
($sun_path_SIZE == 4) && ($sun_path_pack = (is_little_endian() ? "V" : "N"));

# This contains $AF_UNIX (it is the .sun_family field of sockaddr_un) + .sun_path field of sockaddr_un
$uaddr = pack($sun_path_pack . " a" . $sun_family_SIZE, $AF_UNIX, $SOCKFILE);



My $uaddr then contains the right struct to create the socket...

$SOMAXCONN is used later to avoid depending on Socket.pm only for SOMAXCONN
The rest of the variables:
$PF_UNIX=1;
$SOCK_STREAM=2;
$SOMAXCONN=128;
...are taken from the #defines of my cross-compiler, and:
$sun_path_SIZE=2;
$sun_family_SIZE=108;
...are extracted from the size of the fields inside sockaddr_un.

To automate the discovery of the above variables, the following C file can be cross-compiled to dump the right variables on the target environment (a MIPS for me):

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>

#ifndef UNIX_PATH_LEN
#define UNIX_PATH_LEN (sizeof(((struct sockaddr_un *) 0)->sun_path))
#endif

int main (int argc, char **argv) {
   
   struct sockaddr_un *sample_un_sock;
   
#ifdef SOCK_STREAM
   printf("SOCK_STREAM=%u\n", SOCK_STREAM);
#endif
#ifdef SOMAXCONN
   printf("SOMAXCONN=%u\n", SOMAXCONN);
#endif
#ifdef PF_UNIX
   printf("PF_UNIX=%u\n", PF_UNIX);
#endif
   printf("OFFSET for .sun_path in sockaddr_un=%u\n", (void *)&(sample_un_sock->sun_path) - (void *)sample_un_sock);
   printf("SIZE for .sun_path in sockaddr_un=%u\n", UNIX_PATH_LEN);
   printf("OFFSET for .sun_family in sockaddr_un=%u\n", (void *)&(sample_un_sock->sun_family) - (void *)sample_un_sock);
   printf("SIZE for .sun_family in sockaddr_un=%u\n", sizeof(sample_un_sock->sun_family));
   return 0;
}

Also, for cross-compiling Perl (using miniperl instead of microperl), there is a nice text describing a cross-Configure (using ssh and scp for example), to generate a config.sh matching with a remote target (for further cross-compilation).
This can be found in the Cross-compilation section of the ./INSTALL text file (in perl-5.8.8)