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
Download (untitled) / with headers
text/plain 872b
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
Download client.pl
text/x-perl 490b
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
Download sleepy_server.pl
text/x-perl 1.7k
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'); }
Download (untitled) / with headers
text/plain 1.7k
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.


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.