#!/usr/bin/perl #Pear Core server version 0.05 use IO::Socket::INET; use strict; use Time::HiRes; #No Go on windows :) use vars qw(%filebase $socket); $socket = IO::Socket::INET->new(Listen => 1, LocalPort => 9876, PeerAddr => "192.168.0.2", #Change IP Proto => "tcp", ReuseAddr => 1, Type => SOCK_STREAM, ); if (!$socket) { die "No Socket"; } $|++; sub timer { for my $ip (keys %filebase) { $filebase{$ip}{timestamp}++; if ($filebase{$ip}{timestamp} > 5) { logrequest("Deleted $ip -> $filebase{$ip}{timestamp}"); delete($filebase{$ip}); } } } #Increase counter every 30 secs #If above ceiling, remove host $SIG{ALRM} = \&timer; if ($^O ne "MSWin32") { Time::HiRes::ualarm(30_000_000,30_000_000); } $socket->autoflush(1); print "Accepting clients...\n"; #Complex Data Structure met files and IPs while(my $client = $socket->accept()) { my $line = <$client>; chomp $line; my $clientaddress = $client->peerhost; $client->autoflush(1); #Log it if ($line eq "Pear Pear") #Send file list { $line = <$client>; chomp $line; while($line) { push(@{$filebase{$clientaddress}{files}},{filename=>$line}); #Stick files in data struc based on IP logrequest("$line located at $clientaddress"); $line = <$client>; chomp $line; } close($client); } if ($line eq "Orange Orange") #Send Time event { $filebase{$clientaddress}{timestamp} = 0; logrequest("$clientaddress checked in..."); close($client); } if ($line eq "Apple Apple") #Query file?? { $line = <$client>; chomp $line; if ($line =~ /^Pluck ([^\s]*)$/) #extract filename : Pluck filename { my $fruit = $1; my @query = (); for my $ip (keys %filebase) { for my $filerecord (@{$filebase{$ip}{files}}) { my $filename = ${$filerecord}{filename}; if ($ip ne $clientaddress && $filename =~ /$fruit/i) { push(@query,"$ip;$filename"); } #Check data struc for files } } logrequest("$fruit queried by $clientaddress"); for(@query) { print $client $_,"\n"; } #Send IP list to client } close($client); } } close($socket); sub logrequest { open(LOG,">>pear.log") || die $!; my $hour = sprintf "%02d",(localtime(time))[2]; my $minute = sprintf "%02d",(localtime(time))[1]; my $second = sprintf "%02d",(localtime(time))[0]; my $day = sprintf "%02d",(localtime(time))[3]; my $month = sprintf "%02d",(localtime(time))[4]+1; my $year = 1900+(localtime(time))[5]; #sprintf - Zero padding my $datestring = "$hour:$minute:$second $day/$month/$year "; print LOG $datestring,join(" - ",@_),"\n"; close(LOG); #Log connections } # ------ Client #!/usr/bin/perl use IO::Socket; use vars qw($pid $server $debug); use Term::ReadLine; use Time::HiRes; use File::Find; use strict; $debug = 1; #1 -> yes #0 -> no #Socket to Core sub createsocket { $server = IO::Socket::INET->new(PeerPort => 9876, PeerAddr => '192.168.0.2', #Change Core IP Proto => 'tcp', ReuseAddr => 1, Type => SOCK_STREAM, ); $server->autoflush(1); debuglog("Created Core Server Connection"); if (!$server) { return 0; } else { return 1; } } sub closesocket { close($server); debuglog("Closing Core Server Connection"); } #Send timestamp sub sendtime { createsocket(); print $server "Orange Orange\n"; closesocket(); } #Send file list sub sendfiles { createsocket(); print $server "Pear Pear\n"; #Init file list if ($^O ne "MSWin32") { File::Find::find({ wanted=> sub { my $filename = $File::Find::name; $filename =~ s/^\.\/(.*)$/$1/; print $server $filename,"\n" if !-d $File::Find::name; }, follow=>1 }, "."); } else { sub dodir { opendir(DIR,$_[0]); my $dir = $_[0]; if ($dir !~ /\/$/) { $dir .= "/"; } for my $file(readdir(DIR)) { $file =~ s/^\.\/(.*)$/$1/; if ($file =~ /^\.\.?$/) { next; } my $fullpath = $dir.$file; if (-d $fullpath) { dodir($fullpath); } else { print $server $fullpath,"\n"; } } closedir(DIR); } dodir("."); } debuglog("Sending filelist to Core server"); closesocket(); } #Query Core for files sub queryfile { createsocket(); my $filename = shift; print $server "Apple Apple\n"; print $server "Pluck $filename\n"; #Query filename my @IP = (); while(my $line = <$server>) { chomp $line; push(@IP,$line); } debuglog("Querying files on Core server"); closesocket(); return \@IP; } sendtime(); sendfiles(); #Send sig every 60 secs $SIG{ALRM} = \&sendtime; if ($^O ne "MSWin32") { Time::HiRes::ualarm(60_000_000,60_000_000); } die "can't fork: $!" unless defined($pid = fork()); if ($pid) # client { my $term = new Term::ReadLine 'Pear Client'; my $label = "Keyword : "; my $keyword; my @db; my $file; #Fancy input while ( defined ($keyword = $term->readline($label)) ) { if ($keyword =~ /^update$/i) { sendtime(); sendfiles(); } if ($keyword =~ /^(quit|bye|exit)$/i) { kill 9,$pid; exit; } if ($keyword =~ /^help$/i) { print "help:\t\t\tThis page\nupdate:\t\t\tUpdate filelist and time\nfind :\tFind filename\nget :\t\tGet file from host indicated by number\n"; print "quit:\t\t\tQuit Pear\n"; } if ($keyword =~ /^find ([^\s]*)$/i) { $file = $1; #Find filename -> Core returns array my @foo = @{queryfile($file)}; my $c = 0; for(@foo) { my ($ip,$filename) = split(/;/,$_); push(@db,{IP=>$ip,Filename=>$filename}); } for(@db) { print join("\t","[$c]",$_->{Filename},$_->{IP}."\n"); $c++ } } if ($keyword =~ /^get (\d*)$/i) { my $index = $1; my $ip = $db[$index]->{IP}; #Displays list with index my $socket = IO::Socket::INET->new(PeerPort => 6789, PeerAddr => $ip, Proto => "tcp", ReuseAddr => 1, Type => SOCK_STREAM, ); if (!$socket) { debuglog("IP $ip is not online"); next; } $socket->autoflush(1); my $file = $db[$index]->{Filename}; debuglog("Fetching $file from $ip"); print $socket "Peach Peach $file\n"; my $filesize = <$socket>; chomp $filesize; if ($filesize eq "ERROR") { next; } my $data; my $buffersize = 4096; my $returnsize; my $readsize; #Dump to file if(open(OUTFILE,">$file")) { while($returnsize = read($socket,$data,$buffersize) && $readsize != $filesize) { print OUTFILE $data; $readsize += $returnsize; } close(OUTFILE); } else { debuglog("Error opening $file for writing ($ip)"); } close($socket); } } } else { my $socket = IO::Socket::INET->new(Listen => 1, LocalPort => 6789, PeerAddr => "192.168.0.2", Proto => "tcp", ReuseAddr => 1, Type => SOCK_STREAM, ); if (!$socket) { die "No Socket"; } $|++; $socket->autoflush(1); print "Pear Server Accepting clients...\n"; while(my $client = $socket->accept()) { $client->autoflush(1); my $line = <$client>; chomp $line; if ($line =~ /^Peach Peach ([^\s]*)/) { my $filename = $1; my $filesize = -s $filename; print $client "$filesize\n"; if(open(FILE,"<$filename")) { print $client "$filesize\n"; my $data; my $buffersize = 4096; my $returnsize; my $readsize; while($returnsize = read(FILE,$data,$buffersize) && $readsize != $filesize) { print $client $data; $readsize += $returnsize; } close(FILE); } else { print $client "ERROR\n"; debuglog("Error opening $filename for reading - ".$client->peerhost); } close($client); } } } sub debuglog { if (!$debug) { return } open(LOG,">>debug.log") || die $!; my $hour = sprintf "%02d",(localtime(time))[2]; my $minute = sprintf "%02d",(localtime(time))[1]; my $second = sprintf "%02d",(localtime(time))[0]; my $day = sprintf "%02d",(localtime(time))[3]; my $month = sprintf "%02d",(localtime(time))[4]+1; my $year = 1900+(localtime(time))[5]; my $datestring = "$hour:$minute:$second $day/$month/$year "; print LOG $datestring,join(" - ",@_),"\n"; close(LOG); #Log connections }