| OLD | NEW |
| (Empty) |
| 1 X-Original-To: jm@jmason.org | |
| 2 Delivered-To: jm@dogma.boxhost.net | |
| 3 Received: from localhost [127.0.0.1] | |
| 4 by localhost with IMAP (fetchmail-6.2.5) | |
| 5 for jm@localhost (single-drop); Thu, 09 Mar 2006 21:44:57 +0000 (GMT) | |
| 6 Received: from minotaur.apache.org (minotaur.apache.org [209.237.227.194]) | |
| 7 by dogma.boxhost.net (Postfix) with SMTP id 0D3463105BF | |
| 8 for <jm@jmason.org>; Thu, 9 Mar 2006 19:52:50 +0000 (GMT) | |
| 9 Received: (qmail 30661 invoked by uid 1833); 9 Mar 2006 19:52:44 -0000 | |
| 10 Delivered-To: jm@locus.apache.org | |
| 11 Received: (qmail 30451 invoked from network); 9 Mar 2006 19:52:38 -0000 | |
| 12 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) | |
| 13 by minotaur.apache.org with SMTP; 9 Mar 2006 19:52:38 -0000 | |
| 14 Received: (qmail 97860 invoked by uid 500); 9 Mar 2006 19:52:29 -0000 | |
| 15 Delivered-To: apmail-jm@apache.org | |
| 16 Received: (qmail 97837 invoked by uid 500); 9 Mar 2006 19:52:28 -0000 | |
| 17 Mailing-List: contact commits-help@spamassassin.apache.org; run by ezmlm | |
| 18 Precedence: bulk | |
| 19 list-help: <mailto:commits-help@spamassassin.apache.org> | |
| 20 list-unsubscribe: <mailto:commits-unsubscribe@spamassassin.apache.org> | |
| 21 List-Post: <mailto:commits@spamassassin.apache.org> | |
| 22 Reply-To: "SpamAssassin Dev" <dev@spamassassin.apache.org> | |
| 23 List-Id: <commits.spamassassin.apache.org> | |
| 24 Delivered-To: mailing list commits@spamassassin.apache.org | |
| 25 Received: (qmail 97826 invoked by uid 99); 9 Mar 2006 19:52:28 -0000 | |
| 26 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) | |
| 27 by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 09 Mar 2006 11:52:28 -0800 | |
| 28 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 | |
| 29 tests=ALL_TRUSTED,NO_REAL_NAME | |
| 30 Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) | |
| 31 by apache.org (qpsmtpd/0.29) with SMTP; Thu, 09 Mar 2006 11:52:26 -0800 | |
| 32 Received: (qmail 29644 invoked by uid 65534); 9 Mar 2006 19:52:06 -0000 | |
| 33 Message-ID: <20060309195206.29643.qmail@minotaur.apache.org> | |
| 34 Content-Type: text/plain; charset="utf-8" | |
| 35 MIME-Version: 1.0 | |
| 36 Content-Transfer-Encoding: 7bit | |
| 37 Subject: svn commit: r384590 - in /spamassassin/branches/3.1: ./ | |
| 38 lib/Mail/SpamAssassin/ lib/Mail/SpamAssassin/Plugin/ spamd/ | |
| 39 Date: Thu, 09 Mar 2006 19:52:02 -0000 | |
| 40 To: commits@spamassassin.apache.org | |
| 41 From: sidney@apache.org | |
| 42 X-Mailer: svnmailer-1.0.7 | |
| 43 X-Virus-Checked: Checked by ClamAV on apache.org | |
| 44 Status: O | |
| 45 X-UID: 60795 | |
| 46 X-Keywords:
| |
| 47 | |
| 48 Author: sidney | |
| 49 Date: Thu Mar 9 11:51:59 2006 | |
| 50 New Revision: 384590 | |
| 51 | |
| 52 URL: http://svn.apache.org/viewcvs?rev=384590&view=rev | |
| 53 Log: | |
| 54 Bug 4696: consolidated fixes for timeout bugs | |
| 55 | |
| 56 Added: | |
| 57 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm | |
| 58 Modified: | |
| 59 spamassassin/branches/3.1/MANIFEST | |
| 60 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm | |
| 61 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm | |
| 62 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm | |
| 63 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm | |
| 64 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm | |
| 65 spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm | |
| 66 spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm | |
| 67 spamassassin/branches/3.1/spamd/spamd.raw | |
| 68 | |
| 69 Modified: spamassassin/branches/3.1/MANIFEST | |
| 70 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/MANIFEST?rev=384590
&r1=384589&r2=384590&view=diff | |
| 71 ============================================================================== | |
| 72 --- spamassassin/branches/3.1/MANIFEST (original) | |
| 73 +++ spamassassin/branches/3.1/MANIFEST Thu Mar 9 11:51:59 2006 | |
| 74 @@ -89,6 +89,7 @@ | |
| 75 lib/Mail/SpamAssassin/SQLBasedAddrList.pm | |
| 76 lib/Mail/SpamAssassin/SpamdForkScaling.pm | |
| 77 lib/Mail/SpamAssassin/SubProcBackChannel.pm | |
| 78 +lib/Mail/SpamAssassin/Timeout.pm | |
| 79 lib/Mail/SpamAssassin/Util.pm | |
| 80 lib/Mail/SpamAssassin/Util/DependencyInfo.pm | |
| 81 lib/Mail/SpamAssassin/Util/Progress.pm | |
| 82 | |
| 83 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm | |
| 84 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Logger.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 85 ============================================================================== | |
| 86 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm (original) | |
| 87 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Logger.pm Thu Mar 9 11:51:5
9 2006 | |
| 88 @@ -142,7 +142,7 @@ | |
| 89 | |
| 90 if ($level eq "error") { | |
| 91 # don't log alarm timeouts or broken pipes of various plugins' network chec
ks | |
| 92 - return if ($message[0] =~ /__(?:alarm|brokenpipe)__ignore__/); | |
| 93 + return if ($message[0] =~ /__ignore__/); | |
| 94 | |
| 95 # dos: we can safely ignore any die's that we eval'd in our own modules so | |
| 96 # don't log them -- this is caller 0, the use'ing package is 1, the eval is
2 | |
| 97 | |
| 98 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm | |
| 99 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Plugin/DCC.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 100 ============================================================================== | |
| 101 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm (original) | |
| 102 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm Thu Mar 9 11:
51:59 2006 | |
| 103 @@ -44,6 +44,7 @@ | |
| 104 | |
| 105 use Mail::SpamAssassin::Plugin; | |
| 106 use Mail::SpamAssassin::Logger; | |
| 107 +use Mail::SpamAssassin::Timeout; | |
| 108 use IO::Socket; | |
| 109 use strict; | |
| 110 use warnings; | |
| 111 @@ -375,15 +376,10 @@ | |
| 112 | |
| 113 $permsgstatus->enter_helper_run_mode(); | |
| 114 | |
| 115 - my $oldalarm = 0; | |
| 116 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 117 + my $err = $timer->run_and_catch(sub { | |
| 118 | |
| 119 - eval { | |
| 120 - # safe to use $SIG{ALRM} here instead of Util::trap_sigalrm_fully(), | |
| 121 - # since there are no killer regexp hang dangers here | |
| 122 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 123 - local $SIG{__DIE__}; # bug 4631 | |
| 124 - | |
| 125 - $oldalarm = alarm $timeout; | |
| 126 + local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 127 | |
| 128 my $sock = IO::Socket::UNIX->new(Type => SOCK_STREAM, | |
| 129 Peer => $sockpath) || dbg("dcc: failed to open socket") && die; | |
| 130 @@ -419,28 +415,20 @@ | |
| 131 } | |
| 132 | |
| 133 dbg("dcc: dccifd got response: $response"); | |
| 134 + | |
| 135 + }); | |
| 136 | |
| 137 - if (defined $oldalarm) { | |
| 138 - alarm $oldalarm; $oldalarm = undef; | |
| 139 - } | |
| 140 - }; | |
| 141 + $permsgstatus->leave_helper_run_mode(); | |
| 142 | |
| 143 - my $err = $@; | |
| 144 - if (defined $oldalarm) { | |
| 145 - alarm $oldalarm; $oldalarm = undef; | |
| 146 + if ($timer->timed_out()) { | |
| 147 + dbg("dcc: dccifd check timed out after $timeout secs."); | |
| 148 + return 0; | |
| 149 } | |
| 150 - $permsgstatus->leave_helper_run_mode(); | |
| 151 | |
| 152 if ($err) { | |
| 153 chomp $err; | |
| 154 - $response = undef; | |
| 155 - if ($err eq "__alarm__ignore__") { | |
| 156 - dbg("dcc: dccifd check timed out after $timeout secs."); | |
| 157 - return 0; | |
| 158 - } else { | |
| 159 - warn("dcc: dccifd -> check skipped: $! $err"); | |
| 160 - return 0; | |
| 161 - } | |
| 162 + warn("dcc: dccifd -> check skipped: $! $err"); | |
| 163 + return 0; | |
| 164 } | |
| 165 | |
| 166 if (!defined $response || $response !~ /^X-DCC/) { | |
| 167 @@ -494,17 +482,12 @@ | |
| 168 | |
| 169 # use a temp file here -- open2() is unreliable, buffering-wise, under spamd | |
| 170 my $tmpf = $permsgstatus->create_fulltext_tmpfile($fulltext); | |
| 171 - my $oldalarm = 0; | |
| 172 - | |
| 173 my $pid; | |
| 174 - eval { | |
| 175 - # safe to use $SIG{ALRM} here instead of Util::trap_sigalrm_fully(), | |
| 176 - # since there are no killer regexp hang dangers here | |
| 177 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 178 - local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 179 - local $SIG{__DIE__}; # bug 4631 | |
| 180 | |
| 181 - $oldalarm = alarm $timeout; | |
| 182 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 183 + my $err = $timer->run_and_catch(sub { | |
| 184 + | |
| 185 + local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 186 | |
| 187 # note: not really tainted, this came from system configuration file | |
| 188 my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf
}->{dcc_path}); | |
| 189 @@ -542,17 +525,7 @@ | |
| 190 | |
| 191 dbg("dcc: got response: $response"); | |
| 192 | |
| 193 - # note: this must be called BEFORE leave_helper_run_mode() | |
| 194 - # $self->cleanup_kids($pid); | |
| 195 - if (defined $oldalarm) { | |
| 196 - alarm $oldalarm; $oldalarm = undef; | |
| 197 - } | |
| 198 - }; | |
| 199 - | |
| 200 - my $err = $@; | |
| 201 - if (defined $oldalarm) { | |
| 202 - alarm $oldalarm; $oldalarm = undef; | |
| 203 - } | |
| 204 + }); | |
| 205 | |
| 206 if (defined(fileno(*DCC))) { # still open | |
| 207 if ($pid) { | |
| 208 @@ -564,11 +537,14 @@ | |
| 209 } | |
| 210 $permsgstatus->leave_helper_run_mode(); | |
| 211 | |
| 212 + if ($timer->timed_out()) { | |
| 213 + dbg("dcc: check timed out after $timeout seconds"); | |
| 214 + return 0; | |
| 215 + } | |
| 216 + | |
| 217 if ($err) { | |
| 218 chomp $err; | |
| 219 - if ($err eq "__alarm__ignore__") { | |
| 220 - dbg("dcc: check timed out after $timeout seconds"); | |
| 221 - } elsif ($err eq "__brokenpipe__ignore__") { | |
| 222 + if ($err eq "__brokenpipe__ignore__") { | |
| 223 dbg("dcc: check failed: broken pipe"); | |
| 224 } elsif ($err eq "no response") { | |
| 225 dbg("dcc: check failed: no response"); | |
| 226 @@ -645,47 +621,37 @@ | |
| 227 my ($self, $options, $tmpf) = @_; | |
| 228 my $timeout = $options->{report}->{conf}->{dcc_timeout}; | |
| 229 | |
| 230 - $options->{report}->enter_helper_run_mode(); | |
| 231 + # note: not really tainted, this came from system configuration file | |
| 232 + my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->{c
onf}->{dcc_path}); | |
| 233 | |
| 234 - my $oldalarm = 0; | |
| 235 + my $opts = $options->{report}->{conf}->{dcc_options} || ''; | |
| 236 | |
| 237 - eval { | |
| 238 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 239 - local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 240 - local $SIG{__DIE__}; # bug 4631 | |
| 241 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 242 | |
| 243 - $oldalarm = alarm $timeout; | |
| 244 - | |
| 245 - # note: not really tainted, this came from system configuration file | |
| 246 - my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->
{conf}->{dcc_path}); | |
| 247 + $options->{report}->enter_helper_run_mode(); | |
| 248 + my $err = $timer->run_and_catch(sub { | |
| 249 | |
| 250 - my $opts = $options->{report}->{conf}->{dcc_options} || ''; | |
| 251 + local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 252 | |
| 253 my $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC, | |
| 254 - $tmpf, 1, $path, "-t", "many", split(' ', $opts)); | |
| 255 + $tmpf, 1, $path, "-t", "many", split(' ', $opts)); | |
| 256 $pid or die "$!\n"; | |
| 257 | |
| 258 my @ignored = <DCC>; | |
| 259 $options->{report}->close_pipe_fh(\*DCC); | |
| 260 - | |
| 261 waitpid ($pid, 0); | |
| 262 - if (defined $oldalarm) { | |
| 263 - alarm $oldalarm; $oldalarm = undef; | |
| 264 - } | |
| 265 - }; | |
| 266 + | |
| 267 + }); | |
| 268 + $options->{report}->leave_helper_run_mode(); | |
| 269 | |
| 270 - my $err = $@; | |
| 271 - if (defined $oldalarm) { | |
| 272 - alarm $oldalarm; $oldalarm = undef; | |
| 273 + if ($timer->timed_out()) { | |
| 274 + dbg("reporter: DCC report timed out after $timeout seconds"); | |
| 275 + return 0; | |
| 276 } | |
| 277 | |
| 278 - $options->{report}->leave_helper_run_mode(); | |
| 279 - | |
| 280 if ($err) { | |
| 281 chomp $err; | |
| 282 - if ($err eq "__alarm__ignore__") { | |
| 283 - dbg("reporter: DCC report timed out after $timeout seconds"); | |
| 284 - } elsif ($err eq "__brokenpipe__ignore__") { | |
| 285 + if ($err eq "__brokenpipe__ignore__") { | |
| 286 dbg("reporter: DCC report failed: broken pipe"); | |
| 287 } else { | |
| 288 warn("reporter: DCC report failed: $err\n"); | |
| 289 | |
| 290 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm | |
| 291 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Plugin/DomainKeys.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 292 ============================================================================== | |
| 293 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm (origin
al) | |
| 294 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm Thu Mar
9 11:51:59 2006 | |
| 295 @@ -34,6 +34,8 @@ | |
| 296 | |
| 297 use Mail::SpamAssassin::Plugin; | |
| 298 use Mail::SpamAssassin::Logger; | |
| 299 +use Mail::SpamAssassin::Timeout; | |
| 300 + | |
| 301 use strict; | |
| 302 use warnings; | |
| 303 use bytes; | |
| 304 @@ -165,30 +167,22 @@ | |
| 305 } | |
| 306 | |
| 307 my $timeout = $scan->{conf}->{domainkeys_timeout}; | |
| 308 - my $oldalarm = 0; | |
| 309 | |
| 310 - eval { | |
| 311 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 312 - local $SIG{__DIE__}; # bug 4631 | |
| 313 - $oldalarm = alarm($timeout); | |
| 314 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 315 + my $err = $timer->run_and_catch(sub { | |
| 316 + | |
| 317 $self->_dk_lookup_trapped($scan, $message, $domain); | |
| 318 - if (defined $oldalarm) { | |
| 319 - alarm $oldalarm; $oldalarm = undef; | |
| 320 - } | |
| 321 - }; | |
| 322 - | |
| 323 - my $err = $@; | |
| 324 - if (defined $oldalarm) { | |
| 325 - alarm $oldalarm; $oldalarm = undef; | |
| 326 + | |
| 327 + }); | |
| 328 + | |
| 329 + if ($timer->timed_out()) { | |
| 330 + dbg("dk: lookup timed out after $timeout seconds"); | |
| 331 + return 0; | |
| 332 } | |
| 333 | |
| 334 if ($err) { | |
| 335 chomp $err; | |
| 336 - if ($err eq "__alarm__ignore__") { | |
| 337 - dbg("dk: lookup timed out after $timeout seconds"); | |
| 338 - } else { | |
| 339 - warn("dk: lookup failed: $err\n"); | |
| 340 - } | |
| 341 + warn("dk: lookup failed: $err\n"); | |
| 342 return 0; | |
| 343 } | |
| 344 | |
| 345 | |
| 346 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm | |
| 347 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Plugin/Pyzor.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 348 ============================================================================== | |
| 349 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm (original) | |
| 350 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Pyzor.pm Thu Mar 9 1
1:51:59 2006 | |
| 351 @@ -35,6 +35,7 @@ | |
| 352 | |
| 353 use Mail::SpamAssassin::Plugin; | |
| 354 use Mail::SpamAssassin::Logger; | |
| 355 +use Mail::SpamAssassin::Timeout; | |
| 356 use strict; | |
| 357 use warnings; | |
| 358 use bytes; | |
| 359 @@ -229,27 +230,22 @@ | |
| 360 | |
| 361 $pyzor_count = 0; | |
| 362 $pyzor_whitelisted = 0; | |
| 363 - | |
| 364 - $permsgstatus->enter_helper_run_mode(); | |
| 365 + my $pid; | |
| 366 | |
| 367 # use a temp file here -- open2() is unreliable, buffering-wise, under spamd | |
| 368 my $tmpf = $permsgstatus->create_fulltext_tmpfile($fulltext); | |
| 369 - my $oldalarm = 0; | |
| 370 | |
| 371 - my $pid; | |
| 372 - eval { | |
| 373 - # safe to use $SIG{ALRM} here instead of Util::trap_sigalrm_fully(), | |
| 374 - # since there are no killer regexp hang dangers here | |
| 375 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 376 - local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 377 - local $SIG{__DIE__}; # bug 4631 | |
| 378 + # note: not really tainted, this came from system configuration file | |
| 379 + my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf}-
>{pyzor_path}); | |
| 380 + | |
| 381 + my $opts = $self->{main}->{conf}->{pyzor_options} || ''; | |
| 382 | |
| 383 - $oldalarm = alarm $timeout; | |
| 384 + $permsgstatus->enter_helper_run_mode(); | |
| 385 | |
| 386 - # note: not really tainted, this came from system configuration file | |
| 387 - my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf
}->{pyzor_path}); | |
| 388 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 389 + my $err = $timer->run_and_catch(sub { | |
| 390 | |
| 391 - my $opts = $self->{main}->{conf}->{pyzor_options} || ''; | |
| 392 + local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 393 | |
| 394 dbg("pyzor: opening pipe: " . join(' ', $path, $opts, "check", "< $tmpf")); | |
| 395 | |
| 396 @@ -273,21 +269,7 @@ | |
| 397 die("internal error\n"); | |
| 398 } | |
| 399 | |
| 400 - # note: this must be called BEFORE leave_helper_run_mode() | |
| 401 - # $self->cleanup_kids($pid); | |
| 402 - | |
| 403 - # attempt to call this inside the eval, as leaving this scope is | |
| 404 - # a slow operation and timing *that* out is pointless | |
| 405 - if (defined $oldalarm) { | |
| 406 - alarm $oldalarm; $oldalarm = undef; | |
| 407 - } | |
| 408 - }; | |
| 409 - | |
| 410 - # clear the alarm before doing lots of time-consuming hard work | |
| 411 - my $err = $@; | |
| 412 - if (defined $oldalarm) { | |
| 413 - alarm $oldalarm; $oldalarm = undef; | |
| 414 - } | |
| 415 + }); | |
| 416 | |
| 417 if (defined(fileno(*PYZOR))) { # still open | |
| 418 if ($pid) { | |
| 419 @@ -299,11 +281,14 @@ | |
| 420 } | |
| 421 $permsgstatus->leave_helper_run_mode(); | |
| 422 | |
| 423 + if ($timer->timed_out()) { | |
| 424 + dbg("pyzor: check timed out after $timeout seconds"); | |
| 425 + return 0; | |
| 426 + } | |
| 427 + | |
| 428 if ($err) { | |
| 429 chomp $err; | |
| 430 - if ($err eq "__alarm__ignore__") { | |
| 431 - dbg("pyzor: check timed out after $timeout seconds"); | |
| 432 - } elsif ($err eq "__brokenpipe__ignore__") { | |
| 433 + if ($err eq "__brokenpipe__ignore__") { | |
| 434 dbg("pyzor: check failed: broken pipe"); | |
| 435 } elsif ($err eq "no response") { | |
| 436 dbg("pyzor: check failed: no response"); | |
| 437 @@ -364,23 +349,19 @@ | |
| 438 | |
| 439 sub pyzor_report { | |
| 440 my ($self, $options, $tmpf) = @_; | |
| 441 + | |
| 442 + # note: not really tainted, this came from system configuration file | |
| 443 + my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->{c
onf}->{pyzor_path}); | |
| 444 + | |
| 445 + my $opts = $options->{report}->{conf}->{pyzor_options} || ''; | |
| 446 my $timeout = $self->{main}->{conf}->{pyzor_timeout}; | |
| 447 | |
| 448 $options->{report}->enter_helper_run_mode(); | |
| 449 | |
| 450 - my $oldalarm = 0; | |
| 451 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 452 + my $err = $timer->run_and_catch(sub { | |
| 453 | |
| 454 - eval { | |
| 455 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 456 local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" }; | |
| 457 - local $SIG{__DIE__}; # bug 4631 | |
| 458 - | |
| 459 - $oldalarm = alarm $timeout; | |
| 460 - | |
| 461 - # note: not really tainted, this came from system configuration file | |
| 462 - my $path = Mail::SpamAssassin::Util::untaint_file_path($options->{report}->
{conf}->{pyzor_path}); | |
| 463 - | |
| 464 - my $opts = $options->{report}->{conf}->{pyzor_options} || ''; | |
| 465 | |
| 466 dbg("pyzor: opening pipe: " . join(' ', $path, $opts, "report", "< $tmpf"))
; | |
| 467 | |
| 468 @@ -391,23 +372,19 @@ | |
| 469 my @ignored = <PYZOR>; | |
| 470 $options->{report}->close_pipe_fh(\*PYZOR); | |
| 471 | |
| 472 - if (defined $oldalarm) { | |
| 473 - alarm $oldalarm; $oldalarm = undef; | |
| 474 - } | |
| 475 waitpid ($pid, 0); | |
| 476 - }; | |
| 477 + }); | |
| 478 | |
| 479 - my $err = $@; | |
| 480 - if (defined $oldalarm) { | |
| 481 - alarm $oldalarm; $oldalarm = undef; | |
| 482 - } | |
| 483 $options->{report}->leave_helper_run_mode(); | |
| 484 | |
| 485 + if ($timer->timed_out()) { | |
| 486 + dbg("reporter: pyzor report timed out after $timeout seconds"); | |
| 487 + return 0; | |
| 488 + } | |
| 489 + | |
| 490 if ($err) { | |
| 491 chomp $err; | |
| 492 - if ($err eq '__alarm__ignore__') { | |
| 493 - dbg("reporter: pyzor report timed out after $timeout seconds"); | |
| 494 - } elsif ($err eq '__brokenpipe__ignore__') { | |
| 495 + if ($err eq '__brokenpipe__ignore__') { | |
| 496 dbg("reporter: pyzor report failed: broken pipe"); | |
| 497 } else { | |
| 498 warn("reporter: pyzor report failed: $err\n"); | |
| 499 | |
| 500 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm | |
| 501 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Plugin/Razor2.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 502 ============================================================================== | |
| 503 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm (original) | |
| 504 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/Razor2.pm Thu Mar 9
11:51:59 2006 | |
| 505 @@ -143,14 +143,11 @@ | |
| 506 } | |
| 507 | |
| 508 Mail::SpamAssassin::PerMsgStatus::enter_helper_run_mode($self); | |
| 509 - my $oldalarm = 0; | |
| 510 | |
| 511 - eval { | |
| 512 - local ($^W) = 0; # argh, warnings in Razor | |
| 513 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 514 + my $err = $timer->run_and_catch(sub { | |
| 515 | |
| 516 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 517 - local $SIG{__DIE__}; # bug 4631 | |
| 518 - $oldalarm = alarm $timeout; | |
| 519 + local ($^W) = 0; # argh, warnings in Razor | |
| 520 | |
| 521 # everything's in the module! | |
| 522 my $rc = Razor2::Client::Agent->new("razor-$type"); | |
| 523 @@ -184,7 +181,7 @@ | |
| 524 # let's reset the alarm since get_server_info() calls | |
| 525 # nextserver() which calls discover() which very likely will | |
| 526 # reset the alarm for us ... how polite. :( | |
| 527 - alarm $timeout; | |
| 528 + $timer->reset(); | |
| 529 | |
| 530 # no facility prefix on this die | |
| 531 my $sigs = $rc->compute_sigs($objects) | |
| 532 @@ -219,100 +216,96 @@ | |
| 533 my $error = $rc->errprefix("$debug: spamassassin") || "$debug: razor2
had unknown error during disconnect"; | |
| 534 die $error; | |
| 535 } | |
| 536 + } | |
| 537 | |
| 538 - # if we got here, we're done doing remote stuff, abort the alert | |
| 539 - if (defined $oldalarm) { | |
| 540 - alarm $oldalarm; $oldalarm = undef; | |
| 541 - } | |
| 542 - | |
| 543 - # Razor 2.14 says that if we get here, we did ok. | |
| 544 - $return = 1; | |
| 545 + # Razor 2.14 says that if we get here, we did ok. | |
| 546 + $return = 1; | |
| 547 | |
| 548 - # figure out if we have a log file we need to close... | |
| 549 - if (ref($rc->{logref}) && exists $rc->{logref}->{fd}) { | |
| 550 - # the fd can be stdout or stderr, so we need to find out if it is | |
| 551 - # so we don't close them by accident. Note: we can't just | |
| 552 - # undef the fd here (like the IO::Handle manpage says we can) | |
| 553 - # because it won't actually close, unfortunately. :( | |
| 554 - my $untie = 1; | |
| 555 - foreach my $log (*STDOUT{IO}, *STDERR{IO}) { | |
| 556 - if ($log == $rc->{logref}->{fd}) { | |
| 557 - $untie = 0; | |
| 558 - last; | |
| 559 - } | |
| 560 - } | |
| 561 - close $rc->{logref}->{fd} if ($untie); | |
| 562 - } | |
| 563 - | |
| 564 - if ($type eq 'check') { | |
| 565 - # so $objects->[0] is the first (only) message, and ->{spam} is a gene
ral yes/no | |
| 566 - push(@results, { result => $objects->[0]->{spam} }); | |
| 567 + # figure out if we have a log file we need to close... | |
| 568 + if (ref($rc->{logref}) && exists $rc->{logref}->{fd}) { | |
| 569 + # the fd can be stdout or stderr, so we need to find out if it is | |
| 570 + # so we don't close them by accident. Note: we can't just | |
| 571 + # undef the fd here (like the IO::Handle manpage says we can) | |
| 572 + # because it won't actually close, unfortunately. :( | |
| 573 + my $untie = 1; | |
| 574 + foreach my $log (*STDOUT{IO}, *STDERR{IO}) { | |
| 575 + if ($log == $rc->{logref}->{fd}) { | |
| 576 + $untie = 0; | |
| 577 + last; | |
| 578 + } | |
| 579 + } | |
| 580 + close $rc->{logref}->{fd} if ($untie); | |
| 581 + } | |
| 582 | |
| 583 - # great for debugging, but leave this off! | |
| 584 - #use Data::Dumper; | |
| 585 - #print Dumper($objects),"\n"; | |
| 586 - | |
| 587 - # ->{p} is for each part of the message | |
| 588 - # so go through each part, taking the highest cf we find | |
| 589 - # of any part that isn't contested (ct). This helps avoid false | |
| 590 - # positives. equals logic_method 4. | |
| 591 - # | |
| 592 - # razor-agents < 2.14 have a different object format, so we now suppor
t both. | |
| 593 - # $objects->[0]->{resp} vs $objects->[0]->{p}->[part #]->{resp} | |
| 594 - my $part = 0; | |
| 595 - my $arrayref = $objects->[0]->{p} || $objects; | |
| 596 - if (defined $arrayref) { | |
| 597 - foreach my $cf (@{$arrayref}) { | |
| 598 - if (exists $cf->{resp}) { | |
| 599 - for (my $response=0; $response<@{$cf->{resp}}; $response++) { | |
| 600 - my $tmp = $cf->{resp}->[$response]; | |
| 601 - my $tmpcf = $tmp->{cf}; # Part confidence | |
| 602 - my $tmpct = $tmp->{ct}; # Part contested? | |
| 603 - my $engine = $cf->{sent}->[$response]->{e}; | |
| 604 - | |
| 605 - # These should always be set, but just in case ... | |
| 606 - $tmpcf = 0 unless defined $tmpcf; | |
| 607 - $tmpct = 0 unless defined $tmpct; | |
| 608 - $engine = 0 unless defined $engine; | |
| 609 - | |
| 610 - push(@results, | |
| 611 - { part => $part, engine => $engine, contested => $tmpct,
confidence => $tmpcf }); | |
| 612 - } | |
| 613 - } | |
| 614 - else { | |
| 615 - push(@results, { part => $part, noresponse => 1 }); | |
| 616 - } | |
| 617 - $part++; | |
| 618 - } | |
| 619 - } | |
| 620 - else { | |
| 621 - # If we have some new $objects format that isn't close to | |
| 622 - # the current razor-agents 2.x version, we won't FP but we | |
| 623 - # should alert in debug. | |
| 624 - dbg("$debug: it looks like the internal Razor object has changed for
mat!"); | |
| 625 - } | |
| 626 - } | |
| 627 + if ($type eq 'check') { | |
| 628 + # so $objects->[0] is the first (only) message, and ->{spam} is a gener
al yes/no | |
| 629 + push(@results, { result => $objects->[0]->{spam} }); | |
| 630 + | |
| 631 + # great for debugging, but leave this off! | |
| 632 + #use Data::Dumper; | |
| 633 + #print Dumper($objects),"\n"; | |
| 634 + | |
| 635 + # ->{p} is for each part of the message | |
| 636 + # so go through each part, taking the highest cf we find | |
| 637 + # of any part that isn't contested (ct). This helps avoid false | |
| 638 + # positives. equals logic_method 4. | |
| 639 + # | |
| 640 + # razor-agents < 2.14 have a different object format, so we now support
both. | |
| 641 + # $objects->[0]->{resp} vs $objects->[0]->{p}->[part #]->{resp} | |
| 642 + my $part = 0; | |
| 643 + my $arrayref = $objects->[0]->{p} || $objects; | |
| 644 + if (defined $arrayref) { | |
| 645 + foreach my $cf (@{$arrayref}) { | |
| 646 + if (exists $cf->{resp}) { | |
| 647 + for (my $response=0; $response<@{$cf->{resp}}; $response++) { | |
| 648 + my $tmp = $cf->{resp}->[$response]; | |
| 649 + my $tmpcf = $tmp->{cf}; # Part confidence | |
| 650 + my $tmpct = $tmp->{ct}; # Part contested? | |
| 651 + my $engine = $cf->{sent}->[$response]->{e}; | |
| 652 + | |
| 653 + # These should always be set, but just in case ... | |
| 654 + $tmpcf = 0 unless defined $tmpcf; | |
| 655 + $tmpct = 0 unless defined $tmpct; | |
| 656 + $engine = 0 unless defined $engine; | |
| 657 + | |
| 658 + push(@results, | |
| 659 + { part => $part, engine => $engine, contested => $tmpct,
confidence => $tmpcf }); | |
| 660 + } | |
| 661 + } | |
| 662 + else { | |
| 663 + push(@results, { part => $part, noresponse => 1 }); | |
| 664 + } | |
| 665 + $part++; | |
| 666 + } | |
| 667 + } | |
| 668 + else { | |
| 669 + # If we have some new $objects format that isn't close to | |
| 670 + # the current razor-agents 2.x version, we won't FP but we | |
| 671 + # should alert in debug. | |
| 672 + dbg("$debug: it looks like the internal Razor object has changed form
at!"); | |
| 673 + } | |
| 674 } | |
| 675 } | |
| 676 else { | |
| 677 warn "$debug: undefined Razor2::Client::Agent\n"; | |
| 678 } | |
| 679 | |
| 680 - if (defined $oldalarm) { | |
| 681 - alarm $oldalarm; $oldalarm = undef; | |
| 682 - } | |
| 683 - }; | |
| 684 + }); | |
| 685 + | |
| 686 + # OK, that's enough Razor stuff. now, reset all that global | |
| 687 + # state it futzes with :( | |
| 688 + # work around serious brain damage in Razor2 (constant seed) | |
| 689 + srand; | |
| 690 | |
| 691 - my $err = $@; | |
| 692 - if (defined $oldalarm) { | |
| 693 - alarm $oldalarm; $oldalarm = undef; | |
| 694 + Mail::SpamAssassin::PerMsgStatus::leave_helper_run_mode($self); | |
| 695 + | |
| 696 + if ($timer->timed_out()) { | |
| 697 + dbg("$debug: razor2 $type timed out after $timeout seconds"); | |
| 698 } | |
| 699 | |
| 700 if ($err) { | |
| 701 chomp $err; | |
| 702 - if ($err eq "__alarm__ignore__") { | |
| 703 - dbg("$debug: razor2 $type timed out after $timeout seconds"); | |
| 704 - } elsif ($err =~ /(?:could not connect|network is unreachable)/) { | |
| 705 + if ($err =~ /(?:could not connect|network is unreachable)/) { | |
| 706 # make this a dbg(); SpamAssassin will still continue, | |
| 707 # but without Razor checking. otherwise there may be | |
| 708 # DSNs and errors in syslog etc., yuck | |
| 709 @@ -323,11 +316,6 @@ | |
| 710 warn("$debug: razor2 $type failed: $! $err"); | |
| 711 } | |
| 712 } | |
| 713 - | |
| 714 - # work around serious brain damage in Razor2 (constant seed) | |
| 715 - srand; | |
| 716 - | |
| 717 - Mail::SpamAssassin::PerMsgStatus::leave_helper_run_mode($self); | |
| 718 | |
| 719 # razor also debugs to stdout. argh. fix it to stderr... | |
| 720 if (would_log('dbg', $debug)) { | |
| 721 | |
| 722 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm | |
| 723 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Plugin/SPF.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 724 ============================================================================== | |
| 725 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm (original) | |
| 726 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm Thu Mar 9 11:
51:59 2006 | |
| 727 @@ -34,6 +34,7 @@ | |
| 728 | |
| 729 use Mail::SpamAssassin::Plugin; | |
| 730 use Mail::SpamAssassin::Logger; | |
| 731 +use Mail::SpamAssassin::Timeout; | |
| 732 use strict; | |
| 733 use warnings; | |
| 734 use bytes; | |
| 735 @@ -300,30 +301,17 @@ | |
| 736 | |
| 737 my ($result, $comment); | |
| 738 my $timeout = $scanner->{conf}->{spf_timeout}; | |
| 739 - my $oldalarm = 0; | |
| 740 | |
| 741 - eval { | |
| 742 - local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 743 - local $SIG{__DIE__}; # bug 4631 | |
| 744 - $oldalarm = alarm($timeout); | |
| 745 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); | |
| 746 + my $err = $timer->run_and_catch(sub { | |
| 747 + | |
| 748 ($result, $comment) = $query->result(); | |
| 749 - if (defined $oldalarm) { | |
| 750 - alarm $oldalarm; $oldalarm = undef; | |
| 751 - } | |
| 752 - }; | |
| 753 | |
| 754 - my $err = $@; | |
| 755 - if (defined $oldalarm) { | |
| 756 - alarm $oldalarm; $oldalarm = undef; | |
| 757 - } | |
| 758 + }); | |
| 759 | |
| 760 if ($err) { | |
| 761 chomp $err; | |
| 762 - if ($err eq "__alarm__ignore__") { | |
| 763 - dbg("spf: lookup timed out after $timeout seconds"); | |
| 764 - } else { | |
| 765 - warn("spf: lookup failed: $err\n"); | |
| 766 - } | |
| 767 + warn("spf: lookup failed: $err\n"); | |
| 768 return 0; | |
| 769 } | |
| 770 | |
| 771 | |
| 772 Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm | |
| 773 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/SpamdForkScaling.pm?rev=384590&r1=384589&r2=384590&view=diff | |
| 774 ============================================================================== | |
| 775 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm (origina
l) | |
| 776 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/SpamdForkScaling.pm Thu Mar
9 11:51:59 2006 | |
| 777 @@ -25,6 +25,7 @@ | |
| 778 | |
| 779 use Mail::SpamAssassin::Util; | |
| 780 use Mail::SpamAssassin::Logger; | |
| 781 +use Mail::SpamAssassin::Timeout; | |
| 782 | |
| 783 use vars qw { | |
| 784 @PFSTATE_VARS %EXPORT_TAGS @EXPORT_OK | |
| 785 @@ -109,6 +110,9 @@ | |
| 786 | |
| 787 delete $self->{kids}->{$pid}; | |
| 788 | |
| 789 + # note this for the select()-caller's benefit | |
| 790 + $self->{child_just_exited} = 1; | |
| 791 + | |
| 792 # remove the child from the backchannel list, too | |
| 793 $self->{backchannel}->delete_socket_for_child($pid); | |
| 794 | |
| 795 @@ -188,24 +192,63 @@ | |
| 796 vec($rin, $self->{server_fileno}, 1) = 0; | |
| 797 } | |
| 798 | |
| 799 - my ($rout, $eout, $nfound, $timeleft); | |
| 800 + my ($rout, $eout, $nfound, $timeleft, $selerr); | |
| 801 + | |
| 802 + # use alarm to back up select()'s built-in alarm, to debug Theo's bug. | |
| 803 + # not that I can remember what Theo's bug was, but hey ;) A good | |
| 804 + # 60 seconds extra on the alarm() should make that quite rare... | |
| 805 + | |
| 806 + my $timer = Mail::SpamAssassin::Timeout->new({ secs => ($tout*2) + 60 }); | |
| 807 | |
| 808 - # use alarm to back up select()'s built-in alarm, to debug theo's bug | |
| 809 - eval { | |
| 810 - Mail::SpamAssassin::Util::trap_sigalrm_fully(sub { die "tcp timeout"; }); | |
| 811 - alarm ($tout*2) if ($tout); | |
| 812 + $timer->run(sub { | |
| 813 + | |
| 814 + $self->{child_just_exited} = 0; | |
| 815 ($nfound, $timeleft) = select($rout=$rin, undef, $eout=$rin, $tout); | |
| 816 - }; | |
| 817 - alarm 0; | |
| 818 + $selerr = $!; | |
| 819 | |
| 820 - if ($@) { | |
| 821 - warn "prefork: select timeout failed! recovering\n"; | |
| 822 - sleep 1; # avoid overload | |
| 823 - return; | |
| 824 - } | |
| 825 + }); | |
| 826 + | |
| 827 + # bug 4696: under load, the process can go for such a long time without | |
| 828 + # being context-switched in, that when it does return the alarm() fires | |
| 829 + # before the select() timeout does. Treat this as a select() timeout | |
| 830 + if ($timer->timed_out) { | |
| 831 + dbg("prefork: select timed out (via alarm)"); | |
| 832 + $nfound = 0; | |
| 833 + $timeleft = 0; | |
| 834 + } | |
| 835 + | |
| 836 + # errors; handle undef *or* -1 returned. do this before "errors on | |
| 837 + # the handle" below, since an error condition is signalled both via | |
| 838 + # a -1 return and a $eout bit. | |
| 839 + if (!defined $nfound || $nfound < 0) | |
| 840 + { | |
| 841 + if (exists &Errno::EINTR && $selerr == &Errno::EINTR) | |
| 842 + { | |
| 843 + # this happens if the process is signalled during the select(), | |
| 844 + # for example if someone sends SIGHUP to reload the configuration. | |
| 845 + # just return inmmediately | |
| 846 + dbg("prefork: select returned err $selerr, probably signalled"); | |
| 847 + return; | |
| 848 + } | |
| 849 + | |
| 850 + # if a child exits during that select() call, it generates a spurious | |
| 851 + # error, like this: | |
| 852 + # | |
| 853 + # Jan 29 12:53:17 dogma spamd[18518]: prefork: child states: BI | |
| 854 + # Jan 29 12:53:17 dogma spamd[18518]: spamd: handled cleanup of child pid 1
3101 due to SIGCHLD | |
| 855 + # Jan 29 12:53:17 dogma spamd[18518]: prefork: select returned -1! recoveri
ng: | |
| 856 + # | |
| 857 + # avoid by setting a boolean in the child_exited() callback and checking | |
| 858 + # it here. log $! just in case, though. | |
| 859 + if ($self->{child_just_exited} && $nfound == -1) { | |
| 860 + dbg("prefork: select returned -1 due to child exiting, ignored ($selerr)"
); | |
| 861 + return; | |
| 862 + } | |
| 863 + | |
| 864 + warn "prefork: select returned ". | |
| 865 + (defined $nfound ? $nfound : "undef"). | |
| 866 + "! recovering: $selerr\n"; | |
| 867 | |
| 868 - if (!defined $nfound) { | |
| 869 - warn "prefork: select returned undef! recovering\n"; | |
| 870 sleep 1; # avoid overload | |
| 871 return; | |
| 872 } | |
| 873 @@ -213,7 +256,7 @@ | |
| 874 # errors on the handle? | |
| 875 # return them immediately, they may be from a SIGHUP restart signal | |
| 876 if (vec ($eout, $self->{server_fileno}, 1)) { | |
| 877 - warn "prefork: select returned error on server filehandle: $!\n"; | |
| 878 + warn "prefork: select returned error on server filehandle: $selerr $!\n"; | |
| 879 return; | |
| 880 } | |
| 881 | |
| 882 @@ -282,7 +325,7 @@ | |
| 883 | |
| 884 my ($sock, $kid); | |
| 885 while (($kid, $sock) = each %{$self->{backchannel}->{kids}}) { | |
| 886 - $self->syswrite_with_retry($sock, PF_PING_ORDER) and next; | |
| 887 + $self->syswrite_with_retry($sock, PF_PING_ORDER, $kid, 3) and next; | |
| 888 | |
| 889 warn "prefork: write of ping failed to $kid fd=".$sock->fileno.": ".$!; | |
| 890 | |
| 891 @@ -353,7 +396,7 @@ | |
| 892 return $self->order_idle_child_to_accept(); | |
| 893 } | |
| 894 | |
| 895 - if (!$self->syswrite_with_retry($sock, PF_ACCEPT_ORDER)) | |
| 896 + if (!$self->syswrite_with_retry($sock, PF_ACCEPT_ORDER, $kid)) | |
| 897 { | |
| 898 # failure to write to the child; bad news. call it dead | |
| 899 warn "prefork: killing rogue child $kid, failed to write on fd ".$sock->f
ileno.": $!\n"; | |
| 900 @@ -396,7 +439,7 @@ | |
| 901 my ($self, $kid) = @_; | |
| 902 if ($self->{waiting_for_idle_child}) { | |
| 903 my $sock = $self->{backchannel}->get_socket_for_child($kid); | |
| 904 - $self->syswrite_with_retry($sock, PF_ACCEPT_ORDER) | |
| 905 + $self->syswrite_with_retry($sock, PF_ACCEPT_ORDER, $kid) | |
| 906 or die "prefork: $kid claimed it was ready, but write failed on fd ". | |
| 907 $sock->fileno.": ".$!; | |
| 908 $self->{waiting_for_idle_child} = 0; | |
| 909 @@ -426,7 +469,7 @@ | |
| 910 sub report_backchannel_socket { | |
| 911 my ($self, $str) = @_; | |
| 912 my $sock = $self->{backchannel}->get_parent_socket(); | |
| 913 - $self->syswrite_with_retry($sock, $str) | |
| 914 + $self->syswrite_with_retry($sock, $str, 'parent') | |
| 915 or write "syswrite() to parent failed: $!"; | |
| 916 } | |
| 917 | |
| 918 @@ -537,12 +580,31 @@ | |
| 919 } | |
| 920 | |
| 921 sub syswrite_with_retry { | |
| 922 - my ($self, $sock, $buf) = @_; | |
| 923 + my ($self, $sock, $buf, $targetname, $numretries) = @_; | |
| 924 + $numretries ||= 10; # default 10 retries | |
| 925 | |
| 926 my $written = 0; | |
| 927 + my $try = 0; | |
| 928 | |
| 929 retry_write: | |
| 930 + | |
| 931 + $try++; | |
| 932 + if ($try > 1) { | |
| 933 + warn "prefork: syswrite(".$sock->fileno.") to $targetname failed on try $tr
y"; | |
| 934 + if ($try > $numretries) { | |
| 935 + warn "prefork: giving up"; | |
| 936 + return undef; | |
| 937 + } | |
| 938 + else { | |
| 939 + # give it 1 second to recover. we retry indefinitely. | |
| 940 + my $rout = ''; | |
| 941 + vec($rout, $sock->fileno, 1) = 1; | |
| 942 + select(undef, $rout, undef, 1); | |
| 943 + } | |
| 944 + } | |
| 945 + | |
| 946 my $nbytes = $sock->syswrite($buf); | |
| 947 + | |
| 948 if (!defined $nbytes) { | |
| 949 unless ((exists &Errno::EAGAIN && $! == &Errno::EAGAIN) | |
| 950 || (exists &Errno::EWOULDBLOCK && $! == &Errno::EWOULDBLOCK)) | |
| 951 @@ -551,13 +613,7 @@ | |
| 952 return undef; | |
| 953 } | |
| 954 | |
| 955 - warn "prefork: syswrite(".$sock->fileno.") failed, retrying..."; | |
| 956 - | |
| 957 - # give it 5 seconds to recover. we retry indefinitely. | |
| 958 - my $rout = ''; | |
| 959 - vec($rout, $sock->fileno, 1) = 1; | |
| 960 - select(undef, $rout, undef, 5); | |
| 961 - | |
| 962 + warn "prefork: retrying syswrite(): $!"; | |
| 963 goto retry_write; | |
| 964 } | |
| 965 else { | |
| 966 @@ -568,7 +624,8 @@ | |
| 967 return $written; # it's complete, we can return | |
| 968 } | |
| 969 else { | |
| 970 - warn "prefork: partial write of $nbytes, towrite=".length($buf). | |
| 971 + warn "prefork: partial write of $nbytes to ". | |
| 972 + $targetname.", towrite=".length($buf). | |
| 973 " sofar=".$written." fd=".$sock->fileno.", recovering"; | |
| 974 goto retry_write; | |
| 975 } | |
| 976 | |
| 977 Added: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm | |
| 978 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/lib/Mail/SpamAssass
in/Timeout.pm?rev=384590&view=auto | |
| 979 ============================================================================== | |
| 980 --- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm (added) | |
| 981 +++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Timeout.pm Thu Mar 9 11:51:
59 2006 | |
| 982 @@ -0,0 +1,215 @@ | |
| 983 +# <@LICENSE> | |
| 984 +# Copyright 2004 Apache Software Foundation | |
| 985 +# | |
| 986 +# Licensed under the Apache License, Version 2.0 (the "License"); | |
| 987 +# you may not use this file except in compliance with the License. | |
| 988 +# You may obtain a copy of the License at | |
| 989 +# | |
| 990 +# http://www.apache.org/licenses/LICENSE-2.0 | |
| 991 +# | |
| 992 +# Unless required by applicable law or agreed to in writing, software | |
| 993 +# distributed under the License is distributed on an "AS IS" BASIS, | |
| 994 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 995 +# See the License for the specific language governing permissions and | |
| 996 +# limitations under the License. | |
| 997 +# </@LICENSE> | |
| 998 + | |
| 999 +=head1 NAME | |
| 1000 + | |
| 1001 +Mail::SpamAssassin::Timeout - safe, reliable timeouts in perl | |
| 1002 + | |
| 1003 +=head1 SYNOPSIS | |
| 1004 + | |
| 1005 + # non-timeout code... | |
| 1006 + | |
| 1007 + my $t = Mail::SpamAssassin::Timeout->new({ secs => 5 }); | |
| 1008 + | |
| 1009 + $t->run(sub { | |
| 1010 + # code to run with a 5-second timeout... | |
| 1011 + }); | |
| 1012 + | |
| 1013 + if ($t->timed_out()) { | |
| 1014 + # do something... | |
| 1015 + } | |
| 1016 + | |
| 1017 + # more non-timeout code... | |
| 1018 + | |
| 1019 +=head1 DESCRIPTION | |
| 1020 + | |
| 1021 +This module provides a safe, reliable and clean API to provide | |
| 1022 +C<alarm(2)>-based timeouts for perl code. | |
| 1023 + | |
| 1024 +Note that C<$SIG{ALRM}> is used to provide the timeout, so this will not | |
| 1025 +interrupt out-of-control regular expression matches. | |
| 1026 + | |
| 1027 +Nested timeouts are supported. | |
| 1028 + | |
| 1029 +=head1 PUBLIC METHODS | |
| 1030 + | |
| 1031 +=over 4 | |
| 1032 + | |
| 1033 +=cut | |
| 1034 + | |
| 1035 +package Mail::SpamAssassin::Timeout; | |
| 1036 + | |
| 1037 +use strict; | |
| 1038 +use warnings; | |
| 1039 +use bytes; | |
| 1040 + | |
| 1041 +use vars qw{ | |
| 1042 + @ISA | |
| 1043 +}; | |
| 1044 + | |
| 1045 +@ISA = qw(); | |
| 1046 + | |
| 1047 +########################################################################### | |
| 1048 + | |
| 1049 +=item my $t = Mail::SpamAssassin::Timeout->new({ ... options ... }); | |
| 1050 + | |
| 1051 +Constructor. Options include: | |
| 1052 + | |
| 1053 +=over 4 | |
| 1054 + | |
| 1055 +=item secs => $seconds | |
| 1056 + | |
| 1057 +timeout, in seconds. Optional; if not specified, no timeouts will be applied. | |
| 1058 + | |
| 1059 +=back | |
| 1060 + | |
| 1061 +=cut | |
| 1062 + | |
| 1063 +sub new { | |
| 1064 + my ($class, $opts) = @_; | |
| 1065 + $class = ref($class) || $class; | |
| 1066 + my %selfval = $opts ? %{$opts} : (); | |
| 1067 + my $self = \%selfval; | |
| 1068 + | |
| 1069 + bless ($self, $class); | |
| 1070 + $self; | |
| 1071 +} | |
| 1072 + | |
| 1073 +########################################################################### | |
| 1074 + | |
| 1075 +=item $t->run($coderef) | |
| 1076 + | |
| 1077 +Run a code reference within the currently-defined timeout. | |
| 1078 + | |
| 1079 +The timeout is as defined by the B<secs> parameter to the constructor. | |
| 1080 + | |
| 1081 +Returns whatever the subroutine returns, or C<undef> on timeout. | |
| 1082 +If the timer times out, C<$t-<gt>timed_out()> will return C<1>. | |
| 1083 + | |
| 1084 +Time elapsed is not cumulative; multiple runs of C<run> will restart the | |
| 1085 +timeout from scratch. | |
| 1086 + | |
| 1087 +=item $t->run_and_catch($coderef) | |
| 1088 + | |
| 1089 +Run a code reference, as per C<$t-<gt>run()>, but also catching any | |
| 1090 +C<die()> calls within the code reference. | |
| 1091 + | |
| 1092 +Returns C<undef> if no C<die()> call was executed and C<$@> was unset, or the | |
| 1093 +value of C<$@> if it was set. (The timeout event doesn't count as a C<die()>.) | |
| 1094 + | |
| 1095 +=cut | |
| 1096 + | |
| 1097 +sub run { $_[0]->_run($_[1], 0); } | |
| 1098 + | |
| 1099 +sub run_and_catch { $_[0]->_run($_[1], 1); } | |
| 1100 + | |
| 1101 +sub _run { # private | |
| 1102 + my ($self, $sub, $and_catch) = @_; | |
| 1103 + | |
| 1104 + delete $self->{timed_out}; | |
| 1105 + | |
| 1106 + if (!$self->{secs}) { # no timeout! just call the sub and return. | |
| 1107 + return &$sub; | |
| 1108 + } | |
| 1109 + | |
| 1110 + # assertion | |
| 1111 + if ($self->{secs} < 0) { | |
| 1112 + die "Mail::SpamAssassin::Timeout: oops? neg value for 'secs': $self->{secs}
"; | |
| 1113 + } | |
| 1114 + | |
| 1115 + my $oldalarm = 0; | |
| 1116 + my $ret; | |
| 1117 + | |
| 1118 + eval { | |
| 1119 + # note use of local to ensure closed scope here | |
| 1120 + local $SIG{ALRM} = sub { die "__alarm__ignore__\n" }; | |
| 1121 + local $SIG{__DIE__}; # bug 4631 | |
| 1122 + | |
| 1123 + $oldalarm = alarm($self->{secs}); | |
| 1124 + | |
| 1125 + $ret = &$sub; | |
| 1126 + | |
| 1127 + # Unset the alarm() before we leave eval{ } scope, as that stack-pop | |
| 1128 + # operation can take a second or two under load. Note: previous versions | |
| 1129 + # restored $oldalarm here; however, that is NOT what we want to do, since | |
| 1130 + # it creates a new race condition, namely that an old alarm could then fire | |
| 1131 + # while the stack-pop was underway, thereby appearing to be *this* timeout | |
| 1132 + # timing out. In terms of how we might possibly have nested timeouts in | |
| 1133 + # SpamAssassin, this is an academic issue with little impact, but it's | |
| 1134 + # still worth avoiding anyway. | |
| 1135 + | |
| 1136 + alarm 0; | |
| 1137 + }; | |
| 1138 + | |
| 1139 + my $err = $@; | |
| 1140 + | |
| 1141 + if (defined $oldalarm) { | |
| 1142 + # now, we could have died from a SIGALRM == timed out. if so, | |
| 1143 + # restore the previously-active one, or zero all timeouts if none | |
| 1144 + # were previously active. | |
| 1145 + alarm $oldalarm; | |
| 1146 + } | |
| 1147 + | |
| 1148 + if ($err) { | |
| 1149 + if ($err =~ /__alarm__ignore__/) { | |
| 1150 + $self->{timed_out} = 1; | |
| 1151 + } else { | |
| 1152 + if ($and_catch) { | |
| 1153 + return $@; | |
| 1154 + } else { | |
| 1155 + die $@; # propagate any "real" errors | |
| 1156 + } | |
| 1157 + } | |
| 1158 + } | |
| 1159 + | |
| 1160 + if ($and_catch) { | |
| 1161 + return; # undef | |
| 1162 + } else { | |
| 1163 + return $ret; | |
| 1164 + } | |
| 1165 +} | |
| 1166 + | |
| 1167 +########################################################################### | |
| 1168 + | |
| 1169 +=item $t->timed_out() | |
| 1170 + | |
| 1171 +Returns C<1> if the most recent code executed in C<run()> timed out, or | |
| 1172 +C<undef> if it did not. | |
| 1173 + | |
| 1174 +=cut | |
| 1175 + | |
| 1176 +sub timed_out { | |
| 1177 + my ($self) = @_; | |
| 1178 + return $self->{timed_out}; | |
| 1179 +} | |
| 1180 + | |
| 1181 +########################################################################### | |
| 1182 + | |
| 1183 +=item $t->reset() | |
| 1184 + | |
| 1185 +If called within a C<run()> code reference, causes the current alarm timer to | |
| 1186 +be reset to its starting value. | |
| 1187 + | |
| 1188 +=cut | |
| 1189 + | |
| 1190 +sub reset { | |
| 1191 + my ($self) = @_; | |
| 1192 + alarm($self->{secs}); | |
| 1193 +} | |
| 1194 + | |
| 1195 +########################################################################### | |
| 1196 + | |
| 1197 +1; | |
| 1198 | |
| 1199 Modified: spamassassin/branches/3.1/spamd/spamd.raw | |
| 1200 URL: http://svn.apache.org/viewcvs/spamassassin/branches/3.1/spamd/spamd.raw?rev
=384590&r1=384589&r2=384590&view=diff | |
| 1201 ============================================================================== | |
| 1202 --- spamassassin/branches/3.1/spamd/spamd.raw (original) | |
| 1203 +++ spamassassin/branches/3.1/spamd/spamd.raw Thu Mar 9 11:51:59 2006 | |
| 1204 @@ -2049,6 +2049,9 @@ | |
| 1205 foreach (keys %children) { | |
| 1206 kill 'INT' => $_; | |
| 1207 my $pid = waitpid($_, 0); | |
| 1208 + if ($scaling) { | |
| 1209 + $scaling->child_exited($pid); | |
| 1210 + } | |
| 1211 info("spamd: child $pid killed successfully"); | |
| 1212 } | |
| 1213 %children = (); | |
| 1214 | |
| 1215 | |
| 1216 | |
| 1217 | |
| 1218 | |
| OLD | NEW |