It seems to me that there isn't a whole lot that needs to be changed to provide non-blocking support for Win32 systems from within the IO::Socket module. Of course I could be missing something.
There needs to be a blocking() sub which uses ioctl() instead of allowing IO:Handle's blocking sub to do the work. And some of the if conditions in the connect() function need to be changed to reflect the fact that Windows uses EWOULDBLOCK instead of EINPROGRESS and WSAEINVAL (10022) instead of EISCONN.
Note that the following are based on the IO::Socket which came with ActiveState Perl 5.8.0 build 806. Also note that the blocking() sub doesn't handle the case of just checking the blocking state of a socket using $somesock->blocking().
Here is a blocking sub which would work (assuming that the fixed version of ioctl from change 19534 is being used):
sub blocking { my $sock = shift; return $sock->SUPER::blocking(@_) unless $^O =~ /Win32/; #Windows handles blocking differently my $nonblocking = $_[0] ? "0" : "1"; #0x8004667e is FIONBIO return ioctl($sock, 0x8004667e, \$nonblocking);
}
and here is the modified connect (sorry this isn't a diff)
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} || ($^O =~ /Win32/ && $!{EWOULDBLOCK}))) { require IO::Select;
my $sel = new IO::Select $sock;
if (!$sel->can_write($timeout)) { $err = $! || (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); $@ = "connect: timeout"; } elsif (!connect($sock,$addr) && not ($!{EISCONN} || ($^O =~ /Win32/ && $! == 10022))) { # Some systems refuse to re-connect() to # an already open socket and set errno to EISCONN. # Windows sets errno to WSAEINVAL (10022) $err = $!; $@ = "connect: $!"; } } elsif ($blocking || !($!{EINPROGRESS} || ($^O =~ /Win32/ && $!{EWOULDBLOCK}))) { $err = $!; $@ = "connect: $!"; } }
> It seems to me that there isn't a whole lot that needs to be changed to > provide non-blocking support for Win32 systems from within the > IO::Socket module. Of course I could be missing something.
> There needs to be a blocking() sub which uses ioctl() instead of > allowing IO:Handle's blocking sub to do the work. And some of the if > conditions in the connect() function need to be changed to reflect the > fact that Windows uses EWOULDBLOCK instead of EINPROGRESS and WSAEINVAL > (10022) instead of EISCONN.
According to my network programming book, both EWOULDBLOCK and EINPROGRESS are valid errno values for a nonblocking connect.
However, the fact that neither of these two constants are in Errno.pm probably should be considered a bug. (At least, they aren't there in Activestate Perl 5.6.1, with local patch 631)
-- $a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca );{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "$@[$a%6 ]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}
>>There needs to be a blocking() sub which uses ioctl() instead of >>allowing IO:Handle's blocking sub to do the work. And some of the if >>conditions in the connect() function need to be changed to reflect the >>fact that Windows uses EWOULDBLOCK instead of EINPROGRESS and WSAEINVAL >>(10022) instead of EISCONN.
> According to my network programming book, both EWOULDBLOCK and > EINPROGRESS are valid errno values for a nonblocking connect.
With that being the case, the "$^O =~ /Win32/ &&" portions could be dropped to make it a bit cleaner. It just seems like Windows is the only one where EWOULDBLOCK is used. The bit with WSAEINVAL is a bit harder to simplify, since no other platform has that particular error.
> However, the fact that neither of these two constants are in Errno.pm > probably should be considered a bug. (At least, they aren't there > in Activestate Perl 5.6.1, with local patch 631)
And they still aren't there in ActivePerl 5.6.1.635. However, they are present in ActivePerl 5.8.0.806, which is what I based my changes on. I also seem to recall something about the $!{ERROR} construction not being valid in 5.6.1. There doesn't seem to be anything majorly different between the 5.8.0.806 and 5.6.1.635 versions of Errno.pm other than the addition of about 37 error numbers, mostly networking related, so maybe if a 5.6.1.636 build is released, those constants could be in there.
>Benjamin Goldberg wrote: >> Robert Moser II wrote:
>>>There needs to be a blocking() sub which uses ioctl() instead of >>>allowing IO:Handle's blocking sub to do the work. And some of the if >>>conditions in the connect() function need to be changed to reflect the >>>fact that Windows uses EWOULDBLOCK instead of EINPROGRESS and WSAEINVAL >>>(10022) instead of EISCONN.
>> According to my network programming book, both EWOULDBLOCK and >> EINPROGRESS are valid errno values for a nonblocking connect.
>With that being the case, the "$^O =~ /Win32/ &&" portions could be >dropped to make it a bit cleaner. It just seems like Windows is the >only one where EWOULDBLOCK is used. The bit with WSAEINVAL is a bit >harder to simplify, since no other platform has that particular error.
WSAEINVAL is just Win32 bolt-on for EINVAL from sockets DLL.