The link found at the end of this email points to a high-performance qpsmtpd daemon (or use the attached files), which is meant as a replacement of the included qpsmtpd-forkserver.
We call it high-performance since it handles high load significantly better than <qpsmtpd-forkserver> (at least that's what we've experienced). Our tests show that a single server is able to handle more than 1 million messages per day (scanning with ClamAV and spamassassin). Difference in relation to <qpsmtpd-forkserver>: - pre-fork children - reuse child - renice of parent to ensure reaper and re-spawn of children - reload option to graceful reinitialize plugins Usage: -- cd /path/to/qpsmtpd (path to vanilla version of qpsmtpd) wget http://www.softscan.dk/doc/qpsmtpd/qpsmtpd-highperf-daemon.tar.gz tar zxvf qpsmtpd-highperf-daemon.tar.gz patch -p1 < qpsmtpd-prefork.patch -- Continue to install qpsmtpd as you normally would, then copy <qpsmtpd-highperf> to a desired location and start the daemon. See <qpsmtpd-highperf --help> for daemon options. Needed patches: Two modules must be patched to avoid <exit>, as it terminates the child. <Exit> has been replaced with <die>, allowing the daemon to catch finished children and reuse them. Requirements: Patched version of qpsmtpd and Perl module <IPC::Shareable>. Children use the shareable memory to load/save connection information. Considerations: Since children are reused it's important that a child is reset after/before use. It would be greatly appreciated if those with better knowledge of the inner workings of qpsmtpd could comment on the current used solution in TcpServer.pm. We solved the problem by resetting <$self->{_connection}> and <$self->{_transaction}> in the <start_connection> function . Stability: The daemon has been tested without problems on Debian Sarge with the following plugins: -- check_badmailfrom check_badrcptto check_badrcptto_patterns check_loop check_relay check_spamhelo hosts_allow queue/qmail rcpt_ok tls -- Download daemon and patch here: http://www.softscan.co.uk/doc/qpsmtpd/qpsmtpd-highperf-daemon.tar.gz (md5: 413bcd27f1df237d3adb71a3808f7901)
qpsmtpd-highperf
Description: Binary data
diff -urN qpsmtpd/lib/Qpsmtpd/SMTP.pm qpsmtpd-dev/lib/Qpsmtpd/SMTP.pm
--- qpsmtpd/lib/Qpsmtpd/SMTP.pm 2006-02-26 13:22:16.000000000 +0100
+++ qpsmtpd-dev/lib/Qpsmtpd/SMTP.pm 2006-05-24 11:00:07.772226000 +0200
@@ -71,7 +71,11 @@
if (1 or $self->{_commands}->{$cmd} and $self->can($cmd)) {
my ($result) = eval { $self->$cmd(@_) };
- $self->log(LOGERROR, "XX: $@") if $@;
+ if ($@ =~ /^disconnect_tcpserver/) {
+ die "disconnect_tcpserver";
+ } elsif ($@) {
+ $self->log(LOGERROR, "XX: $@") if $@;
+ }
return $result if defined $result;
return $self->fault("command '$cmd' failed unexpectedly");
}
diff -urN qpsmtpd/lib/Qpsmtpd/TcpServer.pm qpsmtpd-dev/lib/Qpsmtpd/TcpServer.pm
--- qpsmtpd/lib/Qpsmtpd/TcpServer.pm 2006-02-26 13:22:16.000000000 +0100
+++ qpsmtpd-dev/lib/Qpsmtpd/TcpServer.pm 2006-05-24 10:59:59.435494000 +0200
@@ -29,6 +29,10 @@
my $now = POSIX::strftime("%H:%M:%S %Y-%m-%d", localtime);
$0 = "$first_0 [$remote_ip : $remote_host : $now]";
+ #reset info
+ $self->{_connection} = Qpsmtpd::Connection->new(); #reset connection
+ $self->{_transaction} = Qpsmtpd::Transaction->new(); #reset transaction
+
$self->SUPER::connection->start(remote_info => $remote_info,
remote_ip => $remote_ip,
remote_host => $remote_host,
@@ -58,14 +62,21 @@
|| 1200; # default value
alarm $timeout;
- while (<STDIN>) {
- alarm 0;
- $_ =~ s/\r?\n$//s; # advanced chomp
- $self->log(LOGDEBUG, "dispatching $_");
- $self->connection->notes('original_string', $_);
- defined $self->dispatch(split / +/, $_)
- or $self->respond(502, "command unrecognized: '$_'");
- alarm $timeout;
+ eval {
+ while (<STDIN>) {
+ alarm 0;
+ $_ =~ s/\r?\n$//s; # advanced chomp
+ $self->log(LOGDEBUG, "dispatching $_");
+ $self->connection->notes('original_string', $_);
+ defined $self->dispatch(split / +/, $_)
+ or $self->respond(502, "command unrecognized: '$_'");
+ alarm $timeout;
+ }
+ };
+ if ($@ =~ /^disconnect_tcpserver/) {
+ die "disconnect_tcpserver";
+ } else {
+ die "died while reading from STDIN (probably broken sender) - $@";
}
alarm(0);
}
@@ -85,7 +96,7 @@
$self->log(LOGDEBUG,"click, disconnecting");
$self->SUPER::disconnect(@_);
$self->run_hooks("post-connection");
- exit;
+ die "disconnect_tcpserver";
}
1;
