Skip Menu |

This queue is for tickets about the libnet CPAN distribution.

Report information
The Basics
Id: 115025
Status: open
Priority: 0/
Queue: libnet

People
Owner: Nobody in particular
Requestors: BJAKUBSKI [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 3.08
Fixed in: (no value)



Subject: Net::SMTP (or rather Cmd?) does not handle interrupted system calls
When one of system calls (select, sysread) is interrupted by SIGCHLD Net::SMTP does not retry it and simply fails. It seems there was work done to fix that problem for syswrite already in https://github.com/steve-m-hay/perl-libnet/pull/24 but other system calls are still broken. This resulted in rare, non-deterministic failures in our email-sending program. I believe this issue is behind problems "upstream" like this: https://rt.cpan.org/Ticket/Display.html?id=43104 Attached: * sleepy_server.pl - sleeps for 10 seconds before acknowledging that it received "\r\n.\r\n". It listens on localhos:9025 * client.pl - which installs SIGCHLD handler and forks a child process that only sleeps for 2 seconds and then attempts to send email via localhost:9025 In this setup SIGCHLD is delivered when Net::Cmd is performing select() call and thus select fails with EINTR
Subject: client.pl
use strict; use Net::SMTP; $SIG{CHLD} = sub { warn "GOT SIGCHLD" }; if ( fork() ) { } else { sleep 2; exit 0; } my $smtp = Net::SMTP->new('localhost', Port => 9025, Debug => 1); $smtp->mail("foobar"); $smtp->to('postmaster'); $smtp->data(); $smtp->datasend("To: postmaster\n"); $smtp->datasend("\n"); $smtp->datasend("A simple test message\n"); # Server is configured to sleep 10 seconds before replying $smtp->dataend() or die "DATAEND failed: ".$smtp->message; $smtp->quit;
Subject: sleepy_server.pl
use strict; use Net::Server::Mail::SMTP; use IO::Socket::INET; my $server = new IO::Socket::INET Listen => 1, LocalPort => 9025; warn "Listening on port 9025\n"; my $conn; while ($conn = $server->accept) { warn "Connected to: ",$conn->peerhost(),"\n"; my $smtpd = new Net::Server::Mail::SMTP socket => $conn; $smtpd->set_callback('banner' => \&banner); $smtpd->set_callback('HELO' => \&helo); $smtpd->set_callback('MAIL' => \&mail); $smtpd->set_callback('RCPT' => \&rcpt); $smtpd->set_callback('DATA-INIT' => \&data_init); $smtpd->set_callback('DATA-PART' => \&data_part); $smtpd->set_callback('DATA' => \&data_end); $smtpd->set_callback('QUIT' => \&quit); warn "Entering SMTP processing loop...\n"; $smtpd->process; # cleanup $smtpd = undef; $conn = undef; } exit(0); ## subs sub banner { my $session = shift; warn "CMD: banner\n"; return(0, 220, '[A] sleepy-server'); } sub helo { my $session = shift; my $hostname = shift; warn "CMD: helo $hostname\n"; return (1,250, "[B] helo $hostname"); } sub mail { my $session = shift; my $address = shift; warn "CMD: mail from $address\n"; return (1, 250, "[C] mail from $address"); } sub rcpt { my $session = shift; my $address = shift; warn "CMD: rcpt to $address\n"; return (1, 250, "[D] rcpt to $address"); } sub data_init { my $session = shift; warn "CMD: data_init\n"; return (1, 354, '[E] data_init'); } sub data_part { my $session = shift; my $chunk = shift; # ref to buffer warn "CMD: data_part\n"; return (1); } sub data_end { my $session = shift; warn "CMD: data_end\n"; # # Sleepy part # sleep 10; return (1, 250, '[F] data_end'); } sub quit { my $session = shift; warn "CMD: quit\n"; return (1, 221, '[G] quit'); }
On Fri Jun 03 04:39:33 2016, BJAKUBSKI wrote: Show quoted text
> When one of system calls (select, sysread) is interrupted by SIGCHLD > Net::SMTP does not retry it and simply fails. > > It seems there was work done to fix that problem for syswrite already > in https://github.com/steve-m-hay/perl-libnet/pull/24 but other system > calls are still broken. > > This resulted in rare, non-deterministic failures in our email-sending > program. > I believe this issue is behind problems "upstream" like this: > https://rt.cpan.org/Ticket/Display.html?id=43104 > > Attached: > * sleepy_server.pl - sleeps for 10 seconds before acknowledging that > it received "\r\n.\r\n". It listens on localhos:9025 > * client.pl - which installs SIGCHLD handler and forks a child process > that only sleeps for 2 seconds and then attempts to send email via > localhost:9025 > > In this setup SIGCHLD is delivered when Net::Cmd is performing > select() call and thus select fails with EINTR
It would seem that my team has also encountered this issue. We've spent a bit of time analyzing networking traffic and reducing the error to an interrupted system call when sending an email using MIME::Lite. Our particular issue is being instigated on a network where backpressure in the email system is delaying our SMTP protocol response from the email server, then a subsequent signal interruption happens sporadically in our perl process and the email exchange terminates unexpectedly. I've made a PR that mimics the prior work to make syswrite retryable under the EINTR condition: https://github.com/steve-m-hay/perl-libnet/pull/30 The above PR makes the test case included in this RT function correctly, that made things easier having that, thanks. Looking for feedback in the PR if any.
PR#30 has been (belatedly!) merged so please have a look (either in Github now, or else in the next release (3.12)) to see whether this issue is now fixed.