Back to Top

Monday, November 27, 2006

Fixing Open Source

Before you all jump over me: I won't be talking here about a silver bullet which would take the open source movement in the right direction, ensure its competitiveness or something like that. What I'll talk about is the joy that you can have by fixing open source scripting libraries.

To be specific: in one of my Perl scripts I wanted to send mail. The problem was that I didn't have access to a SMTP server on that machine. After toying around with the example code of Net::SMTP::Server I concluded that it didn't work and went off to find some lightweight solution. One of the more promising solutions was RunMail, however I was still uncomfortable about running binary code of unknown origin on the server. As a results I fired up telnet and the Perl debugger and stepped into the library source code. There I found the following part:

    # Loop through the recipient list.
    foreach $target (@{$self->{TO}}) {
 my $rr;
 my $domain = /@(.*)/;
 my $res = new Net::DNS::Resolver;
 my @mx = mx($res, defined($1) ? $1 : hostdomain);

I promptly replaced the line so that $1 would be set, and voila, it works!

    # Loop through the recipient list.
    foreach $target (@{$self->{TO}}) {
 my $rr;
 $target =~ /@(.*)/;
 my $res = new Net::DNS::Resolver;
 my @mx = mx($res, defined($1) ? $1 : hostdomain);

Now, if this would have been a binary library, I would had to: (a) get the source code (b) set up a build environment (c) compile from source (to get the debugging symbols) and (c) figure out how to integrate the debugging version with the release version such that I get a breakpoint where I need to and I get the debugging symbols. And I didn't even speak about the rich introspection capabilities of scripting language debuggers!

Update: the actual problem was in Net::SMTP::Server::Relay, not in Net::SMTP::Server.

Update: below you can see the full code of the module (since it is rather short). The part shown with bold is the one which needed to be changed:

package Net::SMTP::Server::Relay;

require 5.001;

use strict;
use vars qw($VERSION @ISA @EXPORT);

require Exporter;
require AutoLoader;
use Carp;
use Net::DNS;
use Net::Domain qw(hostdomain);
use Net::SMTP;

@ISA = qw(Exporter AutoLoader);
@EXPORT = qw();

$VERSION = '1.1';

sub _relay {
    my $self = shift;
    my $target;
    
    # Loop through the recipient list.
    foreach $target (@{$self->{TO}}) {
 my $rr;
 $target =~ /@(.*)/;
 my $res = new Net::DNS::Resolver;
 my @mx = mx($res, defined($1) ? $1 : hostdomain);
 
 next unless defined(@mx);
 
 # Loop through the MXs.
 foreach $rr (@mx) {
     my $client = new Net::SMTP($rr->exchange) || next;
     
     $client->mail($self->{FROM});
     $client->to($target);
     $client->data($self->{MSG});
     $client->quit;
     
     last;
 }
    }
}

1 comment:

  1. Anonymous7:50 PM

    Could you post a generic version of your working script?

    ReplyDelete