Perl embedding example

Since there was no progress from my last experiment, writing a rudimentary program without any WSF/C code seemed like a logical next step. For those of you who don’t know what I tried to do, here’s a brief explanation. I want to let other people provide Web services in Perl. My objective is to enable people to just copy their Perl scripts to, say, a folder and it’ll automatically become a Web service. Let me explain that with an example. Say you have the following Perl script,

#!/usr/bin/env perl
 
sub getRandomNumber {
    return 4;
}

I’m going to assuming you have configured your web server to execute Perl scripts ending with .pl via ModPerl for a directory called perl. You copy the file and it’s accessible from http://localhost/perl/random.pl. And it’s a web service now. So you can send an XML payload like,

<getRandomNumber />

And get back something like,

<number>4</number>

Since I’m using WSF/C as the underlying Web service engine and it provides various other facilities like WS-Security, WS-ReliableMessaging etc… at blazing speed, I wanna use it.

Here’s a simplified graphical version of the story,

1. Request comes to rand.pl via ModPerl and it gets executed.
2. rand.pl then calls some methods in Service.pm module which in turn calls to some C functions.
3. From one of those C functions we need to call a Perl function residing in the script the request came into.

If you’re wondering how the graphic relates to the story of copying your Perl script and making it a service (’cos there’s a Service.pm in the picture), please note that I’ve not yet figured out every detail in the system :-)

Perl is segfaulting at all the bizzare places when this is executed. When things get this bad it’s time to write a very simple application that does the same thing without any WSF/C code. Here’s how I did it.

I started by creating a new Perl extension in C.

$ h2xs -A -n ICanHaz

This’ll create the skeleton and all I have to do is edit the .xs file and put my code there. Here’s my ICanHaz.xs file,

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <string.h>
 
#include "ppport.h"
 
static	PerlInterpreter *my_perl;
 
void cheeseburger( void )
{
    char *embedding[] = {"/usr/local/apache2/perl/exec-this.pl"};
 
    my_perl = perl_alloc();
    perl_construct(my_perl);
    PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
    perl_parse(my_perl, NULL, 1, embedding, NULL);
    perl_run(my_perl);
    perl_destruct(my_perl);
    perl_free(my_perl);
    PERL_SYS_TERM();
}
 
MODULE = ICanHaz		PACKAGE = ICanHaz		
 
void
cheeseburger()

Now you have to edit Makefile.PL and give the output of, perl -MExtUtils::Embed -e ccopts -e ldopts to the compiler flags. After that you can compile and install the module. Here’s what’s inside exec-this.pl,

sub keele_teh_urth {
    print "oh noez. i iz gud kitteh";
}

Just a simple function. Then I wrote another Perl script to invoke the method in my C extension. Here’s the program,

#!/usr/local/bin/perl
 
use ICanHaz;
 
ICanHaz::cheeseburger();
 
print "Content-type: text/html\n\n";
print "dis segfaults, srsly.\n";

Executing this file via ModPerl results in a segmentation fault. As you can see even the simplest case of embedding will not execute through ModPerl. Switched to CGI and got the same results. Possible alternatives to try is 1) move all the embedding stuff to it’s own executable, when you need to call the Perl function from C do a fork followed by exec, pass the payload as a parameter, store the result in a shared memory and once done read from it (this .. um .. a bit ugly to say the least). Second alternative is to use PPI. I haven’t looked into PPI yet so don’t know for sure whether it’s possible.

Comments (1)