El 19/04/2010 12:54, Dale Gallagher escribió:
Hi all

Any reason why I should not be using the maildir plugin, instead of
the qmail-queue plugin, other than for the .qmail flexibility in
delivery? I'd like to improve performance and it seems somewhat of a
waste for qpsmtpd to spool messages and then hand it over to
qmail-queue to spool again....

Because qmail-queue will be able to then forward to qmail-remote for non-local domains (relay) in f(x) of your qmail configuration. Maybe the retries that the qmail queue does are of interest too (consider your DSPAM out of service)... Maybe the additional qmail-local concurrency control is of help too...

I patched qmail-queue plugin to make it more efficient (consume lots less CPU). I sent it to the list some time ago, but after Hanno's suggestions, I didn't follow up. http://markmail.org/message/l3zufmxgbwyblse4#query:+page:1+mid:7rcwalhbupyrjc44+state:results

Attached is the modified plugin considering the body_fh being undef.
I've been using it in production happily for quite some time now without problems.

Any feedback is more than welcome ;) (specially if you find more efficient block sizes... I really couldn't get around to benchmarking that).

Jose Luis Martinez
jlmarti...@capside.com

# -*- perl -*-
=head1 NAME

qmail-queue

=head1 DESCRIPTION

This is the most common plugin used to queue incoming mails.  A
variation of this plugin would maybe forward the mail via smtp.

=head1 CONFIG

It takes one optional parameter, the location of qmail-queue.  This
makes it easy to use a qmail-queue replacement.

  queue/qmail-queue  /var/qmail/bin/another-qmail-queue

If set the environment variable QMAILQUEUE overrides this setting.

=cut

use POSIX ();

sub register {
  my ($self, $qp, @args) = @_;

  if (@args > 0) {
    $self->{_queue_exec} = $args[0];
    $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") if (@args > 
1);
  }
  else {
    $self->{_queue_exec} = ($ENV{QMAIL} || '/var/qmail') . "/bin/qmail-queue";
  }

  $self->{_queue_exec} = $ENV{QMAILQUEUE} if $ENV{QMAILQUEUE};
}

sub hook_queue {
  my ($self, $transaction) = @_;

  # if the message was to big, the body_fh could be undef
  if (not defined $transaction->body_fh) {
      return DECLINED;
  }
  
  # these bits inspired by Peter Samuels "qmail-queue wrapper"
  pipe(MESSAGE_READER, MESSAGE_WRITER) or die("Could not create message pipe");
  pipe(ENVELOPE_READER, ENVELOPE_WRITER) or die("Could not create envelope 
pipe");

  local $SIG{PIPE} = sub { die "SIGPIPE" };
  my $child = fork();

  not defined $child and die("Could not fork");

  if ($child) {
    # Parent
    my $oldfh = select(MESSAGE_WRITER); $| = 1; 
                select(ENVELOPE_WRITER); $| = 1;
    select($oldfh);

    close MESSAGE_READER  or die("close msg reader fault");
    close ENVELOPE_READER or die("close envelope reader fault");
 
    $transaction->header->print(\*MESSAGE_WRITER);
    # called to to force a spool to disk
    $transaction->body_filename;

    $transaction->body_resetpos;
    my $input = $transaction->body_fh;
    my $buf;

    while (read($input, $buf, 8192)) {
        print MESSAGE_WRITER $buf;
    }
    
    close MESSAGE_WRITER;

    my @rcpt = map { "T" . $_->address } $transaction->recipients;
    my $from = "F".($transaction->sender->address|| "" );
    print ENVELOPE_WRITER "$from\0", join("\0",@rcpt), "\0\0"
      or return(DECLINED,"Could not print addresses to queue");
  
    close ENVELOPE_WRITER;
    waitpid($child, 0);
    my $exit_code = $? >> 8;
    $exit_code and return(DECLINED, "Unable to queue message ($exit_code)");

    my $msg_id = $transaction->header->get('Message-Id') || '';
    $msg_id =~ s/[\r\n].*//s;  # don't allow newlines in the Message-Id here
    $msg_id = "<$msg_id>" unless $msg_id =~ /^<.*>$/;  # surround in <>'s
    return (OK, "Queued! " . time . " qp $child $msg_id");
  } elsif (defined $child) {
    # Child
    close MESSAGE_WRITER or exit 1;
    close ENVELOPE_WRITER or exit 2;
    
    # Untaint $self->{_queue_exec}
    my $queue_exec = $self->{_queue_exec};
    if ($queue_exec =~ /^(\/[\/\-\_\.a-z0-9A-Z]*)$/) {
      $queue_exec = $1;
    } else {
      $self->log(LOGERROR, "FATAL ERROR: Unexpected characters in qmail-queue 
plugin argument");
      # This exit is ok as we're exiting a forked child process.
      exit 3;
    }

    # save the original STDIN and STDOUT in case exec() fails below
    open(SAVE_STDIN, "<&STDIN");
    open(SAVE_STDOUT, ">&STDOUT");

    POSIX::dup2(fileno(MESSAGE_READER), 0) or die "Unable to dup 
MESSAGE_READER: $!";
    POSIX::dup2(fileno(ENVELOPE_READER), 1) or die "Unable to dup 
ENVELOPE_READER: $!";

    my $ppid = getppid();
    $self->log(LOGNOTICE, "(for $ppid ) Queuing qp $$ to $queue_exec");

    my $rc = exec $queue_exec;

    # close the pipe
    close(MESSAGE_READER);
    close(MESSAGE_WRITER);
    
    exit 6; # we'll only get here if the exec fails
  }
}

Reply via email to