Problem with IO::Socket

M

Martin Kissner

Hello group,

I am trying to use a script from the book "Networkprogramming with Perl"
by Lincoln D. Stein.

----
#!/usr/bin/perl

use warnings;
use strict;

use IO::Socket;

my $server = shift;
my $fh = IO::Socket::INET->new($server);
my $line = <$fh>;
print $line;
----

It is supposed to read the first line from a remote server's welcome
message.

% ./lgetr.pl wuarchive.wustl.edu:daytime
is supposed to output the current date of that server.

% ./lgetr.pl wuarchive.wustl.edu:ftp
should print the welcome message of the ftp service on
wuarchive.wustl.edu

% ./lgetr.pl mail.hotmail.com:smtp
should print the welcome message of the smtp-server on mail.motmail.com

and so on.
In my case the script hangs infinitely without any output.
I have even tried my local smtp server wuth the sam result.

What could be wrong?
Any help will be appreciated.

Regards
Martin
 
A

A. Sinan Unur

What could be wrong?

I am not sure.
Any help will be appreciated.

FWIW, the services you are trying

1) May not be enabled on the computers you have tried
2) May be behind a firewall
3) May require prior authentication

Sinan
 
M

Martin Kissner

A. Sinan Unur wrote :
FWIW, the services you are trying

1) May not be enabled on the computers you have tried
2) May be behind a firewall
3) May require prior authentication

Thank you for your response, Sinan.

After I had written my answer (pointing out what I have tried to exclude
the reasons you mentioned) I tried using the port numbers instead of the
service name.
This finally worked and leads me to the next question:

Why doesn't the script (or the Perl interpreter) look up the portnumber
in /etc/services. Telnet works properly with given servicenames.

Regards
Martin
 
P

phaylon

Martin said:
Why doesn't the script (or the Perl interpreter) look up the portnumber in
/etc/services. Telnet works properly with given servicenames.

- perl (lc) is not only for *ixoid systems.
- telnet is programmed to do so.
- perl can be programmed to do so.
- You can program perl to do so.
 
C

chris-usenet

Martin Kissner said:
Why doesn't the script (or the Perl interpreter) look up the portnumber
in /etc/services. Telnet works properly with given servicenames.

perldoc -f getservbyname

perl -e 'print join(", ", getservbyname ("telnet", "tcp")), ".\n"'

Chris
 
M

Martin Kissner

phaylon wrote :
- perl (lc) is not only for *ixoid systems.
- telnet is programmed to do so.
- perl can be programmed to do so.
- You can program perl to do so.

Well, to be honest, I am just beginning with networkprogramming with
Perl.
That's why I am reading the book and at this point the above does not
really help.

It is the second example in the book (the first one reads one line
from a file) and is supposed to work without any preparations and also
on windows and classic Mac OS.

Maybe perl can be programmed to do so (I am sure it can), but at this
point, I do not want to work out my own humble solution.

I would rather be interested if anyone out there could run the script
successfully without any changes and with servicenames instead of
portnumbers as it is suggested in the book.

Regrads
Martin
 
P

phaylon

Martin said:
I would rather be interested if anyone out there could run the script
successfully without any changes and with servicenames instead of
portnumbers as it is suggested in the book.

A better way is to use the docs. For IO::Socket::INET it is documented,
that

| If the constructor is only passed a single argument, it is assumed to be
| a PeerAddr specification.

A few lines up, we see

| The PeerAddr can be a hostname or the IP-address on the "xx.xx.xx.xx"
| form. The PeerPort can be a number or a symbolic service name. The
| service name might be followed by a number in parenthesis which is used
| if the service is not known by the system. The PeerPort specification
| can also be embedded in the PeerAddr by preceding it with a ":".
 
M

Martin Kissner

phaylon wrote :
A better way is to use the docs. For IO::Socket::INET it is documented,
that

This will not give me any information on the above question.
btw: I did read the docs for IO::Socket::INET.
| If the constructor is only passed a single argument, it is assumed to be
| a PeerAddr specification.

A few lines up, we see

| The PeerAddr can be a hostname or the IP-address on the "xx.xx.xx.xx"
| form. The PeerPort can be a number or a symbolic service name. The
| service name might be followed by a number in parenthesis which is used
| if the service is not known by the system. The PeerPort specification
| can also be embedded in the PeerAddr by preceding it with a ":".

| "The PeerPort can be a number or a service name."
I have used a service name. No contradiction to the docs so far.

And as sugessted in the last sentence I have embedded the service name
in the PeerAddr by preceding it with a ":".
The service is known by the system.

Farther, while finding the solution to my question in the first place, I
did some testing with unexpected results, which I did not want to
mention in my first post to keep it scarce and tidy.

The following script did not run either unless I didn't use use the
line, which is commented out below for creating the socket object.
The syntax for the constructor is taken from the docs.
The number in parantheses seems to be not used and the service name
seems to not work although known by the system.

-----
#!/usr/bin/perl

use IO::Socket;

my $fh = IO::Socket::INET->new(PeerAddr => 'localhost:smtp(25)');
# my $fh = IO::Socket::INET->new(PeerAddr => 'localhost:25');
my $line = <$fh>;
print $line;
-----

Also

my $fh = IO::Socket::INET->new(PeerAddr => 'localhost',
PeerPort => 'PeerPort(25)');

did not work as construcor whereas

my $fh = IO::Socket::INET->new(PeerAddr => 'localhost',
PeerPort => '25');

did.

Sorry, but I still do not understand this; therefor I am still
interested if it works for anyone else.
If I have overseen something, please point me to it.

Regards
Martin
 
X

xhoster

Martin Kissner said:
Hello group,

I am trying to use a script from the book "Networkprogramming with Perl"
by Lincoln D. Stein.

----
#!/usr/bin/perl

use warnings;
use strict;

use IO::Socket;

my $server = shift;
my $fh = IO::Socket::INET->new($server);

One should probably check for success:

my $fh = IO::Socket::INET->new($server) or die $@;
my $line = <$fh>;
print $line;
----

It is supposed to read the first line from a remote server's welcome
message.

% ./lgetr.pl wuarchive.wustl.edu:daytime
is supposed to output the current date of that server.

It gives me a connection refused message.
% ./lgetr.pl wuarchive.wustl.edu:ftp
should print the welcome message of the ftp service on
wuarchive.wustl.edu

For me, it does do that.
% ./lgetr.pl mail.hotmail.com:smtp
should print the welcome message of the smtp-server on mail.motmail.com

the smtp-server on mail.hotmail.com doesn't seem to have a welcome
message.
and so on.
In my case the script hangs infinitely without any output.

The only one that hangs for me is hotmail, and given the behavior of that
server, this is not unexpected.


Xho
 
A

A. Sinan Unur

Sorry, but I still do not understand this; therefor I am still
interested if it works for anyone else.
If I have overseen something, please point me to it.

I am not sure. Here is some info:

Microsoft Windows 2000 [Version 5.00.2195]
This is perl, v5.8.6 built for MSWin32-x86-multi-thread

C:\> perl -MIO::Socket::INET -e "print $IO::Socket::INET::VERSION"
1.27

I tried your script against a variety of hosts using the service name
'smtp'. The script worked as expected.

You will need to give some more information regarding the system on which
you are testing this in a clear and concise way.

Now, you can check if perl is able to do the mapping from service names
to port addresses on your system by running this script (from Perl docs):

#! /usr/bin/perl

use strict;
use warnings;

use Net::servent;
my $s = getservbyname(shift) || die "no service";
printf "port for %s is %s, aliases are %s\n",
$s->name, $s->port, "@{$s->aliases}";

__END__

On the system I mentioned above, this gives me:

C:\> perl s.pl smtp
port for smtp is 25, aliases are mail

C:\> perl s.pl chargen
port for chargen is 19, aliases are ttytst source

Exploring from here is an option.

Sinan
 
M

Martin Kissner

One should probably check for success:

Yes, that's probably true.
my $fh = IO::Socket::INET->new($server) or die $@;

It gives me a connection refused message.

The book is from 2002; the service is discontinued, I guess.
But it proves, that the script tried to connect.
For me, it does do that.

Thank you for that information.
What is your OS? Mine is Darwin 7.8 (Mac OS X)
Which Version of Perl are you using. I am using Perl 5.8.1
the smtp-server on mail.hotmail.com doesn't seem to have a welcome
message.

With telnet I get

| 220 mc9-f7.hotmail.com Sending unsolicited commercial or bulk e-mail to
| Microsoft's computer network is prohibited. Other restrictions are found
| at http://privacy.msn.com/Anti-spam/. Violations will result in use of
| equipment located in California and other states. Wed, 16 Feb 2005
| 13:48:09 -0800

I do still not know how to find out why it doesn't work on my system.
Any suggestions are welcome.

Regards
Martin
 
M

Martin Kissner

A. Sinan Unur wrote :
You will need to give some more information regarding the system on which
you are testing this in a clear and concise way.

Of course.
I should have done in the first place.

% uname -msr
Darwin 7.8.0 Power Macintosh
# which is Mac OS X

% perl -v
This is perl, v5.8.1-RC3 built for darwin-thread-multi-2level
(with 1 registered patch, see perl -V for more detail)
Now, you can check if perl is able to do the mapping from service names
to port addresses on your system by running this script (from Perl docs):

Thank you for the script.

% ./test_services.pl smtp
port for smtp is 25, aliases are

% ./test_services.pl http
port for http is 80, aliases are www www-http

works optimally and makes it still more surprising that the script doesn't
 
X

xhoster

Martin Kissner said:
Thank you for that information.
What is your OS? Mine is Darwin 7.8 (Mac OS X)
Which Version of Perl are you using. I am using Perl 5.8.1

Sorry, I should have included that:

Summary of my perl5 (revision 5.0 version 8 subversion 0) configuration:
Platform:
osname=linux, osvers=2.4.21-1.1931.2.393.entsmp,
archname=i386-linux-thread-multi
With telnet I get

| 220 mc9-f7.hotmail.com Sending unsolicited commercial or bulk e-mail to
| Microsoft's computer network is prohibited. Other restrictions are
| found at http://privacy.msn.com/Anti-spam/. Violations will result in
| use of equipment located in California and other states. Wed, 16 Feb
| 2005 13:48:09 -0800

For me it just hung, even with telnet. Maybe it was just very slow and I
didn't wait long enough.
I do still not know how to find out why it doesn't work on my system.
Any suggestions are welcome.

After you added error checking, did it still hang with the first one, or
did you get a connection refused?

Xho
 
M

Martin Kissner

After you added error checking, did it still hang with the first one, or
did you get a connection refused?

This morning I tried to connect to a ftp-server in my LAN and watched the
network with tcpdump.
There was no attempt to connect and the script hanged as it did without
error checking.
With a port number the script connected at once.
With an invalid port number I got the error message as expected
(Connection refused ... ).

What else could I do to find the reason for this behaviour?

Regards
Martin
 
A

Anno Siegel

Martin Kissner said:
A. Sinan Unur wrote :

Of course.
I should have done in the first place.

% uname -msr
Darwin 7.8.0 Power Macintosh
# which is Mac OS X

Something is fishy on Darwin. I also see it hang when the service is
given by name and reply as expected when given by port number. However,
just *calling* getservbyname() before opening the socket makes it work
with a name too.

use IO::Socket;

my $server = shift;

if ( my ( $port) = $server =~ /:(.*)/ ) {
# just call it
getservbyname( $port, 'tcp') or die "getservbyname( $port)";
}

print "Trying $server\n";
my $fh = IO::Socket::INET->new( $server) or die $!;
my $line = <$fh>;
print $line;

__END__

This gives the expected reply from "mail.hotmail.com:smtp". Comment out
the call to getservbyname() and it doesn't.

I'm not sure how Darwin deals with getservbyname(). It may use some
netinfo devilry instead of /etc/services. The man page is ominously
missing.

Anno
 
M

Martin Kissner

Anno Siegel wrote :
Something is fishy on Darwin.

I guess it is.
I will try this on FreeBSD as soon as possible.
I also see it hang when the service is
given by name and reply as expected when given by port number. However,
just *calling* getservbyname() before opening the socket makes it work
with a name too.

use IO::Socket;

my $server = shift;

if ( my ( $port) = $server =~ /:(.*)/ ) {
# just call it
getservbyname( $port, 'tcp') or die "getservbyname( $port)";
}

print "Trying $server\n";
my $fh = IO::Socket::INET->new( $server) or die $!;
my $line = <$fh>;
print $line;

Thank you for this code example. It works for me, too and examples like
this one expand my view since I am not so experienced in Perl
programming.
This gives the expected reply from "mail.hotmail.com:smtp". Comment out
the call to getservbyname() and it doesn't.

I'm not sure how Darwin deals with getservbyname(). It may use some
netinfo devilry instead of /etc/services. The man page is ominously
missing.

Te documentation to Darwin sometimes is a drag. It has become better
with Panther, but it's still not goos enough.
However, Darwin does use /etc/services.
I tried by simply changing the name of a service in /etc/services.
 
M

Martin Kissner

Anno Siegel wrote :
Something is fishy on Darwin. I also see it hang when the service is
given by name and reply as expected when given by port number. However,
just *calling* getservbyname() before opening the socket makes it work
with a name too.

After I had proved that servicenames can be resolved by Perl on Mac OS X
with the function 'getservbyname()' I was interested if I could find out
how IO::Socket::INET gets the servicenames and how this might be
different from 'getservbyname()'.
As far as I can see IO::Socket::INET uses 'getservbyname()'.
In Version 1.26 of IO::Socket::INET the conversion is done in line 58/59
of 'INET.pm'.

After all I tried the script once again without making any changes and
to my very great surprise it ran flawlessly with servicenames and with
portnumbers.
If Anno had not seen it hang when servicenames were given, I'd probably
doubted my mental health ;-).

I report this not because I expect that someone could explain this
but to give some final feedback to everybody who had to helped.

Best regards
Martin
 
A

Anno Siegel

Martin Kissner said:
Anno Siegel wrote :
Something is fishy on Darwin. I also see it hang when the service is
given by name and reply as expected when given by port number. However,
[...]

After all I tried the script once again without making any changes and
to my very great surprise it ran flawlessly with servicenames and with
portnumbers.
If Anno had not seen it hang when servicenames were given, I'd probably
doubted my mental health ;-).

I've seen that too. It wasn't reproducible, so I dismissed it for
the time being.

Anno
 
M

Martin Kissner

Anno Siegel wrote :
I've seen that too. It wasn't reproducible, so I dismissed it for
the time being.

This turned out to be really annoying.
This morning I tried another script from my book and it ran right away.
After I came back from work, I woke up my computer and ran the script
from the shell history ... and got an error or better said a warning.
The first script (the one I posted) also didn't run any more.

Surprising to me was, that the 'new' method sucessfully returned a socket
object. The problem was that this socket can not be used, however.

I finally found out, that 'IO::Socket::INET->new()' seems to open an UDP Socket
at least sometimes on Mac OS X.

The manual says:
| If "Proto" is not given and you specify a symbolic "PeerPort" port,
| then the constructor will try to derive "Proto" from the service
| name. As a last resort "Proto" "tcp" is assumed.

This is what I have experienced:
As soon as the PeerPort specification is given as number it seems that 'tcp' is
assumed in any case unless "Proto" is given.
It seems that if "Proto" is not given in most cases the protocol is used,
which is listed first in "/etc/services".
On Mac OS X the udp specifications are listed before the tcp spec. in the
services file.
That (I guess) is the reason for the deadlocks.

This, however, does not explain why sometimes 'tcp' is assumed on Mac OS X.
It also doesn't explain, why 'tcp' is not assumed with services like ftp, smtp
etc. which AFAIK can not be used with udp.
And finally I can not find the code in Socket.pm which should be responsible
for what I have quoted above fom the documentation.

Is there a way to find out the reason for this unreliability?
What would be the right address to report a -in my opinion bugy- behaviour
like this?
Is there a chance to fix this (or get it fixed)?

My conclusion for now is, to always define "Proto".

Best regards
Martin
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top