We help IT Professionals succeed at work.

Perl Socket Problem

monish
monish asked
on
Medium Priority
633 Views
Last Modified: 2008-03-03
I want to be able to change my passwd on the server "ebs2.eecs" from my machine "ebs1.eecs" using sockets.
ebs2.eecs has an entry for the program under /etc/services and /etc/inetd.conf. On calling the program from ebs1.eecs I do get Testing.. as the output but nothing further happens.

1) What do I need to do to get this to work?
2) How come I don't get an output for $name when I call the
   client prog. with an output?

The client program that runs on my machine "ebs1.eecs"

#!/usr/sww/bin/perl
# passwd.client

$AF_INET = 2;
$SOCK_STREAM = 1;
$sockaddr = 'S n a4 x8';

chop ($user = `whoami`) unless $user;

$port = 1997;
$host = 'ebs2.eecs';

($n, $a, $proto) = getprotobyname('tcp');
($n, $a, $t, $l, @thisaddr) = gethostbyname('localhost');
($n, $a, $t, $l, @thataddr) = gethostbyname($host);

$this = pack($sockaddr, $AF_INET, 0, $thisaddr);
$that = pack($sockaddr, $AF_INET, $port, @thataddr);

socket(S, $AF_INET, $SOCK_STREAM, $proto) || die "Can't open socket!\n";
bind(S, $this) || die "Couldn't bind a new socket!\n";
connect(S, $that) || die "Couldn't connect to host $host, port $port!\n";

select(S); $| = 1; select(STDOUT);

print S "$user\n";  ##Pass the user to the server                                  passwd.answerd prog

while (<S>) {
    print;
}

---------------------------------
The server prog on "ebs2.eecs"
---------------------------------

#!/usr/sww/bin/perl
# passwd.server

$ENV{'PATH'} = '/bin:/etc:/etc/bin:/usr/bin:/usr/ucb:/usr/local/bin';
print "Testing.. \n" ;
local($name) = @_ ;

$AF_INET = 2;
$SOCK_STREAM = 1;
$sockaddr = 'S n a4 x8';

$port = 1997;

($n, $a, $t, $l, @thisaddr) = gethostbyname($host);
($n, $a, $proto) = getprotobyname('tcp');
$thisport = pack($sockaddr,$AF_INET,$port,$thisaddr);
socket(S, $AF_INET, $SOCK_STREAM, $proto) || die "Can't open socket!";
bind(S,$thisport) || die "Cannot bind socket \n" ;
listen(S,5) || die "Cannot listen socket \n" ;
for(;;)
{
  accept(NS,S) || die "Cannot accept socket\n" ;
  system "/bin/passwd" ;
  close NS;
}



Comment
Watch Question

Commented:
The first thing I would recommend doing is changing the
socket handling techniques you are using to use the Socket
module provided with perl5.002 and higher.

#
# Sample code to get the server operating (assumes
# perl5.002 is installed at /usr/local/bin/perl):
#

#!/usr/local/bin/perl

require 5.002;
use Socket;
use Fcntl;
use POSIX;

$port = 1997;
$proto = getprotobyname('tcp');

# Open the socket, set socket options for reuse

socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die "setsockopt: $!";
setsockopt(Server, SOL_SOCKET, SO_LINGER, 0);

# bind socket, allowing 1 connection at a time, set
# non-blocking io

bind(Server, sockaddr_in($port, INADDR_ANY)) or die "bind: $!";
fcntl(Server, F_SETFL, O_NONBLOCK);
listen(Server, 1) or die "listen: $!";

for (; $paddr = accept(Client,Server); close Client){

   # Ok, the server has a connection which can now
   # be referenced as the filehandle Client.
   # Expect input in the form: user tab pwd
   # Warning: You will likely need to strip some
   # extra characters found at the end of the string.
   # You can do this by checking for non-null characters.

   my ($input) = <Client>;
   my ($user, $pwd) = (split("\t", $input));

   # You will likely need to reorganize the way you
   # interact wth the passwd command, see below.  
   # after executing pwd command the for loop closes
   # the connection.
}

#
# Sample Code for Interacting with passwd command
#

open(PWD, "|/bin/passwd $user");
while(<PWD>){

   # You know what the password command prompts for
   # and you need to print to it in the order that
   # it requires.

   print PWD "${pwd}\n"; # Password to change to
   print PWD "${pwd}\n"; # Verification of new password
}
close(PWD);

#
# Sample Client Code. Assumes same perl call and
# same same modules used
#

$remote  = "hostname.ext";
$port    = 1997
$iaddr   = inet_aton($remote) || return 0;
$paddr   = sockaddr_in($port, $iaddr);

# Open the scket
socket(SOCK, PF_INET, SOCK_STREAM, $proto);  
# Call up the server
connect(SOCK, $paddr);

while(<SOCK>){
   # Print the user name and password, tab-delim
   # The server should expect to read a string, tab, then
   # string.

   print "${user}\t${pwd}\n";

   # The server will close the connection when it is
   # done, this should end the while loop.
}

This should give you a basis for converting to the
Socket module, it is much better than using the old
socket handling techniques, which do not work on all
platforms. This example also shows you how to interact
with the password command through a named pipe. This is
also a good way of handling this...

Hope this helps!
Andy

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
I tried your example. I see the server process start up at
the server "ebs2" and get some error checking output on "ebs1".  
The following is the output I get back on ebs1 when I run the program :

CHECK C1
CHECK C2
CHECK C3
CHECK S1
CHECK C3
CHECK S2
CHECK C3
CHECK S3
bind: Address already in useCHECK C4

So it never goes pass the following line on the server :
bind(Server, $port)                     or die "bind: $!" ;

Any clues on how I can get the client and Server to talk and fix this ? Thanks.


===============================================================
The client code on ebs1 :

#!/usr/local/bin/perl5
require 5.002;
use strict;
use Socket;
use Fcntl;
use POSIX;

my $user = `whoami` ;
my ($remote,$port,$iaddr,$paddr,$proto,$line);

$remote = "ebs2.eecs.berkeley.edu";
$port = 1995 ;

$iaddr = inet_aton($remote) or print "ERROR1\n" ;
$paddr = sockaddr_in($port, $iaddr);

# Open the socket
$proto = getprotobyname('tcp') ;
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "Could'nt create socket";

# Call up the server
connect(SOCK, $paddr) or die "Couldn't connect socket";

print "CHECK C1\n" ;
##select(SOCK); $| = 1; select(STDOUT);
print "CHECK C2\n" ;

while(<SOCK>)
{
    print "CHECK C3\n" ;
    print ;
}
print "CHECK C4\n" ;
close (SOCK) || die "Couldn't close socket\n";
exit ;

====================================================
The server code on ebs2 :

#!/usr/local/bin/perl5
require 5.002;
use strict;
use Socket;
use Carp;
use Fcntl;
use POSIX;

print "CHECK S1\n" ;
my $port = 1995;
my $proto = getprotobyname('tcp');

socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!" ;
print "CHECK S2\n" ;
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("1",1))       or die "setsockopt: $!";
print "CHECK S3\n" ;
#bind(Server,sockaddr_in($port,INADDR_ANY)) or print "bind: $!" ;
bind(Server, $port)                     or die "bind: $!" ;
print "CHECK S4\n" ;
listen(Server,SOMAXCONN)                or die "listen: $!" ;

my $paddr;
for ( ; $paddr = accept(Client,Server); close Client)
{
  my($port, $iaddr) = sockaddr_in($paddr);
  my $name = gethostbyaddr($iaddr,AF_INET);
  print Client "Hello there, $name \n";
}

=========================================================








Commented:
Ok, the bind: Address already in use indicates that either
the port you are using is already bound by another program,
or it is bound by the current program but has not been.

For example, if you run the program and then kill it, the
port will remain bound for a few minutes. I have this problem
with a proxy server I use, it takes about 5 full minutes
before I can run it again after the server dies. Give it
some time and then try again. I know this sucks and is quite
a hassle when debugging but it happens... *sigh*

-Andy
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.