incorrect errno/perror with IO::socket->new

B

brandon

  IZ> [A complimentary Cc of this posting was sent to
  IZ> Uri Guttman
  >> do you understand me now??

  IZ> a) there is no reason to yell;

there is a reason when the OP keeps banging his head on the wall and
won't listen.

  IZ> b) your arguments are, IMO, wrong.

and i disagree. but you are always right so i won't argue with you. it
is a waste of time.

  IZ> In a perfect world, your argument that `$@ should contain all the
  IZ> information one needs' would be right.  In a perfect world, presetting
  IZ> these variables to FALSE would not be needed.  In a perfect world,
  IZ> one would not need to check $!.

and the module code can be patched in the imperfect world. or you can
write your own which i did. no problems with any error handling then.

  IZ> However, as the OP had shown, the world he lives in is not perfect..
  IZ> Somethign fishy is happening.  So it is very logical, very polite, and
  IZ> very helpful (*) that he is setting $!, $@ to FALSE, and is the value
  IZ> of reporting $! to us.

The only thing I have been able to find close to a mention of how to
determine why one's use of IO::Socket might be failing is from $@, and
that only in an example. So I am using $@ now ok? After you mentioned
this I started printing both.
nope, i did the same things and got a clean error message from $@. $! is
useless as it could be from some system call that failed but was handled
by the module. LWP does retries and such so $! may get set along the way
to a perfectly fine page fetch. if the module doesn't specify it will
use $! then looking at it is dumb.

Not exactly, you did not try passing Timeout.

You helped point me to what the problem is though, it's the original
problem I am really having $! or $@ aside. This may make it more
clear :

---------- A Sun example : -----------

1) First with a port on which there is no process listening :

# uname -s
SunOS
# perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.96", PeerPort => "10" ); print "$@\n" unless $s'
IO::Socket::INET: connect: Connection refused
# perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.96", PeerPort => "10", Timeout => "5"); print "$@\n"
unless $s'
IO::Socket::INET: connect: Connection refused
#

In both cases I get "connect: Connection refused", even though I am
passing a Timeout

2) Now a host that does not exist on the subnet and will timeout

# time perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.200", PeerPort => "10" ); print "$@\n" unless $s'
IO::Socket::INET: connect: Connection timed out

real 3m45.01s
user 0m0.27s
sys 0m0.04s
# set -o vi
# time perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.200", PeerPort => "10" , Timeout => "5"); print "$@\n"
unless $s' <
IO::Socket::INET: connect: timeout

real 0m5.35s
user 0m0.29s
sys 0m0.05s
#

The message from $@ in the second case is set in IO::Socket and is
not the same as the first which is the text context of $!, the system
perror set in the _error() subroutine from the system call to connect.
But note that the timeout I've passed caused the call to be abandoned
after 5 seconds.

------------- An AIX example : ------------

1) Same thing as above, a port on which there is no process
listening :

# uname -srv
AIX 3 5
# perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.96", PeerPort => "10" ); print "$@\n" unless $s'
IO::Socket::INET: connect: A remote host refused an attempted connect
operation.
# perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.96", PeerPort => "10", Timeout => "5"); print "$@\n"
unless $s'
IO::Socket::INET: connect: A system call received a parameter that is
not valid.
#

In the two cases above it looks to me like passing a Timeout is
causeing some heartache to the AIX build of Perl - same thing on HP.

2) And again, a host that does not exist on the subnet and will
timeout the connect

# time perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.200", PeerPort => "10" ); print "$@\n" unless $s'
IO::Socket::INET: connect: A remote host did not respond within the
timeout period.

real 1m14.80s
user 0m0.04s
sys 0m0.02s
# time perl -MIO::Socket -e '$s = IO::Socket::INET->new(PeerAddr =>
"172.16.18.200", PeerPort => "10" , Timeout => "5"); print "$@\n"
unless $s'
IO::Socket::INET: connect: timeout

real 0m5.00s
user 0m0.05s
sys 0m0.01s
#

So that is the behavior I think is inconsistent. Why would passing
Timout result in EINVAL on AIX and HP boxes when an error is
encountered in connect?

Thanks
 
X

xhoster

brandon said:
Yes, and note from the code I did test it before and set it to '0'.

Sure, but that doesn't matter. IO::Socket does not guarantee that only a
single system call is made during it's new operation. Some of those system
calls may fail without the whole operation having failed. Those will set
errno, and hence $!, but not in a meaningful manner.

IO::Socket tries to abstract away many things behind the scenes. It
usually does a good job, but not always. If you want to micromanage the
socket creation process the way you would in C, and thus have no hidden
complexities that can set $! in unintuitive ways, then don't use
IO::Socket, use the low-level socket functions instead. It would be great
to figure out why IO::Socket isn't setting $@ appropriately, but I can't
really help much with that because I don't have access to the OSes you
report problems with.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
X

xhoster

brandon said:
So that is the behavior I think is inconsistent. Why would passing
Timout result in EINVAL on AIX and HP boxes when an error is
encountered in connect?

In a similar situation in the past, I made a IO::Socket::INET copy and
replaced the contents of _error with something that does a Carp::confess
instead. That way you can get a back-trace of what is going on.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
B

brandon

In a similar situation in the past, I made a IO::Socket::INET copy and
replaced the contents of _error with something that does a Carp::confess
instead.  That way you can get a back-trace of what is going on.

Xho

Sounds good. I think I'm going to see if I can find out if RH is
changeing anything in IO::Socket, IO::Select, etc., when they build
their perl distribution too. Always a possibility that they are making
some changes that AIX for example is not. If I find anything
interesting I'll let ya'll know.
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
brandon
I have been having fits getting meaningful errno/perror values out of
Perl from Socket->new() and I am hoping someone here might know what
is going on.

I wonder why nobody told this yet: proof of a pudding is in a truss.

Hope this helps,
Ilya
 
D

Dr.Ruud

Uri Guttman schreef:
if the call to IO::Socket->new doesn't
return undef, there is NO point in checking out $! or $@. they will be
meaningless and may be set to some irrelevant value. i have never had
to clear those before making any lib or system calls. i only check
them if there is an indicator of an error. checking them directly is
wrong in almost every case. they could be changed due to some
internal call that is redone or worked around and yet your call will
still have succeeded.


Idem with

eval {
...;
1;
} or do {
...
};

v.s.


eval {
...;
};
if ($@) {
...
};
 
B

brandon

 Sounds good. I think I'm going to see if I can find out if RH is
changeing anything in IO::Socket, IO::Select, etc., when they build
their perl distribution too. Always a possibility that they are making
some changes that AIX for example is not. If I find anything
interesting I'll let ya'll know.




- Show quoted text -

For anyone that continued reading this - I've given up on trying to
use Timeout to limit the amount of time I wait for a sucessful connect
before giving up. I wanted to do that because this is only one of many
checks I need to do and some of these servers (Sun I think) are taking
3 minutes + to timeout.

So I got rid of the Timeout and just fork a child and kill it after
30 sec if there is no response. Works great and does what I need it to
do and the sysadmins won't forget what they were doing by the time the
whole program finishes.

Without Timeout I encountered a few old clients that would not return
a correct perror with $@ and a few old clients that would not return a
correct perror with $!. The vast majority return the same perror for
both $! and $@.

I can't update the version of Perl on these clients but I could haul
the modules .so's around with me, though I prefer not to do that. So I
finally settled on checking the perror (first $@, then if $@ is not a
socket perror I test $!), and printing my own error message. If I
don't recognize either as a socket perror I print a message to that
effect along with both $@ and $!. So far I have not hit that condition
and I've run this on a couple thousand servers.

Thanks to everyone including Uri.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,736
Latest member
zacharyharris

Latest Threads

Top