#!/bin/perl -w

use strict;
use IO::Socket;
use File::Basename;
use Getopt::Std qw(getopts);

my $PHRODO_PORT = 8009;
my $MAXLEN= 1024;
my $CONNECT_TIMEOUT = 10;
my $phonebook="phonebook";
my $phonebook_new="phonebook_new";
my $log="log";
my $date;
my $date2;

# usage stuff
use vars (
q!$opt_d!, # debug mode
);

my $prog = basename $0;
my $usage = "Usage: $prog [-d]\n";

getopts('d')
or die $usage;
my $debug = $opt_d;
warn "Debug logging enabled\n" if $debug;

# server stuff
my $server;

$server = IO::Socket::INET->new( LocalPort => $PHRODO_PORT,
Proto => 'tcp',
Type => SOCK_STREAM,
Listen => SOMAXCONN,
Reuse => 1,
);
unless( $server ) {
die "socket could not be created: $@\n";
}

while (my $client = $server->accept()){
$client->autoflush(1);

$client->peeraddr();

open (PHONEBOOK, "<$phonebook") or die "can't open $phonebook: $!";
open (LOG, ">>$log") or die "can't open $log: $!";

# Get hostname by name or by IP Address (whatever you prefer)
# my $hostname = gethostbyaddr( $client->peeraddr(), AF_INET ) ;
my $hostname = inet_ntoa($client->peeraddr());
$date=localtime;
print LOG "$date - Got connection from $hostname\n";

# Get the message from the client
my $newmsg;
$client->recv($newmsg, $MAXLEN);
$date=localtime;
print LOG "$date - Recieved message from $hostname\n" if $debug;

# If the message is a registration
if ($newmsg =~ /register/) {
# Open phonebook_new filehandler
open (PHONEBOOK_NEW, ">>$phonebook_new") or die "can't open $phonebook_new: $!";

# Substitute the blank ip with the client address
$newmsg =~ s/ip=0.0.0.0/ip=$hostname/g;
$newmsg =~ s/\0//;

# Store the register and host info as primary key in $unique_info
(my $unique_info, my $other_info) = split /\|p/, $newmsg;
(my $box_info, my $host_info) = split /\|/, $unique_info;

# Parse the phonebook. If the unique info is there, client
# already has entry. Check to see if the host has changed.
# If it has changed, modify the entry for that box.
# If the box is not found, add an entry to the phonebook.
my $found=0;
while(){
my $line = $_;
if ( $line =~ /^$box_info/ ){
$found=1;

# Update the registration time
$date2=time();
$line =~ s/rtime=\d.*\d\|udp_ip/rtime=$date2|udp_ip/;

# Replace corresponding hostname with new one, if different
if ($line !~ /ip=$hostname/ ){
# existing entry for box_id has diff hostname
$line =~ s/ip=\w.*\w\|p/ip=$hostname|p/;
$line =~ s/udp_ip=\w.*\w\|u/udp_ip=$hostname|u/;
$date=localtime;
print LOG "$date - Changed entry in phonebook for $box_info on $hostname\n" if $debug;
}
}
print PHONEBOOK_NEW $line;
}

if (not $found) {
print PHONEBOOK_NEW "$newmsg\n";
$date=localtime;
print LOG "$date - Added $box_info to phonebook at $hostname\n" if $debug;
}
close (PHONEBOOK) or die "can't close $phonebook: $!";
close (PHONEBOOK_NEW) or die "can't close $phonebook_new: $!";

# Rename the phonebook with the modified entry
rename($phonebook, "phonebook.orig") or system("rename", $phonebook, "phonebook.orig") or die "can't rename $phonebook to $phonebook.orig: $!";
rename($phonebook_new, $phonebook) or system("rename", $phonebook_new, $phonebook) or die "can't rename $phonebook_new to $phonebook: $!";

# Assign response variable to send to client. Must append
# null character.
my $msg = "rtimer=600\0";
$client->send($msg);

$date=localtime;
print LOG "$date - Sent message $msg to $hostname\n" if $debug;
}

# If the message is a query
if ($newmsg =~ /query/){
# Grab the box ID that the client is looking up
(my $query, my $lookup) = split /\|/, $newmsg;
(my $fieldlabel, my $box_id) = split /=/, $lookup;

# Remove the null character
$box_id =~ s/\0//;

$date=localtime;
print LOG "$date - $query looking for $box_id on $hostname\n" if $debug;

# Parse phonebook. If the queried box ID is found, format a response.
my $sendmsg = 0;
while(){
my $line = $_;
if ( $line =~ /^register=$box_id\|ip/ ){
$line =~ s/register=/serial=/g;
$line =~ s/flags=[0-9]*\|/flags=1\|/g;
$line =~ s/\|rtime/\|ctime=995591865\|utime=1016013554\|rtime/g;
$sendmsg = "$line\0";
$date=localtime;
print LOG "$date - Query found $box_id in phonebook\n" if $debug;
}
}
if ($sendmsg){
# Send back response to client.
$client->send($sendmsg);
}
else {
# Send back unknown response to client
my $unknown = "UNKNOWN\0";
$client->send($unknown);
$date=localtime;
print LOG "$date - Query did not find $box_id in phonebook\n";
}
close (PHONEBOOK) or die "can't close $phonebook: $!";
}
$client->close();

undef $client;

close (LOG) or die "can't close $log: $!";

}
$server->close;