You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Interesting. I believe there's at least one bug here, in
IO::Socket, but it's not entirely clear.
First, the workaround: don't use Timeout. Find some other way of
timing out the operation, like alarm(). The CNAMEs are a red
herring: what matters is that that machine doesn't accept
connections on port 43. The 'Invalid argument' is just the wrong
error: without Timeout, you should see 'Connection refused',
which is the right answer.
[You don't need to read the rest unless you're interested...]
That ->new call gives me exactly the same result as you: EINVAL
from connect(). Since I didn't think connect(2) was even able
to return EINVAL, I ran it under ktrace: this showed two calls to
connect. The first failed with EINPROGRESS, the second with
EINVAL. Retrying without Timeout consistently gave
'Connection refused' instead.
Looking at the source of IO::Socket, the logic if Timeout is
specified is approximately
set non-blocking mode on the socket
try to connect
if connect fails with EINPROGRESS
select(2) for write, with the given timeout
if the select doesn't time out
retry the connect
if that connect succeeds, return success
if it failed with EISCONN, or we are on Win32 and it failed
with WSAEINVAL, return success
otherwise, return the error from the second connect
The EISCONN case is the strange one. There is a comment
Some systems refuse to re-connect() to
an already open socket and set errno to EISCONN.
Windows sets errno to WSAEINVAL (10022)
and it turns out that it's not just Win32 that returns EINVAL in
that case, it's at least current versions of FreeBSD and,
presumably, OS/2 as well. However, even given that, returning
success is completely wrong.
The sequence of events is
app calls connect(2) on a non-blocking socket
connect(2) fails with EINPROGRESS
app calls select(2)-for-write
some time later, a RST packet comes in
select(2) returns socket as ready
app calls connect(2) again
connect(2) fails with EISCONN/EINVAL
The EISCONN/EINVAL error is saying 'this socket isn't fit to be
reused': it doesn't tell you anything about whether the
second connection attempt succeeded or failed. (In fact, you get
the same EINVAL if you attempt to re-connect a TCP socket while
it's in TIME_WAIT state after a successful close.)
Looking about a bit, I found http://cr.yp.to/docs/connect.html,
which mentions this connect-twice strategy as a way of performing
a non-blocking connect and still getting the correct error. It
also says that it doesn't always work, and that you should use
getpeername instead (and for all djb's... um... charm, he's usually
right about things like this). So, I think this counts as a bug
in IO::Socket, since there are common situations on common
operating systems where it doesn't work properly.
[Oddly, it looks from the CVS log as though FreeBSD used to return
EISCONN in this situation, as the IO::Socket code was
kind-of expecting, but it was changed to EINVAL in 2006. It's not
clear to me why, especially since there now appears to be no way
to get an EISCONN error from a TCP socket.]
The attached patch from Ben Morrow works fine for OS/2.
--
Shmuel (Seymour J.) Metz, SysProg and JOAT
Atid/2 http://patriot.net/~shmuel
We don't care. We don't have to care, we're Congress.
(S877: The Shut up and Eat Your spam act of 2003)
The text was updated successfully, but these errors were encountered:
Migrated from rt.cpan.org#86791 (status was 'new')
Requestors:
Attachments:
From [email protected] on 2013-07-08 20:57:09:
See 115706 in the old CPAN tracking system.
Per Ben Morrow [email protected] in thread "IO::Socket::INET hostname
restrictions? " on comp.lang.perl.misc, archived at
http://www.rhinocerus.net/forum/lang-perl-misc/690988-io-socket-inet-hostname-restrictions.html:
Interesting. I believe there's at least one bug here, in
IO::Socket, but it's not entirely clear.
First, the workaround: don't use Timeout. Find some other way of
timing out the operation, like alarm(). The CNAMEs are a red
herring: what matters is that that machine doesn't accept
connections on port 43. The 'Invalid argument' is just the wrong
error: without Timeout, you should see 'Connection refused',
which is the right answer.
[You don't need to read the rest unless you're interested...]
That ->new call gives me exactly the same result as you: EINVAL
from connect(). Since I didn't think connect(2) was even able
to return EINVAL, I ran it under ktrace: this showed two calls to
connect. The first failed with EINPROGRESS, the second with
EINVAL. Retrying without Timeout consistently gave
'Connection refused' instead.
Looking at the source of IO::Socket, the logic if Timeout is
specified is approximately
set non-blocking mode on the socket
try to connect
if connect fails with EINPROGRESS
select(2) for write, with the given timeout
if the select doesn't time out
retry the connect
if that connect succeeds, return success
if it failed with EISCONN, or we are on Win32 and it failed
with WSAEINVAL, return success
otherwise, return the error from the second connect
The EISCONN case is the strange one. There is a comment
and it turns out that it's not just Win32 that returns EINVAL in
that case, it's at least current versions of FreeBSD and,
presumably, OS/2 as well. However, even given that, returning
success is completely wrong.
The sequence of events is
The EISCONN/EINVAL error is saying 'this socket isn't fit to be
reused': it doesn't tell you anything about whether the
second connection attempt succeeded or failed. (In fact, you get
the same EINVAL if you attempt to re-connect a TCP socket while
it's in TIME_WAIT state after a successful close.)
Looking about a bit, I found http://cr.yp.to/docs/connect.html,
which mentions this connect-twice strategy as a way of performing
a non-blocking connect and still getting the correct error. It
also says that it doesn't always work, and that you should use
getpeername instead (and for all djb's... um... charm, he's usually
right about things like this). So, I think this counts as a bug
in IO::Socket, since there are common situations on common
operating systems where it doesn't work properly.
[Oddly, it looks from the CVS log as though FreeBSD used to return
EISCONN in this situation, as the IO::Socket code was
kind-of expecting, but it was changed to EINVAL in 2006. It's not
clear to me why, especially since there now appears to be no way
to get an EISCONN error from a TCP socket.]
The attached patch from Ben Morrow works fine for OS/2.
--
Shmuel (Seymour J.) Metz, SysProg and JOAT
Atid/2 http://patriot.net/~shmuel
We don't care. We don't have to care, we're Congress.
(S877: The Shut up and Eat Your spam act of 2003)
The text was updated successfully, but these errors were encountered: