Subject: | SIGPIPE is not trapped for calls to syswrite() |
Date: | Wed, 18 Feb 2009 17:27:11 -0500 |
To: | bug-Mail-IMAPClient [...] rt.cpan.org |
From: | Phil Lobbes <phil [...] perkpartners.com> |
Mail::IMAPClient 3.x (and 2.x) can sometimes exit quietly because under
certain conditions a SIGPIPE may be raised that is not trapped by the
library.
In theory, there are likely only a few places in the code when this
might happen so the a patch is pretty straight forward. The most
obvious handling is to ignore SIGPIPE and let the application handle
EPIPE errors in other more "normal" ways.
The UNIX Socket FAQ recommendation is to ignore SIGPIPE and to handle
errno values ($! for Perl) instead.
Reference:
#2.19 of comp.unix.programmer Unix-socket-faq for network programming
http://www.faqs.org/faqs/unix-faq/socket/
Below is a patch against Mail::IMAPClient 3.14 which affects migrate()
and _send_bytes(). I am still in the process of doing my own testing,
but I suspect this patch should be sufficient to cover the cases I have
seen.
There is also one minor (related) fix where LastError was using $@
instead of $! when reporting an error on sending a command.
Phil
--- IMAPClient.pm.ORIG 2009-02-16 08:15:52.000000000 -0500
+++ IMAPClient.pm 2009-02-18 17:10:48.000000000 -0500
@@ -19,7 +19,7 @@
use Carp qw(carp);
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
-use Errno qw/EAGAIN/;
+use Errno qw/EAGAIN EPIPE/;
use List::Util qw/first min max sum/;
use MIME::Base64;
use File::Spec ();
@@ -679,6 +679,8 @@
my $fromSock = $self->Socket;
my $bufferSize = $self->Buffer || 4096;
+ local $SIG{PIPE} = "IGNORE"; # avoid SIGPIPE on syswrite
+
unless(eval {$peer->IsConnected} )
{ $self->LastError("Invalid or unconnected " . ref($self)
. " object used as target for migrate. $@");
@@ -872,6 +874,10 @@
$temperrs = 0;
}
+ if($! == EPIPE)
+ { $self->LastError("Error sending data to server: $!");
+ return undef;
+ }
if($! == EAGAIN || $ret==0)
{ if(defined $maxagain && $temperrs++ > $maxagain)
{ $self->LastError("Persistent '$!' errors");
@@ -916,9 +922,13 @@
# Now let's send a <CR><LF> to the peer to signal end of APPEND cmd:
{ my $wroteSoFar = 0;
my $fromBuffer = "\r\n";
- $wroteSoFar += syswrite($toSock,$fromBuffer,2-$wroteSoFar,$wroteSoFar)||0
- until $wroteSoFar >= 2;
-
+ until($wroteSoFar >= 2) {
+ $wroteSoFar += syswrite($toSock,$fromBuffer,2-$wroteSoFar,$wroteSoFar)||0;
+ if($! == EPIPE)
+ { $self->LastError("Error sending data to server: $!");
+ return undef;
+ }
+ }
}
# Finally, let's get the new message's UID from the peer:
@@ -1258,6 +1268,8 @@
my $maxagain = $self->Maxtemperrors || 10;
undef $maxagain if $maxagain eq 'unlimited';
+ local $SIG{PIPE} = "IGNORE"; # avoid SIGPIPE on syswrite
+
while($total < length $$byteref)
{ my $written = syswrite($self->Socket, $$byteref, length($$byteref)-$total,
$total);
@@ -2345,7 +2357,7 @@
my $bytes = $self->_send_line($command.$text."\r\n");
unless(defined $bytes)
- { $self->LastError("Error sending command '$command': $@");
+ { $self->LastError("Error sending command '$command': $!");
return undef;
}