From f1d35e3443aa8451bf47be80983076fe28626113 Mon Sep 17 00:00:00 2001 From: Karthik Rajagopalan Date: Thu, 14 Jul 2011 13:36:41 -0400 Subject: [PATCH] Use the exception set in select (connect()) to early return when remote end is busy or in non existing port For non blocking socket, it a timeout has been specified, IO::Socket internally use select(..) to detect the result of socket connection. In situation, where remote end is busy or in non-existing port, we spend entire timeout mentioned in select(..) call. We cannot completely differentiate if error is WSAECONNREFUSED(10061) or WSAETIMEDOUT(10060) in this situation. If we use the exception set in select(..) call, we can do early return and also a make a clear differentiation in error condition. This is same like what Linux handle in this situation. --- dist/IO/lib/IO/Socket.pm | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dist/IO/lib/IO/Socket.pm b/dist/IO/lib/IO/Socket.pm index 31fa18f..06e4e6c 100644 --- a/dist/IO/lib/IO/Socket.pm +++ b/dist/IO/lib/IO/Socket.pm @@ -118,10 +118,21 @@ sub connect { my $sel = new IO::Select $sock; undef $!; - if (!$sel->can_write($timeout)) { - $err = $! || (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); - $@ = "connect: timeout"; - } + 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} || ($! == 10022 && $^O eq 'MSWin32')) ) { -- 2.7.4