# poslib.pl # # Poslib Perl interface for Zaza map applet. # # Copyright (C) 2001 Brian Rudy (brudyNO@SPAMpraecogito.com) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # # Requires: # Config::IniFiles # IPC::ShareLite # # Needed by libposlib.so, DISPLAY_LOCALIZE, and posServer # ## Revision History ## # 0.41 8-16-2001 # Fleshed-out new goal semaphore and goal loading. Now operational # with basic client voting and loading to the planner. # # 0.40 8-15-2001 # Added client fingerprinting, goal voting and vote tabulation. # Added stubs for new goal semaphores. # # 0.30 8-14-2001 # Basic goal ini reading via Config::IniFiles and storage in shared # memory for posServer access. # # 0.20 8-13-2001 # Fixed position hash storage and retrieval w/ proper serialization. # # 0.10 8-10-2001 # First working version. Only impliments position retrieval. # use IPC::ShareLite; use DynaLoader; use Config::IniFiles; my $debug = 0; #my $goalfile = "/home/brudy/posServer/ex_goals.ini"; #my $goalfile = "/home/brudy/posServer/in_goals.ini"; my $goalfile = "/home/brudy/posServer/mccabe_goals.ini"; use Storable qw(freeze thaw); # These default to 65,536 bytes each, so use the default # with care. my $posshare = new IPC::ShareLite( -key => 1492, -create => 'yes', -destroy => 'no', -size => 200 ) or die $!; my $goalshare = new IPC::ShareLite( -key => 1493, -create => 'yes', -destroy => 'no', -size => 5000 ) or die $!; my $voteshare = new IPC::ShareLite( -key => 1494, -create => 'yes', -destroy => 'no' ) or die $!; my $semaphoreshare = new IPC::ShareLite( -key => 1495, -create => 'yes', -destroy => 'no', -size => 8 ) or die $!; sub poslibinit { # not 0, helps client debugging pushpos(1, 1, 1); flushsemaphores(); flushvotes(); read_goal_file(); } sub pushpos { ($x, $y, $theta) = @_ ; if ($debug) { print "got x=" . $x . " ,y=" . $y . ", and theta=" . $theta . "\n"; } %Position = ('x' => $x, 'y' => $y, 'theta' => $theta); $posshare->store(freeze(\%Position)); if ($debug) { ## This is for verification only my %retpos = %{thaw($posshare->fetch)}; my $nx = %retpos->{'x'}; my $ny = %retpos->{'y'}; my $ntheta = %retpos->{'theta'}; print "now x=" . $nx . " , y=" . $ny . ", and theta=" . $ntheta ."\n"; } # this is totally arbitrary right now return $x + $y; } sub poppos { my %fretpos = %{thaw($posshare->fetch)}; # print "Current position is x=" . %fretpos->{'x'} . ", y=" . %fretpos->{'y'} . ", theta=" . %fretpos->{'theta'} . "\n"; %fretpos->{'x'}, %fretpos->{'y'}, %fretpos->{'theta'}; } sub read_goal_file { my $goalini = new Config::IniFiles( -file => $goalfile ); # load it all into an Array of Hashes my @GoalAoH; for (my $i = 0; $i <= 19; $i++) { if ($goalini->val( $i, 'Enabled' ) eq 'yes') { $GoalAoH[$i]{Name} = $goalini->val( $i, 'Name' ); $GoalAoH[$i]{URL} = $goalini->val( $i, 'URL' ); $GoalAoH[$i]{Appletx} = $goalini->val( $i, 'Appletx' ); $GoalAoH[$i]{Applety} = $goalini->val( $i, 'Applety' ); $GoalAoH[$i]{Realx} = $goalini->val( $i, 'Realx' ); $GoalAoH[$i]{Realy} = $goalini->val( $i, 'Realy' ); $GoalAoH[$i]{Enabled} = $goalini->val( $i, 'Enabled' ); $GoalAoH[$i]{Votes} = 0; #print "\$i=" . $i . " is enabled\n"; } #else { # print "\$i=" . $i . " is disabled\n"; #} } # Then read it all out again #for $index (0 .. $#GoalAoH) { # print "[" . $index . "]\n"; # print "Name=" . $GoalAoH[$index]{Name} . "\n"; # print "URL=" . $GoalAoH[$index]{URL} . "\n"; # print "Appletx=" . $GoalAoH[$index]{Appletx} . "\n"; # print "Applety=" . $GoalAoH[$index]{Applety} . "\n"; # print "Realx=" . $GoalAoH[$index]{Realx} . "\n"; # print "Realy=" . $GoalAoH[$index]{Realy} . "\n"; # print "Enabled=" . $GoalAoH[$index]{Enabled} . "\n"; # print "Votes=" . $GoalAoH[$index]{Votes} . "\n"; #} my $frozengoals = freeze(\@GoalAoH); #print "\n\$frozengoals is " . length($frozengoals) . " bytes.\n"; #print "Storing in shared memory...\n"; $goalshare->store($frozengoals); #print "...and now retrieving\n"; #my @newgoalsAoH = @{thaw($goalshare->fetch)}; # #for $j (0 .. $#newgoalsAoH) { # print "$j is { "; # for $role (keys %{ $newgoalsAoH[$j] }) { # print "$role= $newgoalsAoH[$j]{$role}\n"; # } # print "}\n"; #} } # pop the goals AoH out of shared memory sub popgoals { @{thaw($goalshare->fetch)}; } # register vote for goal sub votegoal { ($goalnum, $clientip) = @_ ; #my $binip = IpToBin($clientip); ## Kludgy Client Fingerprinting Schema (TM) ;) # %votelist is a hash of arrays, with the key as the # client's IP address and the array element as the goal # number. my %votelist = %{thaw($voteshare->fetch)}; if ($votelist{$clientip}[$goalnum] == 1) { print "no\n"; print "I already have a vote from you for that goal.\n"; } else { $votelist{$clientip}[$goalnum] = 1; print "ok\n"; print "Vote accepted.\n"; $voteshare->store(freeze(\%votelist)); # This is for testing only! $semaphoreshare->store("1"); } #print "The unmodified string is " . length($clientip) . # " and the binary version is " . length($binip) . " which is " . # $binip . ".\n"; #print "Hey " . $clientip . " I got your goal " . $goalnum . # " right here...\n"; } # Tally all votes sub tallyvotes { my %votelist = %{thaw($voteshare->fetch)}; my @mrgoals = popgoals(); my $votestotal = 0; my %votetally; for $client (keys %votelist) { for $i (0 .. $#{ $votelist{$client} }) { if ($votelist{$client}[$i] == 1) { $votetally{$i}++; } } } # how many have we got? for $j (keys %votetally) { print $votetally{$j} . " votes for " . $mrgoals[$j]{Name} . ".\n"; $votestotal += $votetally{$j}; } if (($votestotal != 0) && ((keys %votetally) != 0)) { my $votesaverage = sprintf("%.0f", $votestotal/(keys %votetally)); print "The total number of votes is " . $votestotal . ". The average number is " . $votesaverage . "\n"; } else { print "There are no votes!\n"; } } # Print current vote tabulation (for debugging) sub printvotes { my @mrgoals = popgoals(); my %votelist = %{thaw($voteshare->fetch)}; for $client (keys %votelist) { print $client . "\n"; for $i (0 .. $#{ $votelist{$client} }) { if ($votelist{$client}[$i] == 1) { print "--" . $mrgoals[$i]{Name} . "\n"; } } print "\n"; } } # Return the first voted goal found # This function is for testing only sub getgoal { my @mrgoals = popgoals(); my %votelist = %{thaw($voteshare->fetch)}; for $client (keys %votelist) { for $i (0 .. $#{ $votelist{$client} }) { if ($votelist{$client}[$i] == 1) { return($mrgoals[$i]{Realx}, $mrgoals[$i]{Realy}); } } } } # Flush out semaphore shared memory sub flushsemaphores { $semaphoreshare->store("0"); } # Flush out vote shared memory space sub flushvotes { my %votelist; $votelist{'127.0.0.1'}[0] = 0; $voteshare->store(freeze(\%votelist)); } # Check if a new goal has been added sub newgoal { my $check = $semaphoreshare->fetch; if ($check eq '1') { return 1; } else { return 0; } } # # Components of the following sub have been borrowed from Charles # Kereke's IpMath.pl (http://homepages.waymark.net/~ckerekes/IpMath.pl) # #This sub converts an entire ip address or subnet mask to char sub IpToBin { my ($ip) = @_[0]; #this is the ip to convert my @octets, $bin; #Split up octets into the array @octets=split(/\./,$ip); #Append the decimal value of the octets $bin = unpack("c", $octets[0]); $bin .= unpack("c", $octets[1]); $bin .= unpack("c", $octets[2]); $bin .= unpack("c", $octets[3]); #return the result in $bin $bin; } 1;