You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2009/11/19 01:51:10 UTC
svn commit: r882020 - in /spamassassin/trunk/lib/Mail: ./ SpamAssassin/
SpamAssassin/Plugin/
Author: mmartinec
Date: Thu Nov 19 00:51:09 2009
New Revision: 882020
URL: http://svn.apache.org/viewvc?rev=882020&view=rev
Log:
Bug 6238: introducing the 'time_limit' configuration option,
with associated code changes in various places
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin.pm
spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm
spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgLearner.pm
spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DCC.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Pyzor.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/SPF.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Timeout.pm
Modified: spamassassin/trunk/lib/Mail/SpamAssassin.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin.pm Thu Nov 19 00:51:09 2009
@@ -485,8 +485,9 @@
sub parse {
my($self, $message, $parsenow, $suppl_attrib) = @_;
- $self->init(1);
+ my $start_time = time;
+ $self->init(1);
my $timer = $self->time_method("parse");
my $msg = Mail::SpamAssassin::Message->new({
@@ -494,6 +495,15 @@
normalize=>$self->{conf}->{normalize_charset},
suppl_attrib=>$suppl_attrib });
+ if (ref $suppl_attrib && exists $suppl_attrib->{master_deadline}) {
+ $msg->{master_deadline} = $suppl_attrib->{master_deadline}; # may be undef
+ } elsif ($self->{conf}->{time_limit}) { # defined and nonzero
+ $msg->{master_deadline} = $start_time + $self->{conf}->{time_limit};
+ }
+ if (defined $msg->{master_deadline}) {
+ dbg("config: time limit %.1f s", $msg->{master_deadline} - $start_time);
+ }
+
# bug 5069: The goal here is to get rendering plugins to do things
# like OCR, convert doc and pdf to text, etc, though it could be anything
# that wants to process the message after it's been parsed.
@@ -524,10 +534,10 @@
my ($self, $mail_obj) = @_;
$self->init(1);
- my $msg = Mail::SpamAssassin::PerMsgStatus->new($self, $mail_obj);
- $msg->check();
+ my $pms = Mail::SpamAssassin::PerMsgStatus->new($self, $mail_obj);
+ $pms->check();
dbg("timing: " . $self->timer_report()) if $self->{timer_enabled};
- $msg;
+ $pms;
}
=item $status = $f->check_message_text ($mailtext)
@@ -1350,7 +1360,7 @@
"Message-Id: <"....@spamassassin_spamd_init>\n", "\n",
"I need to make this message body somewhat long so TextCat preloads\n"x20);
- my $mail = $self->parse(\@testmsg, 1);
+ my $mail = $self->parse(\@testmsg, 1, { master_deadline => undef });
my $status = Mail::SpamAssassin::PerMsgStatus->new($self, $mail,
{ disable_auto_learning => 1 } );
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/AsyncLoop.pm Thu Nov 19 00:51:09 2009
@@ -168,7 +168,7 @@
=cut
sub start_lookup {
- my ($self, $ent) = @_;
+ my ($self, $ent, $master_deadline) = @_;
die "oops, no id" unless $ent->{id} ne '';
die "oops, no key" unless $ent->{key} ne '';
@@ -210,8 +210,17 @@
$t_end = $settings->{rbl_timeout_min} if $settings && !defined $t_end;
$t_end = 0.2 * $t_init if !defined $t_end;
$t_end = 0 if $t_end < 0; # just in case
-
$t_init = $t_end if $t_init < $t_end;
+
+ my $clipped_by_master_deadline = 0;
+ if (defined $master_deadline) {
+ my $time_avail = $master_deadline - time;
+ $time_avail = 0.5 if $time_avail < 0.5; # give some slack
+ if ($t_init > $time_avail) {
+ $t_init = $time_avail; $clipped_by_master_deadline = 1;
+ $t_end = $time_avail if $t_end > $time_avail;
+ }
+ }
$ent->{timeout_initial} = $t_init;
$ent->{timeout_min} = $t_end;
@@ -224,8 +233,9 @@
$self->{total_queries_started}++;
$self->{pending_lookups}->{$key} = $ent;
- dbg("async: starting: %s (timeout %.1fs, min %.1fs)",
- $ent->{display_id}, $ent->{timeout_initial}, $ent->{timeout_min});
+ dbg("async: starting: %s (timeout %.1fs, min %.1fs)%s",
+ $ent->{display_id}, $ent->{timeout_initial}, $ent->{timeout_min},
+ !$clipped_by_master_deadline ? '' : ', capped by time limit');
$ent;
}
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Thu Nov 19 00:51:09 2009
@@ -1573,6 +1573,61 @@
=over 4
+=item time_limit n (default: 0, i.e. unlimited)
+
+Specifies a limit on elapsed time in seconds that SpamAssassin is allowed
+to spend before providing a result. The value may be fractional and must not
+be negative, zero is interpreted as unlimited and is a default.
+
+This is a best-effort advisory setting, processing will not be abruptly
+aborted at an arbitrary point in processing when the time limit is exceeded,
+but only on reaching one of locations in the program flow equipped with a
+time test. Currently equipped with the test are the main checking loop,
+asynchronous DNS lookups, plugins which are calling external programs.
+Rule evaluation is guarded by starting a timer (alarm) on each set of
+compiled rules.
+
+When a message is passed to Mail::SpamAssassin::parse, a deadline time
+is established as a sum of current time and the C<time_limit> setting.
+This deadline may be overruled by a caller through option 'master_deadline'
+in $suppl_attrib on a call to parse(), possibly providing a more accurate
+deadline taking into account past and expected future processing of a
+message in a mail filtering setup.
+
+When a time limit is exceeded, most of the remaining tests will be skipped,
+as well as auto-learning. Whatever tests fired so far will determine the
+final score. The behaviour is similar to short-circuiting with attribute 'on',
+as implemented by a Shortcircuit plugin. A synthetic hit on a rule named
+TIME_LIMIT_EXCEEDED with a near-zero score is generated, so that the report
+will reflect the event.
+
+The C<time_limit> option is a useful protection against excessive processing
+time on certain degenerate or unusually long or complex mail messages, as well
+as against some DoS attacks. It is also needed in time-critical pre-queue
+filtering setups (e.g. milter, proxy, integration with MTA), where message
+processing must finish before a SMTP client times out. RFC 5321 prescribes
+in section 4.5.3.2.6 the 'DATA Termination' time limit of 10 minutes,
+although it is not unusual to see some SMTP clients abort sooner on waiting
+for a response. A sensible C<time_limit> for a pre-queue filtering setup is
+maybe 50 seconds, assuming that clients are willing to wait at least a minute.
+
+=cut
+
+ push (@cmds, {
+ setting => 'time_limit',
+ default => 0,
+ type => $CONF_TYPE_NUMERIC,
+ code => sub {
+ my ($self, $key, $value, $line) = @_;
+ if ($value !~ /^\d+(?:\.\d*)?$/) { return $INVALID_VALUE }
+ $value = 0+$value;
+ if ($value < 0) { return $INVALID_VALUE }
+ $self->{time_limit} = $value;
+ }
+ });
+
+=over 4
+
=item lock_method type
Select the file-locking method used to protect database files on-disk. By
@@ -2549,7 +2604,7 @@
All DNS queries are made at the beginning of a check and we try to read
the results at the end. This value specifies the maximum period of time
-(in seconds) to wait for an DNS query. If most of the DNS queries have
+(in seconds) to wait for a DNS query. If most of the DNS queries have
succeeded for a particular message, then SpamAssassin will not wait for
the full period to avoid wasting time on unresponsive server(s), but will
shrink the timeout according to a percentage of queries already completed.
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm Thu Nov 19 00:51:09 2009
@@ -124,7 +124,8 @@
});
$ent->{id} = $id; # tie up the loose end
- $existing = $self->{async}->start_lookup($ent);
+ $existing =
+ $self->{async}->start_lookup($ent, $self->{master_deadline});
}
# always add set
@@ -172,7 +173,7 @@
});
$ent->{id} = $id; # tie up the loose end
- $self->{async}->start_lookup($ent);
+ $self->{async}->start_lookup($ent, $self->{master_deadline});
}
###########################################################################
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgLearner.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgLearner.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgLearner.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgLearner.pm Thu Nov 19 00:51:09 2009
@@ -73,6 +73,7 @@
'main' => $main,
'msg' => $msg,
'learned' => 0,
+ 'master_deadline' => $msg->{master_deadline},
};
$self->{conf} = $self->{main}->{conf};
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm Thu Nov 19 00:51:09 2009
@@ -53,6 +53,8 @@
use warnings;
use re 'taint';
+use Time::HiRes qw(time);
+
use Mail::SpamAssassin::Constants qw(:sa);
use Mail::SpamAssassin::AsyncLoop;
use Mail::SpamAssassin::Conf;
@@ -92,7 +94,9 @@
'disable_auto_learning' => 0,
'auto_learn_status' => undef,
'conf' => $main->{conf},
- 'async' => Mail::SpamAssassin::AsyncLoop->new($main)
+ 'async' => Mail::SpamAssassin::AsyncLoop->new($main),
+ 'master_deadline' => $msg->{master_deadline}, # typically just inherited
+ 'deadline_exceeded' => 0, # time limit exceeded, skipping further tests
};
#$self->{main}->{use_rule_subs} = 1;
@@ -2200,7 +2204,6 @@
to be appended to an existing list of flags in $self->{conf}->{tflags},
such as: "nice noautolearn multiple". No syntax checks are performed.
-
=item description => $string
Optional: a custom rule description string. This is used in the
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm Thu Nov 19 00:51:09 2009
@@ -225,7 +225,7 @@
key=>$key, id=>$id, type=>'TXT',
zone => $zone, # serves to fetch other per-zone settings
};
- $scanner->{async}->start_lookup($ent);
+ $scanner->{async}->start_lookup($ent, $scanner->{master_deadline});
dbg("asn: launched DNS TXT query for %s.%s in background",
$reversed_ip_quad, $entry->{zone});
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Check.pm Thu Nov 19 00:51:09 2009
@@ -18,9 +18,12 @@
use warnings;
use re 'taint';
+use Time::HiRes qw(time);
+
use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::Logger;
use Mail::SpamAssassin::Util qw(untaint_var);
+use Mail::SpamAssassin::Timeout;
use Mail::SpamAssassin::Constants qw(:sa);
use vars qw(@ISA @TEMPORARY_METHODS);
@@ -49,7 +52,7 @@
my $pms = $args->{permsgstatus};
my $suppl_attrib = $pms->{msg}->{suppl_attrib};
- if (defined $suppl_attrib && ref $suppl_attrib->{rule_hits}) {
+ if (ref $suppl_attrib && ref $suppl_attrib->{rule_hits}) {
my @caller_rule_hits = @{$suppl_attrib->{rule_hits}};
dbg("check: adding caller rule hits, %d rules", scalar(@caller_rule_hits));
for my $caller_rule_hit (@caller_rule_hits) {
@@ -79,6 +82,7 @@
my $decoded = $pms->get_decoded_stripped_body_text_array();
my $bodytext = $pms->get_decoded_body_text_array();
my $fulltext = $pms->{msg}->get_pristine();
+ my $master_deadline = $pms->{master_deadline};
my @uris = $pms->get_uri_list();
@@ -87,11 +91,19 @@
# happen in Conf.pm when we switch a rule from one priority to another
next unless ($pms->{conf}->{priorities}->{$priority} > 0);
- my $timer = $self->{main}->time_method("tests_pri_".$priority);
-
- # if shortcircuiting is hit, we skip all other priorities...
- last if $self->{main}->call_plugins("have_shortcircuited", { permsgstatus => $pms });
+ if ($pms->{deadline_exceeded}) {
+ last;
+ } elsif ($master_deadline && time > $master_deadline) {
+ info("check: exceeded time limit, skipping further tests");
+ $pms->{deadline_exceeded} = 1;
+ last;
+ } elsif ($self->{main}->call_plugins("have_shortcircuited",
+ { permsgstatus => $pms })) {
+ # if shortcircuiting is hit, we skip all other priorities...
+ last;
+ }
+ my $timer = $self->{main}->time_method("tests_pri_".$priority);
dbg("check: running tests for priority: $priority");
# only harvest the dnsbl queries once priority HARVEST_DNSBL_PRIORITY
@@ -122,33 +134,49 @@
# do head tests
$self->do_head_tests($pms, $priority);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
+
$self->do_head_eval_tests($pms, $priority);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
$self->do_body_tests($pms, $priority, $decoded);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
+
$self->do_uri_tests($pms, $priority, @uris);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
+
$self->do_body_eval_tests($pms, $priority, $decoded);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
$self->do_rawbody_tests($pms, $priority, $bodytext);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
+
$self->do_rawbody_eval_tests($pms, $priority, $bodytext);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
$self->do_full_tests($pms, $priority, \$fulltext);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
+
$self->do_full_eval_tests($pms, $priority, \$fulltext);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
$self->do_meta_tests($pms, $priority);
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
# we may need to call this more often than once through the loop, but
# it needs to be done at least once, either at the beginning or the end.
$self->{main}->call_plugins ("check_tick", { permsgstatus => $pms });
$pms->harvest_completed_queries();
+ last if $pms->{deadline_exceeded};
}
# sanity check, it is possible that no rules >= HARVEST_DNSBL_PRIORITY ran so the harvest
@@ -167,15 +195,27 @@
$pms->{resolver}->finish_socket() if $pms->{resolver};
}
+ if ($pms->{deadline_exceeded}) {
+ $pms->got_hit('TIME_LIMIT_EXCEEDED', '', score => 0.001,
+ description => 'Exceeded time limit / deadline');
+ }
+
# finished running rules
delete $pms->{current_rule_name};
undef $decoded;
undef $bodytext;
undef $fulltext;
- # auto-learning
- $pms->learn();
- $self->{main}->call_plugins ("check_post_learn", { permsgstatus => $pms });
+ if ($pms->{deadline_exceeded}) {
+ # dbg("check: exceeded time limit, skipping auto-learning");
+ } elsif ($master_deadline && time > $master_deadline) {
+ info("check: exceeded time limit, skipping auto-learning");
+ $pms->{deadline_exceeded} = 1;
+ } else {
+ # auto-learning
+ $pms->learn();
+ $self->{main}->call_plugins ("check_post_learn", { permsgstatus => $pms });
+ }
# track user_rules recompilations; each scanned message is 1 tick on this counter
if ($self->{done_user_rules}) {
@@ -239,8 +279,17 @@
sub run_generic_tests {
my ($self, $pms, $priority, %opts) = @_;
- return if $self->{main}->call_plugins("have_shortcircuited",
- { permsgstatus => $pms });
+ my $master_deadline = $pms->{master_deadline};
+ if ($pms->{deadline_exceeded}) {
+ return;
+ } elsif ($master_deadline && time > $master_deadline) {
+ info("check: (run_generic) exceeded time limit, skipping further tests");
+ $pms->{deadline_exceeded} = 1;
+ return;
+ } elsif ($self->{main}->call_plugins("have_shortcircuited",
+ { permsgstatus => $pms })) {
+ return;
+ }
my $ruletype = $opts{type};
dbg("rules: running $ruletype tests; score so far=".$pms->{score});
@@ -257,11 +306,17 @@
my $methodname = $package_name."::_".$ruletype."_tests_".$clean_priority;
if (defined &{$methodname} && !$doing_user_rules) {
- no strict "refs";
run_compiled_method:
# dbg("rules: run_generic_tests - calling %s", $methodname);
- $methodname->($pms, @{$opts{args}});
- use strict "refs";
+ my $t = Mail::SpamAssassin::Timeout->new({ deadline => $master_deadline });
+ my $err = $t->run(sub {
+ no strict "refs";
+ $methodname->($pms, @{$opts{args}});
+ });
+ if ($t->timed_out() && $master_deadline && time > $master_deadline) {
+ info("check: exceeded time limit in $methodname, skipping further tests");
+ $pms->{deadline_exceeded} = 1;
+ }
return;
}
@@ -1030,8 +1085,17 @@
sub run_eval_tests {
my ($self, $pms, $testtype, $evalhash, $prepend2desc, $priority, @extraevalargs) = @_;
- return if $self->{main}->call_plugins("have_shortcircuited",
- { permsgstatus => $pms });
+ my $master_deadline = $pms->{master_deadline};
+ if ($pms->{deadline_exceeded}) {
+ return;
+ } elsif ($master_deadline && time > $master_deadline) {
+ info("check: (run_eval) exceeded time limit, skipping further tests");
+ $pms->{deadline_exceeded} = 1;
+ return;
+ } elsif ($self->{main}->call_plugins("have_shortcircuited",
+ { permsgstatus => $pms })) {
+ return;
+ }
my $conf = $pms->{conf};
my $doing_user_rules = $conf->{want_rebuild_for_type}->{$testtype};
@@ -1053,10 +1117,17 @@
if (defined &{"${package_name}::${methodname}"}
&& !$doing_user_rules)
{
+ my $method = "${package_name}::${methodname}";
# dbg("rules: run_eval_tests - calling %s", $methodname);
- no strict "refs";
- &{"${package_name}::${methodname}"}($pms,@extraevalargs);
- use strict "refs";
+ my $t = Mail::SpamAssassin::Timeout->new({ deadline => $master_deadline });
+ my $err = $t->run(sub {
+ no strict "refs";
+ &{$method}($pms,@extraevalargs);
+ });
+ if ($t->timed_out() && $master_deadline && time > $master_deadline) {
+ info("check: exceeded time limit in $method, skipping further tests");
+ $pms->{deadline_exceeded} = 1;
+ }
return;
}
@@ -1207,9 +1278,15 @@
my $method = "${package_name}::${methodname}";
push (@TEMPORARY_METHODS, $methodname);
# dbg("rules: run_eval_tests - calling %s", $methodname);
- no strict "refs";
- &{$method}($pms,@extraevalargs);
- use strict "refs";
+ my $t = Mail::SpamAssassin::Timeout->new({ deadline => $master_deadline });
+ my $err = $t->run(sub {
+ no strict "refs";
+ &{$method}($pms,@extraevalargs);
+ });
+ if ($t->timed_out() && $master_deadline && time > $master_deadline) {
+ info("check: exceeded time limit in $method, skipping further tests");
+ $pms->{deadline_exceeded} = 1;
+ }
}
}
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DCC.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DCC.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DCC.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DCC.pm Thu Nov 19 00:51:09 2009
@@ -679,7 +679,8 @@
$permsgstatus->enter_helper_run_mode();
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $permsgstatus->{master_deadline} });
my $err = $timer->run_and_catch(sub {
local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
@@ -757,7 +758,8 @@
my $tmpf = $permsgstatus->create_fulltext_tmpfile($fulltext);
my $pid;
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $permsgstatus->{master_deadline} });
my $err = $timer->run_and_catch(sub {
local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm Thu Nov 19 00:51:09 2009
@@ -719,7 +719,8 @@
};
my $timeout = $pms->{conf}->{dkim_timeout};
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $pms->{master_deadline} });
my $err = $timer->run_and_catch(sub {
dbg("dkim: performing public key lookup and signature verification");
@@ -909,7 +910,8 @@
my $practices; # author domain signing practices object
my $timeout = $pms->{conf}->{dkim_timeout};
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $pms->{master_deadline} });
my $err = $timer->run_and_catch(sub {
eval {
if (Mail::DKIM::AuthorDomainPolicy->UNIVERSAL::can("fetch")) {
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Pyzor.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Pyzor.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Pyzor.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Pyzor.pm Thu Nov 19 00:51:09 2009
@@ -267,7 +267,8 @@
$permsgstatus->enter_helper_run_mode();
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $permsgstatus->{master_deadline} });
my $err = $timer->run_and_catch(sub {
local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Razor2.pm Thu Nov 19 00:51:09 2009
@@ -140,7 +140,7 @@
}
sub razor2_access {
- my ($self, $fulltext, $type) = @_;
+ my ($self, $fulltext, $type, $deadline) = @_;
my $timeout = $self->{main}->{conf}->{razor_timeout};
my $return = 0;
my @results;
@@ -155,7 +155,8 @@
Mail::SpamAssassin::PerMsgStatus::enter_helper_run_mode($self);
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $deadline });
my $err = $timer->run_and_catch(sub {
local ($^W) = 0; # argh, warnings in Razor
@@ -347,7 +348,7 @@
return unless $self->{main}->{conf}->{use_razor2};
return if $options->{report}->{options}->{dont_report_to_razor};
- if ($self->razor2_access($options->{text}, 'report')) {
+ if ($self->razor2_access($options->{text}, 'report', undef)) {
$options->{report}->{report_available} = 1;
info('reporter: spam reported to Razor');
$options->{report}->{report_return} = 1;
@@ -365,7 +366,7 @@
return unless $self->{main}->{conf}->{use_razor2};
return if $options->{revoke}->{options}->{dont_report_to_razor};
- if ($self->razor2_access($options->{text}, 'revoke')) {
+ if ($self->razor2_access($options->{text}, 'revoke', undef)) {
$options->{revoke}->{revoke_available} = 1;
dbg('reporter: spam revoked from Razor');
$options->{revoke}->{revoke_return} = 1;
@@ -394,7 +395,8 @@
# do it this way to make it easier to get out the results later from the
# netcache plugin
- ($return, @results) = $self->razor2_access($full, 'check');
+ ($return, @results) =
+ $self->razor2_access($full, 'check', $permsgstatus->{master_deadline});
$self->{main}->call_plugins ('process_razor_result',
{ results => \@results, permsgstatus => $permsgstatus }
);
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/SPF.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/SPF.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/SPF.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/SPF.pm Thu Nov 19 00:51:09 2009
@@ -542,7 +542,8 @@
my $timeout = $scanner->{conf}->{spf_timeout};
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $scanner->{master_deadline} });
$err = $timer->run_and_catch(sub {
my $query = $self->{spf_server}->process($request);
@@ -579,7 +580,8 @@
my $timeout = $scanner->{conf}->{spf_timeout};
- my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+ my $timer = Mail::SpamAssassin::Timeout->new(
+ { secs => $timeout, deadline => $scanner->{master_deadline} });
$err = $timer->run_and_catch(sub {
($result, $comment) = $query->result();
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm Thu Nov 19 00:51:09 2009
@@ -924,7 +924,7 @@
}
}
};
- $scanner->{async}->start_lookup($ent);
+ $scanner->{async}->start_lookup($ent, $scanner->{master_deadline});
return $ent;
}
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Timeout.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Timeout.pm?rev=882020&r1=882019&r2=882020&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Timeout.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Timeout.pm Thu Nov 19 00:51:09 2009
@@ -23,7 +23,7 @@
# non-timeout code...
- my $t = Mail::SpamAssassin::Timeout->new({ secs => 5 });
+ my $t = Mail::SpamAssassin::Timeout->new({ secs => 5, deadline => $when });
$t->run(sub {
# code to run with a 5-second timeout...
@@ -58,6 +58,8 @@
use bytes;
use re 'taint';
+use Time::HiRes qw(time alarm);
+
use vars qw{
@ISA
};
@@ -74,7 +76,14 @@
=item secs => $seconds
-timeout, in seconds. Optional; if not specified, no timeouts will be applied.
+time interval, in seconds. Optional; if neither C<secs> nor C<deadline> is
+specified, no timeouts will be applied.
+
+=item deadline => $unix_timestamp
+
+Unix timestamp (time in seconds since epoch) when a timeout is reached.
+Optional; if neither B<secs> nor B<deadline> is specified, no timeouts will
+be applied. If both are specified, the shorter interval of the two prevails.
=back
@@ -96,7 +105,8 @@
Run a code reference within the currently-defined timeout.
-The timeout is as defined by the B<secs> parameter to the constructor.
+The timeout is as defined by the B<secs> and B<deadline> parameters
+to the constructor.
Returns whatever the subroutine returns, or C<undef> on timeout.
If the timer times out, C<$t-<gt>timed_out()> will return C<1>.
@@ -123,13 +133,22 @@
delete $self->{timed_out};
- if (!$self->{secs}) { # no timeout! just call the sub and return.
+ my $secs = $self->{secs};
+ my $deadline = $self->{deadline};
+
+ if (defined $deadline) {
+ my $dt = $deadline - time;
+ $dt = 1 if $dt < 1; # give some slack
+ $secs = $dt if !defined $secs || $dt < $secs;
+ }
+
+ if (!defined $secs) { # no timeout! just call the sub and return.
return &$sub;
}
# assertion
- if ($self->{secs} < 0) {
- die "Mail::SpamAssassin::Timeout: oops? neg value for 'secs': $self->{secs}";
+ if ($secs < 0) {
+ die "Mail::SpamAssassin::Timeout: oops? neg value for 'secs': $secs";
}
my $oldalarm = 0;
@@ -146,7 +165,7 @@
local $SIG{ALRM} = sub { $timedout++; die "__alarm__ignore__\n" };
local $SIG{__DIE__}; # bug 4631
- $oldalarm = alarm($self->{secs});
+ $oldalarm = alarm($secs);
$ret = &$sub;
@@ -187,11 +206,7 @@
$self->{timed_out} = 1;
}
- if ($and_catch) {
- return; # undef
- } else {
- return $ret;
- }
+ return $and_catch ? undef : $ret;
}
###########################################################################
@@ -219,7 +234,16 @@
sub reset {
my ($self) = @_;
- alarm($self->{secs});
+
+ my $secs = $self->{secs};
+ my $deadline = $self->{deadline};
+
+ if (defined $deadline) {
+ my $dt = $deadline - time;
+ $dt = 1 if $dt < 1; # give some slack
+ $secs = $dt if !defined $secs || $dt < $secs;
+ }
+ alarm($secs) if defined $secs;
}
###########################################################################