S
samasama
Hi...
I'm trying to detect multiple clients connected to a SOCK_STREAM
server. I'm doing this via a hash. The actual detecting part is going
fine. The problem I'm running into however takes place when a second
client connects from the same ip address (multiple clients)... When a
second connection is made from the same host, it errors out and
disconnects that second connection as it should, but when the first
(original) connection disconnects and tries to re-connect it doesn't
work. This is because the first (original) connections key in the hash
does not get deleted. I've been banging my head into the desk for a few
weeks trying to figure out how to get that key deleted, and properly.
Any help, advice, pointers, brutal criticism is very much welcome and
appreciated.
#!/usr/bin/perl
use warnings;
use diagnostics;
use strict;
use IO::Socket;
use POSIX qwsys_wait_h);
our %ip_conns; # hash of connected clients
our $time_to_die = 0;
# Globals for the socket
our $SERVER;
our $CLIENT;
$SIG{CHLD} = \&handle_sigchld;
$SIG{INT} = $SIG{TERM} = \&handle_default;
our $banner =
"\%rwhois V-1.5:000082:00 rwhois.foo.bar (Rwhois Server version)";
our $foo; # Temp for messing with chk_multi_conn
my $pid = fork;
exit if $pid;
die "Couldn't fork: $!\n" unless defined($pid);
POSIX::setsid() || die "Can't start a new session: $!";
$SERVER = IO::Socket::INET->new(
Proto => 'tcp',
LocalAddr => '0.0.0.0',
LocalPort => '4321',
Listen => SOMAXCONN,
Reuse => 1
);
die "WSRwhois : Can't setup server : $!\n " unless $SERVER;
print "[ Server $0 accepting clients ]\n";
until ($time_to_die) {
while ( $CLIENT = $SERVER->accept() ) {
$foo = $CLIENT;
$ip_conns{$CLIENT} = $CLIENT->peerhost;
my $conn_ret = chk_multi_conn();
if ($conn_ret == 1 ) {
delete $ip_conns{$CLIENT};
shutdown($CLIENT, 2); }
my $kidpid = fork;
die "Fork: $!\n" unless defined($kidpid);
if ( $kidpid == 0 ) {
shutdown( $SERVER, 1 );
$CLIENT->autoflush;
print $CLIENT "$banner\015\012";
while ( sysread( $CLIENT, $_, 1024 ) ) {
next unless /\S/;
if (/-quit/) {
print $CLIENT "\%ok\015\012";
shutdown( $CLIENT, 2 );
}
}
delete $ip_conns{$CLIENT};
exit(0);
}
else { # Let the parent do some stuff
}
}
}
sub chk_multi_conn {
my %count = ();
my $times;
foreach my $keys ( keys %ip_conns ) {
my $value = $ip_conns{$keys};
print "#DEBUG Inside chk_multi_conn()\n"; # DEBUG
print "#DEBUG \%ip_conns = $keys => $value\n"; # DEBUG
print "#DEBUG\n"; # DEBUG
print "#DEBUG \$CLIENT = $CLIENT\n"; # DEBUG
$times = $count{$value}++;
}
if ( $times >= 1 ) {
print $CLIENT
"\%error Only 1 connection allowed per host.\n";
return (1);
}
else {
return (0); }
}
sub handle_sigchld {
delete $ip_conns{$foo}; # Just to be sure
my $pid = wait; # Wait for children to die
$SIG{'CHLD'} = \&handle_sigchld;
}
sub handle_default {
$time_to_die = 1; # Kill daemon
}
I'm trying to detect multiple clients connected to a SOCK_STREAM
server. I'm doing this via a hash. The actual detecting part is going
fine. The problem I'm running into however takes place when a second
client connects from the same ip address (multiple clients)... When a
second connection is made from the same host, it errors out and
disconnects that second connection as it should, but when the first
(original) connection disconnects and tries to re-connect it doesn't
work. This is because the first (original) connections key in the hash
does not get deleted. I've been banging my head into the desk for a few
weeks trying to figure out how to get that key deleted, and properly.
Any help, advice, pointers, brutal criticism is very much welcome and
appreciated.
#!/usr/bin/perl
use warnings;
use diagnostics;
use strict;
use IO::Socket;
use POSIX qwsys_wait_h);
our %ip_conns; # hash of connected clients
our $time_to_die = 0;
# Globals for the socket
our $SERVER;
our $CLIENT;
$SIG{CHLD} = \&handle_sigchld;
$SIG{INT} = $SIG{TERM} = \&handle_default;
our $banner =
"\%rwhois V-1.5:000082:00 rwhois.foo.bar (Rwhois Server version)";
our $foo; # Temp for messing with chk_multi_conn
my $pid = fork;
exit if $pid;
die "Couldn't fork: $!\n" unless defined($pid);
POSIX::setsid() || die "Can't start a new session: $!";
$SERVER = IO::Socket::INET->new(
Proto => 'tcp',
LocalAddr => '0.0.0.0',
LocalPort => '4321',
Listen => SOMAXCONN,
Reuse => 1
);
die "WSRwhois : Can't setup server : $!\n " unless $SERVER;
print "[ Server $0 accepting clients ]\n";
until ($time_to_die) {
while ( $CLIENT = $SERVER->accept() ) {
$foo = $CLIENT;
$ip_conns{$CLIENT} = $CLIENT->peerhost;
my $conn_ret = chk_multi_conn();
if ($conn_ret == 1 ) {
delete $ip_conns{$CLIENT};
shutdown($CLIENT, 2); }
my $kidpid = fork;
die "Fork: $!\n" unless defined($kidpid);
if ( $kidpid == 0 ) {
shutdown( $SERVER, 1 );
$CLIENT->autoflush;
print $CLIENT "$banner\015\012";
while ( sysread( $CLIENT, $_, 1024 ) ) {
next unless /\S/;
if (/-quit/) {
print $CLIENT "\%ok\015\012";
shutdown( $CLIENT, 2 );
}
}
delete $ip_conns{$CLIENT};
exit(0);
}
else { # Let the parent do some stuff
}
}
}
sub chk_multi_conn {
my %count = ();
my $times;
foreach my $keys ( keys %ip_conns ) {
my $value = $ip_conns{$keys};
print "#DEBUG Inside chk_multi_conn()\n"; # DEBUG
print "#DEBUG \%ip_conns = $keys => $value\n"; # DEBUG
print "#DEBUG\n"; # DEBUG
print "#DEBUG \$CLIENT = $CLIENT\n"; # DEBUG
$times = $count{$value}++;
}
if ( $times >= 1 ) {
print $CLIENT
"\%error Only 1 connection allowed per host.\n";
return (1);
}
else {
return (0); }
}
sub handle_sigchld {
delete $ip_conns{$foo}; # Just to be sure
my $pid = wait; # Wait for children to die
$SIG{'CHLD'} = \&handle_sigchld;
}
sub handle_default {
$time_to_die = 1; # Kill daemon
}