https://kb.speeddemosarchive.com/index.php?title=Amu-chan/Source/amu.pl&feed=atom&action=history Amu-chan/Source/amu.pl - Revision history 2024-03-28T19:10:45Z Revision history for this page on the wiki MediaWiki 1.23.9 https://kb.speeddemosarchive.com/index.php?title=Amu-chan/Source/amu.pl&diff=2582&oldid=prev Njahnke: New page: <pre><nowiki> #!/usr/bin/perl #nathan jahnke <njahnke@gmail.com> ### ATASHI NO KOKORO, UNLOCK! ### # Amu is distributed under the terms of the Gnu General Public License 3.0: # http://ww... 2008-10-12T05:37:49Z <p>New page: &lt;pre&gt;&lt;nowiki&gt; #!/usr/bin/perl #nathan jahnke &lt;njahnke@gmail.com&gt; ### ATASHI NO KOKORO, UNLOCK! ### # Amu is distributed under the terms of the Gnu General Public License 3.0: # http://ww...</p> <p><b>New page</b></p><div>&lt;pre&gt;&lt;nowiki&gt;<br /> #!/usr/bin/perl<br /> #nathan jahnke &lt;njahnke@gmail.com&gt;<br /> <br /> ### ATASHI NO KOKORO, UNLOCK! ###<br /> <br /> # Amu is distributed under the terms of the Gnu General Public License 3.0:<br /> # http://www.gnu.org/licenses/gpl-3.0.txt<br /> <br /> #TODO<br /> ##delimiter is whatever the first character in a new queue is<br /> ##alternative jobs based on os<br /> ##encryption?<br /> <br /> use warnings;<br /> use strict 'subs';<br /> package amu;<br /> <br /> use IO::Socket;<br /> use Sys::Hostname;<br /> use Sys::HostIP;<br /> use threads;<br /> use threads::shared;<br /> #use Thread::Queue;<br /> use List::Util qw(shuffle);<br /> use Cwd qw(abs_path);<br /> <br /> $myversion = 44;<br /> $VERBOSE = 1;<br /> $amudelim = &quot;;&quot;; #this currently delimits only jobs and their indices (keys as a hash) in the queue<br /> $port = 56677;<br /> $myip = Sys::HostIP-&gt;ip;<br /> $mypath = abs_path($0);<br /> my %amustatus :shared = ();<br /> <br /> open(AMUPL,$mypath);<br /> @amupl = &lt;AMUPL&gt;;<br /> close(AMUPL);<br /> <br /> @remote_hosts = ();<br /> if (-e &quot;amu_remotehosts.txt&quot;) {<br /> open(REMOTEHOSTS,&quot;amu_remotehosts.txt&quot;);<br /> while (&lt;REMOTEHOSTS&gt;) {<br /> chomp;<br /> if (($_ ne $myip) &amp;&amp; (!($_ =~ /^#/))) {<br /> push(@remote_hosts,$_) if $_;<br /> }<br /> }<br /> close(REMOTEHOSTS);<br /> }<br /> <br /> #intercept ctrl-c or kill from cli<br /> $SIG{INT} = $SIG{TERM} = \&amp;amushutdown;<br /> $SIG{HUP} = \&amp;amurestart;<br /> <br /> my %amuhash :shared = (); #it needs the my for some reason!?<br /> { #lock and load<br /> lock(%amuhash);<br /> $amuhash{&quot;STATUS&quot;} = &quot;OK&quot;;<br /> $amuhash{&quot;VERSION&quot;} = $myversion;<br /> $amuhash{&quot;QUEUE&quot;} = &quot;&quot;;<br /> $amuhash{&quot;JOB&quot;} = &quot;&quot;;<br /> $amuhash{&quot;REMOTE_HOSTS&quot;} = join(&quot; &quot;,@remote_hosts);<br /> }<br /> print &quot;starting server_thread ...\n&quot; if $VERBOSE;<br /> $server_thread = threads-&gt;create(\&amp;server_thread);<br /> <br /> #status updates every 5 seconds<br /> print &quot;starting status_threads_infinite_loop ...\n&quot; if $VERBOSE;<br /> threads-&gt;create(\&amp;status_threads_infinite_loop);<br /> <br /> print &quot;Amu version $myversion started successfully!\n&quot;;<br /> <br /> <br /> while ($amuhash{&quot;STATUS&quot;} =~ /OK|QUEUEING|JANKEN|WORKING/) {<br /> #update @remote_hosts - don't want to have to lock %amuhash every time we contact people<br /> {<br /> lock(%amuhash);<br /> @remote_hosts = split(&quot; &quot;,$amuhash{&quot;REMOTE_HOSTS&quot;});<br /> }<br /> <br /> if ($amuhash{&quot;STATUS&quot;} =~ /QUEUEING/) {<br /> print &quot;entering status mode block QUEUEING\n&quot; if $VERBOSE;<br /> if ($amuhash{&quot;QUEUE&quot;} ne '') {<br /> #distribute the queue to all known other amus ... a lot will get it and ignore because they're already in QUEUEING mode but this will help ensure everyone gets it - BEFORE we claim a job<br /> threads-&gt;create(\&amp;status_threads, &quot;DO &quot;.$amuhash{&quot;QUEUE&quot;}, @remote_hosts)-&gt;join();<br /> my $jobnum;<br /> if ($amuhash{&quot;QUEUE&quot;} ne '') { #check again to make sure our queue hasn't been emptied since we sent the queue to others<br /> {<br /> print &quot;about to lock the hash...\n&quot; if $VERBOSE;<br /> lock(%amuhash);<br /> print &quot;locked the hash\n&quot; if $VERBOSE;<br /> my %jobs = split($amudelim,$amuhash{&quot;QUEUE&quot;});<br /> #pick random queue item<br /> my @joblist = (%jobs);<br /> $jobnum = int(rand(keys %jobs));<br /> $jobnum = $joblist[$jobnum*2];<br /> #claim it<br /> print &quot;claiming job $jobnum\n&quot; if $VERBOSE;<br /> $amuhash{&quot;JOB&quot;} = $jobnum;<br /> #and get ready to fight for it<br /> $amuhash{&quot;STATUS&quot;} = &quot;JANKEN&quot;;<br /> }<br /> #sleep 5;<br /> %objections = &amp;status_threads(&quot;CLAIM &quot;.$jobnum, @remote_hosts);<br /> }<br /> }<br /> if ($amuhash{&quot;STATUS&quot;} ne &quot;JANKEN&quot;) { #no more jobs for us to do<br /> print &quot;no more jobs for us to do\n&quot; if $VERBOSE;<br /> lock(%amuhash);<br /> $amuhash{&quot;STATUS&quot;} = &quot;OK&quot;;<br /> }<br /> }<br /> if ($amuhash{&quot;STATUS&quot;} =~ /JANKEN/) {<br /> print &quot;entering status mode block JANKEN\n&quot; if $VERBOSE;<br /> if (%objections) {<br /> foreach $evilhost (keys %objections) {<br /> last if $amuhash{&quot;STATUS&quot;} eq &quot;QUEUEING&quot;; #i've already lost<br /> #generate my random number<br /> $random = rand();<br /> $random =~ s/^0.//;<br /> {<br /> lock(%amuhash);<br /> $amuhash{&quot;JANKEN&quot;} = $random;<br /> }<br /> #broadcast<br /> print &quot;asking for janken - job $amuhash{JOB}\n&quot; if $VERBOSE;<br /> my @janken = &amp;status_threads(&quot;JANKEN&quot;, $evilhost);<br /> if (@janken) { #did anyone play with me?<br /> if ($janken[1] &gt; $random) { #i lost<br /> print &quot;i lost at janken\n&quot; if $VERBOSE;<br /> lock(%amuhash);<br /> my %jobs = split($amudelim,$amuhash{&quot;QUEUE&quot;});<br /> if (exists($jobs{$amuhash{&quot;JOB&quot;}})) {<br /> #give this job up<br /> delete($jobs{$amuhash{&quot;JOB&quot;}});<br /> $amuhash{&quot;QUEUE&quot;} = join($amudelim,%jobs);<br /> }<br /> print &quot;trying to get another job; changing status back to QUEUEING ...\n&quot; if $VERBOSE;<br /> $amuhash{&quot;STATUS&quot;} = &quot;QUEUEING&quot;; #try to get another job<br /> } elsif ($janken[1] == $random) { #a tie<br /> print &quot;a tie at janken!?\n&quot; if $VERBOSE;<br /> redo;<br /> }<br /> } else {<br /> print &quot;no responses for janken\n&quot; if $VERBOSE;<br /> }<br /> }<br /> {<br /> lock(%amuhash);<br /> undef $amuhash{&quot;JANKEN&quot;};<br /> }<br /> }<br /> {<br /> lock(%amuhash);<br /> $amuhash{&quot;STATUS&quot;} = &quot;WORKING&quot; if $amuhash{&quot;STATUS&quot;} ne &quot;QUEUEING&quot;;<br /> }<br /> }<br /> if ($amuhash{&quot;STATUS&quot;} =~ /WORKING/) {<br /> print &quot;entering status mode block WORKING\n&quot; if $VERBOSE;<br /> my ($jobnum, %jobs);<br /> {<br /> lock(%amuhash);<br /> %jobs = split($amudelim,$amuhash{&quot;QUEUE&quot;});<br /> $jobnum = $amuhash{&quot;JOB&quot;};<br /> }<br /> #run the command<br /> print &quot;executing $jobs{$jobnum} ...\n&quot; if $VERBOSE;<br /> system($jobs{$jobnum});<br /> #all dun<br /> {<br /> lock(%amuhash);<br /> my %jobs = split($amudelim,$amuhash{&quot;QUEUE&quot;});<br /> delete($jobs{$amuhash{&quot;JOB&quot;}});<br /> $amuhash{&quot;QUEUE&quot;} = join($amudelim,%jobs);<br /> $amuhash{&quot;JOB&quot;} = &quot;&quot;;<br /> $amuhash{&quot;STATUS&quot;} = &quot;QUEUEING&quot;;<br /> }<br /> }<br /> sleep 1;<br /> }<br /> sleep 15;<br /> exec($mypath) if ($amuhash{&quot;STATUS&quot;} =~ /RESTART/);<br /> exit 0 if ($amuhash{&quot;STATUS&quot;} =~ /SHUTDOWN/);<br /> <br /> <br /> sub version_check {<br /> print &quot;Checking the network for a newer version of Amu ...\n&quot; if $VERBOSE;<br /> {<br /> lock(%amustatus);<br /> @knowngoodamus = (keys %amustatus);<br /> }<br /> %hostversions = &amp;status_threads(&quot;VERSION&quot;, @knowngoodamus);<br /> foreach $amuversion (sort { $a &lt; $b } keys %hostversions) {<br /> print &quot;$amuversion : $hostversions{$amuversion}\n&quot; if $VERBOSE;<br /> if ($amuversion &gt; $myversion) {<br /> &amp;status_threads(&quot;AMUPL&quot;, $hostversions{$amuversion});<br /> last;<br /> }<br /> }<br /> }<br /> <br /> sub status_threads_infinite_loop {<br /> while ($amuhash{&quot;STATUS&quot;} =~ /OK|QUEUEING|JANKEN|WORKING/) {<br /> if ($amuhash{&quot;STATUS&quot;} =~ /OK/) {<br /> {<br /> lock(%amuhash);<br /> @remote_hosts = split(&quot; &quot;,$amuhash{&quot;REMOTE_HOSTS&quot;});<br /> }<br /> @remote_hosts = shuffle(@remote_hosts);<br /> my ($status_thread) = threads-&gt;create(\&amp;status_threads, &quot;STATUS&quot;, @remote_hosts);<br /> my %foundamus = $status_thread-&gt;join();<br /> {<br /> lock(%amustatus);<br /> %amustatus = %foundamus;<br /> }<br /> &amp;version_check;<br /> }<br /> sleep 5;<br /> }<br /> print &quot;status_threads_infinite_loop shutting down\n&quot; if $VERBOSE;<br /> return;<br /> }<br /> <br /> sub status_threads {<br /> my $command = shift;<br /> my %threads;<br /> my %foundamus; #temporary hash to avoid locking the shared one while we build up responses<br /> foreach $remote_host (@_) {<br /> ($threads{$remote_host}) = threads-&gt;create(\&amp;hostname_contact, $command, $remote_host);<br /> }<br /> foreach $remote_host (keys %threads) {<br /> @remote_response = $threads{$remote_host}-&gt;join();<br /> if (defined $remote_response[2]) { #not an error<br /> if ($remote_response[1] =~ /AMUPL/) {<br /> shift(@remote_response); #kill the remote host<br /> shift(@remote_response); #kill the command<br /> for (@remote_response) { #make sure this is the entire amu.pl<br /> $amuplgood = 1 if m/^__END__/;<br /> }<br /> if ($amuplgood) {<br /> open(NEWAMUPL,&quot;&gt;$mypath&quot;);<br /> for (@remote_response) { #and print the new script<br /> print NEWAMUPL;<br /> }<br /> close(NEWAMUPL);<br /> print &quot;Upgraded to a new version of Amu! Restarting Amu in 15 seconds ...\n&quot;;<br /> {<br /> lock(%amuhash);<br /> $amuhash{&quot;STATUS&quot;} = &quot;RESTART&quot;;<br /> }<br /> }<br /> } elsif ($remote_response[1] =~ /VERSION/) {<br /> #backwards so that the version is the key and the host is the value: we want only one host - the first to reply - per version<br /> if (!(exists($foundamus{$remote_response[2]}))) {<br /> $foundamus{$remote_response[2]} = $remote_response[0];<br /> }<br /> } else {<br /> $foundamus{$remote_response[0]} = $remote_response[2];<br /> }<br /> } else {<br /> #handle errors<br /> }<br /> }<br /> return %foundamus;<br /> }<br /> <br /> sub hostname_contact {<br /> my $command = shift;<br /> my $remote_host = shift;<br /> my @retval = ($remote_host);<br /> print &quot;trying $remote_host ...\n&quot; if $VERBOSE;<br /> $| = 1 if $VERBOSE; #flush output buffer<br /> if (my $socket = IO::Socket::INET-&gt;new(PeerAddr =&gt; $remote_host,<br /> PeerPort =&gt; $port,<br /> Proto =&gt; &quot;tcp&quot;,<br /> Type =&gt; SOCK_STREAM,<br /> Timeout =&gt; 5 )) {<br /> print $socket &quot;AMU $command\n&quot;;<br /> my @answer = &lt;$socket&gt;;<br /> print &quot;contact with $remote_host\n&quot; if $VERBOSE;<br /> my $firstline = $answer[0];<br /> if ($firstline) {<br /> chomp($firstline);<br /> @remote_host_status = split(&quot; &quot;,$firstline);<br /> $SYNTAX_ERROR_BAD_ARGUMENT = &quot;SYNTAX_ERROR_BAD_ARGUMENT&quot;;<br /> if (($remote_host_status[0] =~ /AMU/) &amp;&amp; (defined $remote_host_status[1]) &amp;&amp; (defined $remote_host_status[2])) {<br /> if ($remote_host_status[1] =~ /STATUS/) {<br /> if ($remote_host_status[2] =~ /OK|QUEUEING|JANKEN|WORKING/) {<br /> push(@retval, $remote_host_status[1], $remote_host_status[2]);<br /> } else {<br /> push(@retval, $SYNTAX_ERROR_BAD_ARGUMENT);<br /> }<br /> } elsif ($remote_host_status[1] =~ /VERSION|CLAIM|JANKEN/) {<br /> if (defined $remote_host_status[2]) {<br /> push(@retval, $remote_host_status[1], join(&quot; &quot;,@remote_host_status[2..$#remote_host_status]));<br /> } else {<br /> push(@retval, $SYNTAX_ERROR_BAD_ARGUMENT);<br /> }<br /> } elsif ($remote_host_status[1] =~ /AMUPL/) {<br /> if ($remote_host_status[2] =~ m,#!/usr/bin/perl,) {<br /> push(@retval, $remote_host_status[1], $remote_host_status[2].&quot;\n&quot;);<br /> shift(@answer); #don't need the first line again<br /> push(@retval, @answer);<br /> } else {<br /> push(@retval, $SYNTAX_ERROR_BAD_ARGUMENT);<br /> }<br /> } else {<br /> push(@retval, &quot;SYNTAX_ERROR_BAD_COMMAND&quot;);<br /> }<br /> } else {<br /> push(@retval, &quot;NOT_AMU&quot;);<br /> }<br /> }<br /> close($socket);<br /> } else {<br /> print &quot;\n&quot; if $VERBOSE;<br /> push(@retval, &quot;CONNECTION_REFUSED_OR_TIMED_OUT&quot;);<br /> }<br /> return @retval;<br /> }<br /> <br /> sub server_thread {<br /> $server = IO::Socket::INET-&gt;new(LocalPort =&gt; $port,<br /> Type =&gt; SOCK_STREAM,<br /> Reuse =&gt; 1,<br /> Listen =&gt; 10)<br /> or die &quot;Couldn't be a tcp server on port $port : $@\n&quot;;<br /> <br /> while ($amuhash{&quot;STATUS&quot;} =~ /OK|QUEUEING|JANKEN|WORKING/) {<br /> $client = $server-&gt;accept();<br /> recv($client, $question, 1024, 0);<br /> chomp($question);<br /> print &quot;$question\n&quot; if $VERBOSE;<br /> @remote_question = split(&quot; &quot;,$question);<br /> if ($remote_question[0] =~ /AMU/) {<br /> lock(%amuhash);<br /> if (defined $amuhash{$remote_question[1]}) {<br /> print $client &quot;AMU $remote_question[1] $amuhash{$remote_question[1]}\n&quot;;<br /> } elsif ($remote_question[1] =~ /AMUPL/) {<br /> print $client &quot;AMU $remote_question[1] &quot;;<br /> for (@amupl) {<br /> print $client $_;<br /> }<br /> print $client &quot;\n&quot;; #just in case there's no carriage return at the end of amu.pl<br /> } elsif (($remote_question[1] =~ /HOSTS/) &amp;&amp; (defined $remote_question[2])) {<br /> print &quot;received new host list\n&quot; if $VERBOSE;<br /> my %newhosts = split(&quot;;&quot;,$remote_question[2]);<br /> $newhosts{$myip} = 1; #sign off that i have seen this list<br /> my @ignoranthosts;<br /> @remote_hosts = ();<br /> foreach $host (keys %newhosts) {<br /> push(@remote_hosts,$host) if $host ne $myip;<br /> if (!($newhosts{$host})) { #these haven't heard about the new host list yet<br /> print &quot;$host hasn't yet heard about the new host list\n&quot; if $VERBOSE;<br /> push(@ignoranthosts,$host);<br /> }<br /> }<br /> $amuhash{&quot;REMOTE_HOSTS&quot;} = join(&quot; &quot;,@remote_hosts);<br /> &amp;status_threads(&quot;HOSTS &quot;.join(&quot;;&quot;,%newhosts), @ignoranthosts);<br /> } elsif (($remote_question[1] =~ /DO/) &amp;&amp; ($amuhash{&quot;STATUS&quot;} eq &quot;OK&quot;) &amp;&amp; (defined $remote_question[2])) {<br /> my $remote_jobs = join(&quot; &quot;,@remote_question[2..$#remote_question]);<br /> print &quot;new job queue '$remote_jobs' has arrived\n&quot; if $VERBOSE;<br /> #new job queue has arrived<br /> $amuhash{&quot;QUEUE&quot;} = $remote_jobs;<br /> $amuhash{&quot;STATUS&quot;} = &quot;QUEUEING&quot;;<br /> } elsif (($remote_question[1] =~ /CLAIM/) &amp;&amp; ($amuhash{&quot;QUEUE&quot;} ne '') &amp;&amp; (defined $remote_question[2])) {<br /> my $remote_job = join(&quot; &quot;,@remote_question[2..$#remote_question]);<br /> if ($amuhash{&quot;JOB&quot;} eq $remote_job) {<br /> #no! that's my job!<br /> print &quot;objecting to job $remote_job\n&quot; if $VERBOSE;<br /> print $client &quot;AMU &quot;.join(&quot; &quot;,@remote_question[1..$#remote_question]).&quot;\n&quot;;<br /> } else {<br /> my %jobs = split($amudelim,$amuhash{&quot;QUEUE&quot;});<br /> if (exists($jobs{$remote_job})) {<br /> #since i have no objections about others claiming this job...<br /> print &quot;deleting job $remote_job\n&quot; if $VERBOSE;<br /> delete($jobs{$remote_job});<br /> $amuhash{&quot;QUEUE&quot;} = join($amudelim,%jobs);<br /> }<br /> }<br /> } else {<br /> #cool and spicy<br /> }<br /> }<br /> close($client);<br /> }<br /> close($server);<br /> print &quot;server_thread shutting down\n&quot; if $VERBOSE;<br /> return;<br /> }<br /> <br /> sub amurestart {<br /> {<br /> lock(%amuhash);<br /> $amuhash{&quot;STATUS&quot;} = &quot;RESTART&quot;;<br /> }<br /> &amp;hostname_contact(&quot;SHUTDOWN&quot;,$myip); #to knock the server thread out of its infinite loop<br /> }<br /> <br /> sub amushutdown {<br /> $| = 1;<br /> print &quot;Shutting down in about 15 seconds ...&quot;;<br /> {<br /> lock(%amuhash);<br /> $amuhash{&quot;STATUS&quot;} = &quot;SHUTDOWN&quot;;<br /> }<br /> &amp;hostname_contact(&quot;SHUTDOWN&quot;,$myip); #to knock the server thread out of its infinite loop<br /> }<br /> <br /> __END__<br /> &lt;/nowiki&gt;&lt;/pre&gt;</div> Njahnke