The general problem with these things is that server and client
have to agree on some protocol, i.e. that each party knows how to react
in response to what the other side has done. Here's your example modified to handle name and password checking with dynamic branching on the client side, in case re-entry of name or password is required.
Server:
#!/usr/bin/perl -w
use strict;
use IO::Socket;
my $sock = new IO::Socket::INET(
LocalHost => 'localhost',
LocalPort => 7890,
Proto => 'tcp',
Listen => SOMAXCONN,
Reuse => 1);
$sock or die "no socket :$!";
STDOUT->autoflush(1);
my $req_name = "Enter Name: \n";
my $req_pass = "Enter Password: \n";
my $req_none = "Enter \n";
sub verify_passw {
my ($name, $pass) = @_;
# print STDERR "name=$name, pass=$pass\n"; # debug
# ...
return 1;
}
while (my $new_sock = $sock->accept())
{
my $name = ""; # lifetime is connection
my $auth = 0; # ditto (storing state of session)
while (<$new_sock>)
{
/^HELLO$/ and print($new_sock $req_name), next;
/^NAME: (\w*)/ and do {
$name = $1;
if ($name && length($name)<=8) {
print $new_sock "Ok, name: $name\n";
print $new_sock $req_pass;
} else {
print $new_sock "Invalid name: '$name'\n";
print $new_sock $req_name;
}
next
};
/^PASS: (\w*)/ and do {
my $pass = $1;
if ($auth = verify_passw($name, $pass)) { # =, not ==
print $new_sock "Login ok\n";
print $new_sock $req_none;
} else {
print $new_sock "Invalid password!\n";
print $new_sock $req_pass;
}
next
};
/^DATE$/ and print($new_sock scalar(localtime), "\n"), next;
print $new_sock "DEFAULT\n";
}
close $new_sock;
}
Client:
#!/usr/bin/perl -w
use strict;
use IO::Socket;
my $host = shift || 'localhost';
my $port = shift || 7890;
my $sock = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp');
$sock or die "no socket :$!";
my %handler = (
Name => \&name,
Password => \&pass,
);
sub show_reply_and_next {
do {
$_=<$sock>;
print unless /Enter $/;
} until /^Enter (\w*)/;
# $1 holds what to do next
if ($handler{$1}) {
$handler{$1}->();
}
# else just return
}
sub hello {
print $sock "HELLO\n";
show_reply_and_next();
}
sub name {
my $name = <STDIN>;
print $sock "NAME: $name";
show_reply_and_next();
}
sub pass {
my $pass = <STDIN>;
print $sock "PASS: $pass";
show_reply_and_next();
}
###
hello(); # initiates login
print $sock "DATE\n";
print scalar <$sock>;
print $sock "NONE\n";
print scalar <$sock>;
close $sock;
Sample session:
$ ./827156_client.pl
Enter Name:
toooooooo_long
Invalid name: 'toooooooo_long'
Enter Name:
Invalid name: ''
Enter Name:
almut
Ok, name: almut
Enter Password:
foobar
Login ok
Sun Mar 7 01:10:53 2010
DEFAULT
It's maybe worth noting that in real life the server should not allow access to any "protected" resources unless the login has successfully been completed. The idea being that a client program with possibly manipulated logic of flow will have no chance to bypass security checks. This is not implemented so far — the code just sets $auth (which should then be used for subsequent checks). |