From acd15ca11a510d3c5cb31f25e173de86fa570300 Mon Sep 17 00:00:00 2001
From: Guilhem Moulin <guilhem@fripost.org>
Date: Thu, 1 Jun 2017 10:08:16 +0200
Subject: postfix-sender-login: pre-fork 2 servers.

On Linux perl's allow multiple children to block in a call to accept(2)
so we don't need to place a lock around the call.
---
 .../files/usr/local/bin/postfix-sender-login.pl    | 69 +++++++++++++---------
 1 file changed, 41 insertions(+), 28 deletions(-)

diff --git a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
index 58cbf9d..987482e 100755
--- a/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
+++ b/roles/MSA/files/usr/local/bin/postfix-sender-login.pl
@@ -34,8 +34,14 @@ use Authen::SASL ();
 $ENV{PATH} = join ':', qw{/usr/bin /bin};
 delete @ENV{qw/IFS CDPATH ENV BASH_ENV/};
 
-# returned for forbidden envelope sender addresses
-my $POSTMASTER = 'postmaster@fripost.org';
+my $nProc      = 2;                        # number of pre-forked servers
+my $POSTMASTER = 'postmaster@fripost.org'; # returned for forbidden envelope sender addresses
+
+my $BASEDN  = 'ou=virtual,dc=fripost,dc=org';
+my $BUFSIZE = 65536; # try to read that many bytes at the time
+my $LDAPI   = 'ldapi://%2Fvar%2Fspool%2Fpostfix-msa%2Fprivate%2Fldapi/';
+sub server();
+
 
 # fdopen(3) the file descriptor FD
 die "This service must be socket-activated.\n"
@@ -43,36 +49,43 @@ die "This service must be socket-activated.\n"
        and defined $ENV{LISTEN_FDS} and $ENV{LISTEN_FDS} == 1;
 open my $S, '+<&=', 3 or die "fdopen: $!";
 
-my $BASEDN  = 'ou=virtual,dc=fripost,dc=org';
-my $BUFSIZE = 65536; # try to read that many bytes at the time
-my $LDAPI   = 'ldapi://%2Fvar%2Fspool%2Fpostfix-msa%2Fprivate%2Fldapi/';
-sub process_request($);
-
-while(1) {
-    accept(my $conn, $S) or do {
-        # try again if accept(2) was interrupted by a signal
-        next if $! == EINTR;
-        die "accept: $!";
-    };
-    my $reply = process_request($conn);
-
-    # encode the reply as a netstring and send it back
-    # https://cr.yp.to/proto/netstrings.txt 
-    $reply = length($reply).':'.$reply.',';
-    my $len = length($reply);
-
-    for (my $i = 0; $i < $len;) {
-        my $n = syswrite($conn, $reply, $len-$i, $i) // do {
-            warn "Can't write: $!";
-            last;
-        };
-        $i += $n;
+for (my $i = 0; $i < $nProc-1; $i++) {
+    my $pid = fork() // die "fork: $!";
+    unless ($pid) {
+        server(); # child, never return
+        exit;
     }
-    close $conn or warn "Can't close: $!";
 }
+server();
+
 
 #############################################################################
 
+sub server() {
+    while(1) {
+        accept(my $conn, $S) or do {
+            # try again if accept(2) was interrupted by a signal
+            next if $! == EINTR;
+            die "accept: $!";
+        };
+        my $reply = process_request($conn);
+
+        # encode the reply as a netstring and send it back
+        # https://cr.yp.to/proto/netstrings.txt
+        $reply = length($reply).':'.$reply.',';
+        my $len = length($reply);
+
+        for (my $i = 0; $i < $len;) {
+            my $n = syswrite($conn, $reply, $len-$i, $i) // do {
+                warn "Can't write: $!";
+                last;
+            };
+            $i += $n;
+        }
+        close $conn or warn "Can't close: $!";
+    }
+}
+
 sub process_request($) {
     my $conn = shift;
     my ($buf, $offset) = (undef, 0);
@@ -125,7 +138,7 @@ sub lookup_sender($$$) {
     my $entry = $mesg->pop_entry() // return "NOTFOUND "; # not a domain we know
     return "TEMP LDAP error: multiple entry founds" if defined $mesg->pop_entry(); # sanity check
 
-    # domain postmasters are allowed to use any sender address 
+    # domain postmasters are allowed to use any sender address
     my @logins = $entry->get_value('fripostPostmaster', asref => 0);
     my @owners = $entry->get_value('fripostOwner', asref => 0);
 
-- 
cgit v1.2.3