Hello!

I would like to try it again. Two month ago, when 0.40 was released i also tried to find someone who is interested in resolving bugs from the qpsmtpd-prefork - but nobody cares. So i hope this time somebody cares about it. Cause qpsmtpd-prefork is not usable at all on high load / many connections / second without my patches. Our company has about 500 servers using qpsmtpd-prefork serving more that 50 million connections / day.

So please please somebody read it and let us discuss about it. I'm really interested, that qpsmtpd-prefork is getting stable for all.

So here are some problems and the solutions ( the patches may not apply cleanly to the actual 0.40 version):


1.) You get some errors with the auth mechanism if an old process has used auth the value seems not to be destroyed. So add "delete($qpsmtpd->{_auth});"
 in function new_child before my ($client, $iinfo) = $d->accept().
otherwise some other hosts are authorized even if they don't authourize at all.

2.) After some million connections i was getting errors with the POSIX::dup2(fileno($client), 0) variant for setting the connection to STDIN and STDOUT (handle errors lost connections etc.). So i changed it so something more stable (really stable - tested for about 2 month). Also important was that sometimes in the old Handle was a STRING from the last SMTP Connection even in the new connection and so check_earlytalker blocks all. So we have to close the old handle before opening a new one.

Here is the patch:
-
-        # set STDIN/STDOUT and autoflush
-        POSIX::dup2(fileno($client), 0)
-          || die "unable to duplicate filehandle to STDIN - $!";
-        POSIX::dup2(fileno($client), 1)
-          || die "unable to duplicate filehandle to STDOUT - $!";
-        $| = 1;
+ or die "failed to create new object - $!"; # wait here until client connects
+
+       next if (!$iinfo or !$client);
+
+ info("connect from: " . ((defined $client->peerhost) ? $client->peerhost : "unknown") . ":" . + ((defined $client->peerport) ? $client->peerport : "unknown"));
+
+       close(STDIN);
+ open(STDIN, "+<&".fileno($client)) || ::log(LOGERROR, "dup2 failed of client->STDIN");
+       close(STDOUT);
+ open(STDOUT, "+>&".fileno($client)) || ::log(LOGERROR, "dup2 failed of client->STDOUT");
+        select(STDOUT); $|=1;


3.) If you would like to run more than one qpsmtpd-prefork on a single machine you get a problem with the shared memory so my patch:
     # setup shared memory
-    $chld_shmem = shmem("qpsmtpd", 1);
+    $chld_shmem = shmem($d_port."qpsmtpd", 1);
     untie $chld_shmem;

@@ -470,7 +485,7 @@ sub shmem_opt {

     my ($chld_shmem, $chld_busy);
     eval {
- $chld_shmem = &shmem("qpsmtpd", 0); #connect to shared memory hash + $chld_shmem = &shmem($d_port."qpsmtpd", 0); #connect to shared memory hash

         if (tied %{$chld_shmem}) {
             # perform options


4.) The only last problem i have is, that if i don't exit the child if it has done a TLS connection a second or third TLS connection mostly fail.

So my dirty hack at the moment is quitting the child if it has done an tld connection - but be careful it does not check if you use really use qpsmtpd-prefork.

Patch for plugins/tls
Add:
sub hook_quit {
  my $self = shift;

  if ($self->connection->notes('tls_enabled')) {
        $self->log(LOGERROR, "exit cause of enables tls");
        exit;
  }

  return DECLINED;
}


5.) I liked the idea of renicing but I think the important thing is, that the master / parent process hold its nice value and only the childs get a new one. So new connections will be handled fast and only the child connections are getting slower (if the cpu is at high usage). So we will not change the nice level in the parent and only in the child this is already done in "sub new_child {)".

So my patch:
@@ -169,16 +173,17 @@ sub run {
             "$d_addr, port: $d_port (user: $user [$<])");

     # reset priority
-    my $old_nice = getpriority(0, 0);
-    my $new_nice = $old_nice - $re_nice;
-    if ($new_nice < 20 && $new_nice > -20) {
-        setpriority(0, 0, $1) if ($new_nice =~ /(\-?\d+)/);
-        info("parent daemon nice level: $1");
-    }
-    else {
-        die "FATAL: new nice level: $new_nice is not between -19 and 19 "
-          . "(old level = $old_nice, renice value = $re_nice)";
-    }
+    # we do not want to change the nice level of the parent
+    #my $old_nice = getpriority(0, 0);
+    #my $new_nice = $old_nice - $re_nice;
+    #if ($new_nice < 20 && $new_nice > -20) {
+    #    setpriority(0, 0, $1) if ($new_nice =~ /(\-?\d+)/);
+    #    info("parent daemon nice level: $1");
+    #}
+    #else {
+    #    die "FATAL: new nice level: $new_nice is not between -19 and 19 "
+    #      . "(old level = $old_nice, renice value = $re_nice)";
+    #}

     if ($user) {
         # change UUID/UGID



Stefan

Reply via email to