New id scheme: Start with a unique id for the Qpsmtpd::SMTP object,

then derive ids for connections and transactions from that via
simple counters.


git-svn-id: https://svn.perl.org/qpsmtpd/trunk@785 958fd67b-6ff1-0310-b445-bb7760255be9
This commit is contained in:
Peter J. Holzer 2007-09-02 10:50:23 +00:00
parent 85cd1aae2b
commit af82701fff
4 changed files with 35 additions and 43 deletions

View File

@ -1,9 +1,6 @@
package Qpsmtpd::Connection; package Qpsmtpd::Connection;
use strict; use strict;
use Sys::Hostname;
use Time::HiRes qw(gettimeofday);
# All of these parameters depend only on the physical connection, # All of these parameters depend only on the physical connection,
# i.e. not on anything sent from the remote machine. Hence, they # i.e. not on anything sent from the remote machine. Hence, they
# are an appropriate set to use for either start() or clone(). Do # are an appropriate set to use for either start() or clone(). Do
@ -18,27 +15,7 @@ my @parameters = qw(
relay_client relay_client
); );
my $SALT_HOST = crypt(hostname, chr(65+rand(57)).chr(65+rand(57)));
$SALT_HOST =~ tr/A-Za-z0-9//cd;
sub new_id {
my $self = shift;
# Generate unique id
# use gettimeofday for microsec precision
# add in rand() in case gettimeofday clock is slow (e.g. bsd?)
# add in $$ in case srand is set per process
my ($start, $mstart) = gettimeofday();
my $id = sprintf("%d.%06d.%s.%d.%d",
$start,
$mstart,
$SALT_HOST,
rand(10000),
$$,
);
$self->{_id} = $id;
}
sub new { sub new {
my $proto = shift; my $proto = shift;
my $class = ref($proto) || $proto; my $class = ref($proto) || $proto;
@ -61,10 +38,16 @@ sub start {
sub id { sub id {
my $self = shift; my $self = shift;
$self->new_id unless $self->{_id}; $self->{_id} = shift if @_;
$self->{_id}; $self->{_id};
} }
sub inc_id {
my $self = shift;
my ($qp_id, $count) = $self->{_id} =~ m/(.+)\.(\d+)/;
$self->{_id} = $qp_id . "." . ++$count;
}
sub clone { sub clone {
my $self = shift; my $self = shift;
my $new = $self->new(); my $new = $self->new();

View File

@ -19,6 +19,8 @@ use Mail::Header ();
#use Data::Dumper; #use Data::Dumper;
use POSIX qw(strftime); use POSIX qw(strftime);
use Net::DNS; use Net::DNS;
use Time::HiRes qw(gettimeofday);
use Sys::Hostname;
# this is only good for forkserver # this is only good for forkserver
# can't set these here, cause forkserver resets them # can't set these here, cause forkserver resets them
@ -37,10 +39,20 @@ sub new {
my (%commands); @commands{@commands} = ('') x @commands; my (%commands); @commands{@commands} = ('') x @commands;
# this list of valid commands should probably be a method or a set of methods # this list of valid commands should probably be a method or a set of methods
$self->{_commands} = \%commands; $self->{_commands} = \%commands;
$self; $self;
} }
sub id {
my $self = shift;
unless ($self->{_id}) {
$self->{_id} = sprintf("%d.%06d.%s.%d",
gettimeofday,
unpack("H*", (gethostbyname(hostname))[4]),
$$);
}
return $self->{_id};
}
sub command_counter { sub command_counter {
my $self = shift; my $self = shift;
$self->{_counter} || 0; $self->{_counter} || 0;
@ -135,16 +147,27 @@ sub transaction {
sub reset_transaction { sub reset_transaction {
my $self = shift; my $self = shift;
$self->run_hooks("reset_transaction") if $self->{_transaction}; $self->run_hooks("reset_transaction") if $self->{_transaction};
return $self->{_transaction} = Qpsmtpd::Transaction->new(); return $self->{_transaction} =
Qpsmtpd::Transaction->new(id => $self->connection->id . "." . ++$self->{_transaction_count});
} }
sub connection { sub connection {
my $self = shift; my $self = shift;
@_ and $self->{_connection} = shift; @_ and $self->{_connection} = shift;
return $self->{_connection} || ($self->{_connection} = Qpsmtpd::Connection->new()); unless ($self->{_connection}) {
$self->{_connection} = Qpsmtpd::Connection->new();
$self->reset_connection;
}
return $self->{_connection};
} }
sub reset_connection {
my $self = shift;
$self->connection->id($self->id . "." . ++$self->{_connection_count});
$self->{_transaction_count} = 0;
$self->reset_transaction;
}
sub helo { sub helo {
my ($self, $line) = @_; my ($self, $line) = @_;

View File

@ -22,21 +22,7 @@ sub start {
my $class = ref($proto) || $proto; my $class = ref($proto) || $proto;
my %args = @_; my %args = @_;
# Generate unique id my $self = { _rcpt => [], started => time, _id => $args{id} };
# use gettimeofday for microsec precision
# add in a sequence in case gettimeofday clock is slow (e.g. alpha)
# add in $$ to provide uniqueness per process/child
my ($start, $mstart) = gettimeofday();
my $seq = $SEQUENCE_ID++ % 10000;
my $id = sprintf("%d.%06d.%s.%d.%d",
$start,
$mstart,
$SALT_HOST,
$seq,
$$,
);
my $self = { _rcpt => [], started => $start, _id => $id };
bless ($self, $class); bless ($self, $class);
return $self; return $self;
} }

View File

@ -239,7 +239,7 @@ while (1) {
# get local/remote hostname, port and ip address # get local/remote hostname, port and ip address
my ($port, $iaddr, $lport, $laddr, $nto_iaddr, $nto_laddr) = Qpsmtpd::TcpServer::lrpip($server, $client, $hisaddr); my ($port, $iaddr, $lport, $laddr, $nto_iaddr, $nto_laddr) = Qpsmtpd::TcpServer::lrpip($server, $client, $hisaddr);
$qpsmtpd->connection->new_id; $qpsmtpd->reset_connection;
my ($rc, @msg) = $qpsmtpd->run_hooks("pre-connection", my ($rc, @msg) = $qpsmtpd->run_hooks("pre-connection",
remote_ip => $nto_iaddr, remote_ip => $nto_iaddr,
remote_port => $port, remote_port => $port,