#!/usr/bin/perl require broker; require IO::Select; require IO::Socket; use Fcntl; $port = shift || 6501; $io_port = shift || 6500; if(fork()) { $SIG{'CHLD'} = IGNORE; exit(0); } else { close(STDIN); close(STDOUT); close(STDERR); $main_socket = IO::Socket::INET->new( Listen => 5, LocalPort => $port, Proto => 'tcp', Reuse => 1); die "Couldn't create socket on $port (already running?)" if(!$main_socket); $select = IO::Select->new($main_socket); $io_socket = connect_io($io_port); die "Couldn't open socket to broker on $io_port (is it running?)" if(!$io_socket); $io_select = IO::Select->new($io_socket); $alive = 1; $con_id = 0; $owner = undef; $SIG{'CHLD'} = IGNORE; $SIG{'INT'} = cleanshutdown; $SIG{'TERM'} = cleanshutdown; $SIG{'PIPE'} = IGNORE; while($alive) { # check and see if anyone is waiting at the door @readable = $select->can_read(0.01); foreach $sock (@readable) { if ($sock eq $main_socket) { $sock = $main_socket->accept(); $sockets{$sock} = $sock; $select->add($sock); $priority{$sock} = 1; $queue{$sock} = (); print $sock "BATMOD>"; } else { $in = <$sock>; if(! defined $in) { # hang up $select->remove($sock); delete $priority{$sock}; delete $sockets{$sock}; delete $queue{$sock}; $sock->close(); } else { # do something $incr = $in; $incr =~ s/\n//; $incr =~ s/\r//; @cmd = split(/ /,$incr); $c = lc @cmd[0]; if($c eq "priority") { $priority{$sock} = $cmd[1]; print $sock "OK $cmd[1]\nBATMOD>"; } elsif($c eq "shutdown") { $alive = 0; } elsif($c eq "quit") { $select->remove($sock); delete $priority{$sock}; delete $sockets{$sock}; delete $queue{$sock}; $sock->close(); } else { push(@{$queue{$sock}},$in); } } } } # check to see if any more data has come in @readable = $io_select->can_read(0); foreach $io_sock (@readable) { $io_sock->recv($in,255,0); if(! defined $in) { # they hung up # keep trying to call back $io_select->remove($io_socket); $io_socket->close(); while(($io_socket = connect_io($io_port))) {}; $io_select->add($io_socket); } else { # we have some data # write it to the owner if they're writable if($owner) { $write_select = IO::Select->new($owner); ($write_socket) = $write_select->can_write(0.01); print $write_socket $in; } if($in =~ /BATMOD>/) { # release owner $owner = undef; } } } if(!$owner) { $last_pri = 100; # seed with a improbably large number $winner = undef; foreach $baz (keys %priority) { $pri = $priority{$baz}; if(($pri < $last_pri) && (@{$queue{$baz}} > 0)) { $winner = $baz; $last_pri = $pri; } } if($winner) { $owner = $sockets{$winner}; $cmd = pop(@{$queue{$winner}}); print $io_socket $cmd; } } } } # end child sub cleanshutdown { my $sig = shift; $alive = 0; $reason = "Got signal: $sig"; } sub connect_io { my $port = shift; my $i; for($i=0;$i<32;$i++) { my $sock = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $port); fcntl($sock,O_SETFL,O_NONBLOCK); return($sock) if($sock); sleep(1); } return undef; }