Support a flag for how many connections to accept in the accept loop
git-svn-id: https://svn.perl.org/qpsmtpd/branches/high_perf@435 958fd67b-6ff1-0310-b445-bb7760255be9
This commit is contained in:
parent
b323b33f60
commit
6ed494275b
23
qpsmtpd
23
qpsmtpd
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl
|
||||||
|
|
||||||
use lib "./lib";
|
use lib "./lib";
|
||||||
BEGIN {
|
BEGIN {
|
||||||
@ -44,6 +44,7 @@ my $MAXCONN = 15; # max simultaneous connections
|
|||||||
my $USER = 'smtpd'; # user to suid to
|
my $USER = 'smtpd'; # user to suid to
|
||||||
my $MAXCONNIP = 5; # max simultaneous connections from one IP
|
my $MAXCONNIP = 5; # max simultaneous connections from one IP
|
||||||
my $PAUSED = 0;
|
my $PAUSED = 0;
|
||||||
|
my $NUMACCEPT = 20;
|
||||||
|
|
||||||
sub help {
|
sub help {
|
||||||
print <<EOT;
|
print <<EOT;
|
||||||
@ -58,6 +59,7 @@ Options:
|
|||||||
-m, --max-from-ip M : limit connections from a single IP; default 5
|
-m, --max-from-ip M : limit connections from a single IP; default 5
|
||||||
-f, --forkmode : fork a child for each connection
|
-f, --forkmode : fork a child for each connection
|
||||||
-j, --procs J : spawn J processes; default 1
|
-j, --procs J : spawn J processes; default 1
|
||||||
|
-a, --accept K : accept up to K conns per loop; default 20
|
||||||
-h, --help : this page
|
-h, --help : this page
|
||||||
|
|
||||||
NB: -f and -j are mutually exclusive. If -f flag is not used the server uses
|
NB: -f and -j are mutually exclusive. If -f flag is not used the server uses
|
||||||
@ -77,6 +79,7 @@ GetOptions(
|
|||||||
'c|limit-connections=i' => \$MAXCONN,
|
'c|limit-connections=i' => \$MAXCONN,
|
||||||
'm|max-from-ip=i' => \$MAXCONNIP,
|
'm|max-from-ip=i' => \$MAXCONNIP,
|
||||||
'u|user=s' => \$USER,
|
'u|user=s' => \$USER,
|
||||||
|
'a|accept=i' => \$NUMACCEPT,
|
||||||
'h|help' => \&help,
|
'h|help' => \&help,
|
||||||
) || help();
|
) || help();
|
||||||
|
|
||||||
@ -86,6 +89,7 @@ if ($LOCALADDR =~ /^([\d\w\-.]+)$/) { $LOCALADDR = $1 } else { &help }
|
|||||||
if ($USER =~ /^([\w\-]+)$/) { $USER = $1 } else { &help }
|
if ($USER =~ /^([\w\-]+)$/) { $USER = $1 } else { &help }
|
||||||
if ($MAXCONN =~ /^(\d+)$/) { $MAXCONN = $1 } else { &help }
|
if ($MAXCONN =~ /^(\d+)$/) { $MAXCONN = $1 } else { &help }
|
||||||
if ($PROCS =~ /^(\d+)$/) { $PROCS = $1 } else { &help }
|
if ($PROCS =~ /^(\d+)$/) { $PROCS = $1 } else { &help }
|
||||||
|
if ($NUMACCEPT =~ /^(\d+)$/) { $NUMACCEPT = $1 } else { &help }
|
||||||
|
|
||||||
$PROCS = 1 if $LineMode;
|
$PROCS = 1 if $LineMode;
|
||||||
# This is a bit of a hack, but we get to approximate MAXCONN stuff when we
|
# This is a bit of a hack, but we get to approximate MAXCONN stuff when we
|
||||||
@ -300,9 +304,7 @@ sub accept_handler {
|
|||||||
$running = scalar keys %$descriptors;
|
$running = scalar keys %$descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $max = $MAXCONNIP ? 100 : 1000;
|
for (1 .. $NUMACCEPT) {
|
||||||
|
|
||||||
for (1 .. $max) {
|
|
||||||
if ($running >= $MAXCONN) {
|
if ($running >= $MAXCONN) {
|
||||||
::log(LOGINFO,"Too many connections: $running >= $MAXCONN.");
|
::log(LOGINFO,"Too many connections: $running >= $MAXCONN.");
|
||||||
return;
|
return;
|
||||||
@ -312,6 +314,8 @@ sub accept_handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Errno qw(EAGAIN EWOULDBLOCK);
|
||||||
|
|
||||||
sub _accept_handler {
|
sub _accept_handler {
|
||||||
my $running = shift;
|
my $running = shift;
|
||||||
|
|
||||||
@ -319,6 +323,13 @@ sub _accept_handler {
|
|||||||
if (!$csock) {
|
if (!$csock) {
|
||||||
# warn("accept() failed: $!");
|
# warn("accept() failed: $!");
|
||||||
return;
|
return;
|
||||||
|
if ($! == EAGAIN || $! == EWOULDBLOCK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn("accept() failed: $!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
binmode($csock, ':raw');
|
binmode($csock, ':raw');
|
||||||
|
|
||||||
@ -331,6 +342,7 @@ sub _accept_handler {
|
|||||||
if (!$LineMode) {
|
if (!$LineMode) {
|
||||||
# multiplex mode
|
# multiplex mode
|
||||||
my $client = Qpsmtpd::PollServer->new($csock);
|
my $client = Qpsmtpd::PollServer->new($csock);
|
||||||
|
my $rem_ip = $client->peer_ip_string;
|
||||||
|
|
||||||
if ($PAUSED) {
|
if ($PAUSED) {
|
||||||
$client->write("451 Sorry, this server is currently paused\r\n");
|
$client->write("451 Sorry, this server is currently paused\r\n");
|
||||||
@ -340,7 +352,6 @@ sub _accept_handler {
|
|||||||
|
|
||||||
if ($MAXCONNIP) {
|
if ($MAXCONNIP) {
|
||||||
my $num_conn = 1; # seed with current value
|
my $num_conn = 1; # seed with current value
|
||||||
my $rem_ip = $client->peer_ip_string;
|
|
||||||
|
|
||||||
# If we for-loop directly over values %childstatus, a SIGCHLD
|
# If we for-loop directly over values %childstatus, a SIGCHLD
|
||||||
# can call REAPER and slip $rip out from under us. Causes
|
# can call REAPER and slip $rip out from under us. Causes
|
||||||
@ -426,7 +437,7 @@ sub _accept_handler {
|
|||||||
sub log {
|
sub log {
|
||||||
my ($level,$message) = @_;
|
my ($level,$message) = @_;
|
||||||
# $level not used yet. this is reimplemented from elsewhere anyway
|
# $level not used yet. this is reimplemented from elsewhere anyway
|
||||||
warn("$$ $message\n");
|
warn("$$ fd:? $message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
sub pause {
|
sub pause {
|
||||||
|
Loading…
Reference in New Issue
Block a user