Skip Menu |

This queue is for tickets about the IO-Socket-IP CPAN distribution.

Report information
The Basics
Id: 98976
Status: resolved
Priority: 0/
Queue: IO-Socket-IP

People
Owner: Nobody in particular
Requestors: pete.a64 [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.32
Fixed in: 0.33



Subject: Fix for IO-Socket-IP-0.32 22timeout.t failure on WIn32
my $client = IO::Socket::IP->new( PeerHost => $server->sockhost, PeerPort => $server->sockport, Timeout => 0.1, ) or die "Cannot connect on PF_INET - $!"; AND [20:26:38] t/22timeout.t ....................... Uncaught exception from user code: Cannot connect on PF_INET - Bad file descriptor at t/22timeout.t line 16. [20:26:38] t/22timeout.t ....................... Dubious, test returned 9 (wstat 2304, 0x9 00) but my $client = IO::Socket::IP->new( PeerHost => $server->sockhost, PeerPort => $server->sockport, TimeOut => 0.1, ) or die "Cannot connect on PF_INET - $!"; and all passing. So, Timeout versus TimeOut. -- Regards, Pete Armstrong pete.a64@gmail.com
From: pete.a64 [...] gmail.com
On Thu Sep 18 23:34:22 2014, parmstro64 wrote: Show quoted text
> my $client = IO::Socket::IP->new( > PeerHost => $server->sockhost, > PeerPort => $server->sockport, > Timeout => 0.1, > ) or die "Cannot connect on PF_INET - $!"; > > AND > > [20:26:38] t/22timeout.t ....................... Uncaught exception > from user code: > Cannot connect on PF_INET - Bad file descriptor at > t/22timeout.t line 16. > [20:26:38] t/22timeout.t ....................... Dubious, test > returned 9 (wstat 2304, 0x9 > 00) > > but > > my $client = IO::Socket::IP->new( > PeerHost => $server->sockhost, > PeerPort => $server->sockport, > TimeOut => 0.1, > ) or die "Cannot connect on PF_INET - $!"; > > and all passing.
However, This only removes the Timeout? So not certain that this is the solution but seems that the Timeout is the problem Windows. -- Regards, Pete Armstrong pete.a64@gmail.com
On Fri Sep 19 01:45:06 2014, parmstro64 wrote: Show quoted text
> This only removes the Timeout? So not certain that this is the > solution but seems that the Timeout is the problem Windows.
Yes - IO::Socket::IP won't complain about unrecognised constructor args, so all this change did is turn off the timeout. Not having access to a Windows machine I can't easily debug this one. Can you perhaps poke into it and find out /which/ system call is reporting the EBADF, and on what file descriptor it was called? -- Paul Evans
Wasn't able to reproduce this with my Perl: https://gist.github.com/wchristian/573cdf032a1c99d092b0 We'll need perl -V output from you.
This bug is CPU load related. Also i tried stepping/debugging it, but it dies somewhere in IO::Socket::IP::setup sub but due to its coding style, I can't set break points in it. On failure, the loop falls off the end and next is called starting the loop again. Next is NOT called on a successful run of 22timeout.t. I will wait until someone else responds. Also this test does not fail if I run 0.32's 22timeout.t with 0.29's IO::Socket::IP.
After some more debugging, I found there are 3 ways to fix this on my system. My 2 core 1 CPU Win XP box will never die with $! 22 unless I have very high CPU usage. My Server 2003 box with 2 core x 4 CPUs fails with $! 22 about 95% of the time, making CPAN shell unusable since HTTP::Tiny is unusable. ------------------------------------------------------- sub connect ------------------------------------------------------- my $vec = ''; vec( $vec, $self->fileno, 1 ) = 1; my ($r, $w, $e) = ($vec, $vec, $vec); if( !select( $r, $w, $e, $timeout ) ) { $! = ETIMEDOUT; return undef; } #remove 2nd connect call, why is it here? select provides info whether a connection was made or not $err = ''; $! = $err, return undef if $err; return 1; } ------------------------------------------------------- my $vec = ''; vec( $vec, $self->fileno, 1 ) = 1; my ($r, $w, $e) = ($vec, $vec, $vec); if( !select( $r, $w, $e, $timeout ) ) { $! = ETIMEDOUT; return undef; } # Hoist the error by connect()ing a second time $err = defined CORE::connect( $self, $addr ) ? 0 : $!+0; #windows reports EINVAL on Win2k and newer, since calling connect twice without a closesocket() in between is an "error" according to MS thinking, and is not an authorized way of finding out if the non blocking connection finished #see http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx $err = 0 if $err == EISCONN || $err == EINVAL; # Some OSes give EISCONN $self->blocking( $was_blocking ); $! = $err, return undef if $err; return 1; } ------------------------------------------------------- my $vec = ''; vec( $vec, $self->fileno, 1 ) = 1; my ($r, $w, $e) = ($vec, $vec, $vec); if( !select( $r, $w, $e, $timeout ) ) { $! = ETIMEDOUT; return undef; } #very bad fix but it works for me sleep 1; # Hoist the error by connect()ing a second time $err = defined CORE::connect( $self, $addr ) ? 0 : $!+0; $err = 0 if $err == EISCONN; # Some OSes give EISCONN $self->blocking( $was_blocking ); $! = $err, return undef if $err; return 1; } ------------------------------------------------------- How come readability is being checked in the select call in your original code? writeability determines when the connection occurs according to MS and from a POSIX person, on POSIX too. Here is a block of code from IO::Socket, notice the "$^O eq 'MSWin32'" ------------------------------------------------------- sub connect { @_ == 2 or croak 'usage: $sock->connect(NAME)'; my $sock = shift; my $addr = shift; my $timeout = ${*$sock}{'io_socket_timeout'}; my $err; my $blocking; $blocking = $sock->blocking(0) if $timeout; if (!connect($sock, $addr)) { if (defined $timeout && ($!{EINPROGRESS} || $!{EWOULDBLOCK})) { require IO::Select; my $sel = new IO::Select $sock; undef $!; my($r,$w,$e) = IO::Select::select(undef,$sel,$sel,$timeout); if(@$e[0]) { # Windows return from select after the timeout in case of # WSAECONNREFUSED(10061) if exception set is not used. # This behavior is different from Linux. # Using the exception # set we now emulate the behavior in Linux # - Karthik Rajagopalan $err = $sock->getsockopt(SOL_SOCKET,SO_ERROR); $@ = "connect: $err"; } elsif(!@$w[0]) { $err = $! || (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); $@ = "connect: timeout"; } elsif (!connect($sock,$addr) && not ($!{EISCONN} || ($^O eq 'MSWin32' && ($! == (($] < 5.019004) ? 10022 : Errno::EINVAL)))) ) { # Some systems refuse to re-connect() to # an already open socket and set errno to EISCONN. # Windows sets errno to WSAEINVAL (10022) (pre-5.19.4) or # EINVAL (22) (5.19.4 onwards). $err = $!; $@ = "connect: $!"; } } -------------------------------------------------------
With help from Leonerd I "wrote" the patch attached that works 100% on windows 2003.
Subject: 0001-Fix-timeout-connections-on-Windows-2003.patch
From 2fb4a2c11ad02b57669116808d901df6af0a1ce4 Mon Sep 17 00:00:00 2001 From: Arthur Axel 'fREW' Schmidt <frioux@gmail.com> Date: Tue, 18 Nov 2014 10:33:34 -0600 Subject: [PATCH] Fix timeout connections on Windows 2003 --- perl/lib/IO/Socket/IP.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perl/lib/IO/Socket/IP.pm b/perl/lib/IO/Socket/IP.pm index 8ebc44a..e038355 100755 --- a/perl/lib/IO/Socket/IP.pm +++ b/perl/lib/IO/Socket/IP.pm @@ -690,7 +690,7 @@ sub connect } # Hoist the error by connect()ing a second time - $err = defined CORE::connect( $self, $addr ) ? 0 : $!+0; + $err = $self->getsockopt( SOL_SOCKET, SO_ERROR ); $err = 0 if $err == EISCONN; # Some OSes give EISCONN $self->blocking( $was_blocking ); -- 2.0.0.390.gcb682f8
Released as 0.33 -- Paul Evans