MonkeyMonk has asked for the wisdom of the Perl Monks concerning the following question:

> perl -v 5.8.4

Dear monks, On a production system where updates to Perl versions are not possible, I came across this SIG{ALRM} robber. Yes, dear monks, LWP stands accused. My question: can I go to bed with this robber?

Consider this code:
eval { local $SIG{ALRM} = sub { die "Network Timeout/Error\n" }; alarm($maxNetworkDelay); $ip=URL_encode($ip); $encodedMAC=URL_encode($mac); my $macr="https://somescript/login; $request = HTTP::Request->new(GET => $macr); $ua = LWP::UserAgent->new( timeout => $maxNetworkDelay ); $response = $ua->request($request); $respcon = $response->content; alarm(0); }; <strike> if($@){ ilog("Network Delay/Error for ."); return (-1); }# </strike> if($response->status_line =~ /^500/ ){ ilog("Network Delay/Error for ."); return (-1); }

I have read whatever there is publicly and from what I understood, decided to write the above since DNS errors/network latency/wrong domain name are _ALL_ trapped by the above code.

As you can see, when using eval with LWP, _your_ error catching mechanism ( the parts struck out ) will not work since LWP internally has a mechanism of its own. What we can test, however is whether LWP has caught the alarm I have triggered.

I am seeking to understand the what is going on. The above code works all the time to satisfaction. My questions are:

  • 1. It looks like a process can have only one SIG{ALRM}
  • 2. An alarm set is caught by the whatever alarm handling mechanism that is in scope - in our case, the alarm handling mechanism in LWP.
  • 3. Once caught. $@ is read, handled, and reset.
  • 4. Finally,do the monks approve of this?
  • Replies are listed 'Best First'.
    Re: The curious case of LWP - the SIG{ALRM} robber
    by ikegami (Patriarch) on Jul 05, 2010 at 18:04 UTC
      I just searched through the latest LWP and IO::Socket, and I couldn't find any mentioned of alarm. They use select now. You could upgrade those, or get rid of timeout => $maxNetworkDelay.

      It looks like a process can have only one SIG{ALRM}

      Signals are sent to processes, so you can't have two alarms going.

      An alarm set is caught by the whatever alarm handling mechanism that is in scope - in our case, the alarm handling mechanism in LWP.

      The alarm handler is global, so "in scope" makes no sense. An alarm signal is handled by the specified alarm handler, if any. (The process is killed otherwise.) In your case, LWP sets the alarm handler last.

      Once caught. $@ is read, handled, and reset.

      I don't know what you mean by that.

    Re: The curious case of LWP - the SIG{ALRM} robber
    by Khen1950fx (Canon) on Jul 06, 2010 at 00:22 UTC
      I took your sample and experimented with it.
      #!/usr/bin/perl use strict; use warnings; use LWP::UserAgent; my $mac = 'http://www.perlmonks.org/?node_id=848086'; eval { do { my $request = HTTP::Request->new( GET => $mac ); my $ua = LWP::UserAgent->new; $ua->timeout(30); $ua->env_proxy; my $response = $ua->request($request); if ( $response->is_success ) { print $response->decoded_content; } else { print $response->status_line, "\n"; } }; }
      Update: I took out $SIG{ALRM}. It didn't work and seemed unnecessary. Added print to status_line and timeout. "status_line' works better.
        Can you try it with say:

      • a non-existent IP
      • a wrong fqdn
      • a very slow server
      • Setting timeout to say 10 without the Alarm for userAgent object will have no effect. This is I think is valid for 5.8.4