Subject: | Mail-IMAPClient-2.2.9 and broken connections |
Date: | Wed, 14 Nov 2007 17:23:10 +0100 |
To: | bug-Mail-IMAPClient [...] rt.cpan.org |
From: | Bernd Petrovitsch <bernd [...] firmix.at> |
Hi!
We are using Mail-IMAPClient-2.2.9 on a Debian/Sarge on x86_64
hardware. We use it against Cyrus-Imapd-2.2.13 where user
mailboxes are stored.
Every user has a "spam" folder there and a janitor
job removes every night old enough spam mails and sends
the user a overview of the remaining.
What happens as seen from the outside?
Once in a while the janitor job busy loops on broken
IMAP connections and stracing the process gives
---- snip ----
write(12, "5378 SELECT user/91070z2/Spam\r\n", 31) = -1 EPIPE (Broken pipe)
--- SIGPIPE (Broken pipe) @ 0 (0) ---
write(12, "5378 SELECT user/91070z2/Spam\r\n", 31) = -1 EPIPE (Broken pipe)
--- SIGPIPE (Broken pipe) @ 0 (0) ---
write(12, "5378 SELECT user/91070z2/Spam\r\n", 31) = -1 EPIPE (Broken pipe)
--- SIGPIPE (Broken pipe) @ 0 (0) ---
write(12, "5378 SELECT user/91070z2/Spam\r\n", 31) = -1 EPIPE (Broken pipe)
--- SIGPIPE (Broken pipe) @ 0 (0) ---
---- snip ----
(and fast of course!).
We have (for various reasons and routinely) SIGPIPE ignored (as the
strace above also tells).
And AFAICS we check for errors on every possibility in our application
code. Following into the Mail-IMAPClient module, I come to the "sub
_send_line" at line 1372 and find some strange (IMHO of course) code on
line 1458:
---- snip ----
1458 until ($total >= length($string)) {
1459 my $ret = 0;
1460 $!=0;
1461 $ret = syswrite(
1462 $self->Socket,
1463 $string,
1464 length($string)-$total,
1465 $total
1466 );
1467 $ret||=0;
1468 if ($! == &EAGAIN ) {
1469 if ( $self->{Maxtemperrors} !~ /^unlimited/i
1470 and $temperrs++ > ($self->{Maxtemperrors}||10)
1471 ) {
1472 $self->LastError("Persistent '${!}' errors\n");
1473 $self->_debug("Persistent '${!}' errors\n")
1474 return undef;
1475 }
1476 $optimize = 1;
1477 } else {
1478 # avoid infinite loops on syswrite error
1479 return undef unless(defined $ret);
1480 }
---- snip ----
What happens more in detail here?
- syswrite() is called and returns "undef" (stored in $ret) and sets $!.
- line 1467: '$ret = 0'
- $! is &EPIPE so we take the "else" branch.
- But here we are not returning because $ret is defined - it has
0 in there.
What is IMHO strange?
- The "unless(defined $ret)" seems wrong to me since $ret will always
be defined there - either by the return value of syswrite() - but
then we shouldn't get there anyways - and otherwise through line
1467.
Are we the first ones which ignore SIGPIPE to stumble over that?
Did I overlook something?
Alas, testing and tracing is not really or easily possible since the
system and application in question has around 23.000 mailboxes ATM and
is the central mail server of a medium sized Austrian ISP (medium sized
for Austrian circumstances).
The short term work-around is to enable SIGPIPE at that end so that the
process vanishes (and can be consequently restarted).
Bernd
--
Firmix Software GmbH http://www.firmix.at/
mobil: +43 664 4416156 fax: +43 1 7890849-55
Embedded Linux Development and Services