#! /usr/bin/perl -w
use strict;
use Socket; # so we can broadcast on udp
use POSIX;

# A deamon to broadcast our name/ip info once in awhile.
# Some other daemon will be listening and updating its /etc/hosts as required

#****************************************globals
my $time_to_die = 0; # shutdown cleanly
my $pid; # for daemonizing
my @IPs; # for multihomed hosts, just broadcast one
my $debug = 0; # don't print if daemonized
my $name; # my name on the ethernet
my $ipaddr; # my ip on the lan
my $msgsock; # the socket
my $portno = 53831; # birthday port-y
my $dest = sockaddr_in($portno, inet_aton("192.168.1.255"));
my $msg; # what I'm going to broadcast

#****************************************
sub mynetinfo ()
{
# some of this is easier, some harder than for the other machines on the net
 open (MYNAME, "hostname |") or die "Can't run hostname utility: $!";
 $name = <MYNAME>; # note, chomp to get rid of /n
 chomp $name;
 close (MYNAME) or die "Can't close hostname utility: $!";
 
 open (MYIP, "hostname -I |") or die "Can't run hostname -I:$!";
 $ipaddr = <MYIP>;
 close (MYIP) or die "Can't close hostname -I"; 
 @IPs = split /\s+/, $ipaddr; # might be more than one
 print LOG "IPs:@IPs\n" if $debug;
 
foreach (@IPs)
 {
  $ipaddr = $_;
  print LOG "ipaddr:$ipaddr\n" if $debug;
  last if ($ipaddr =~ /192.168.1/);
 }
 print LOG "ipaddr after loop:$ipaddr\n" if $debug;
 chomp $ipaddr;
 
 $msg = "$ipaddr $name";
}
#****************************************
sub setupsock()
{
 socket($msgsock,PF_INET,SOCK_DGRAM,getprotobyname("udp")) or die "socket:$!";
 setsockopt($msgsock, SOL_SOCKET, SO_BROADCAST,1) or die "setsockopt:$!";
}
#****************************************
sub signal_handler 
{ 
 $time_to_die = 1; 
 print LOG "Killed by sig\n" if $debug;
}
########################### main
if ($debug) 
{
 open (LOG, "> /tmp/tellem.log") or die "couldn't open logfile";
 print LOG "started\n";
}
$pid = fork(); # we're going to detach from whoever started us
exit if $pid; # parent dies
die "Couldn't fork: $!" unless defined($pid);
POSIX::setsid() or die "Can't start new session: $!";
close (STDIN); # never use it anyway
close (STDOUT) unless $debug;
close (STDERR) unless $debug;
$SIG{TERM} = \&signal_handler;

until ($time_to_die)
{
 sleep int(rand(31) + 30);  # don't flood network or use too much machine either
 #turns out we have to sleep first, as we get started before we have an IP
 # address and a few other things.
 setupsock() unless $msgsock; # even this has to wait for the DHCP stuff
 mynetinfo(); # set up/refresh my own net information
 print LOG ("msg:$msg\n") if $debug;
 send($msgsock,"$msg",0,$dest) or die "send:$!";
}
print LOG "Died\n" if $debug;
