3 # conmux-registry -- console name registry server
5 # Main registry server. This server holds host/port assignments for
6 # conmux daemons registering with it. This allows users to specify
7 # human names for their consoles and find the relevant conmux daemon.
9 # (C) Copyright IBM Corp. 2004, 2005, 2006
10 # Author: Andy Whitcroft <andyw@uk.ibm.com>
12 # The Console Multiplexor is released under the GNU Public License V2
17 use Symbol
qw(gensym);
23 # Find our internal libraries.
24 use lib
$FindBin::Bin
;
25 use lib
"$FindBin::Bin/../lib/";
26 use lib
"$FindBin::Bin/lib/";
29 our $P = 'conmux-registry';
33 # LISTENER SOCKET: creates an intenet listener for new clients and
34 # connects them to the junction provided.
36 package ListenerSocket
;
39 my ($class, $mux, $port, $registry) = @_;
40 my $self = bless { 'mux' => $mux, 'registry' => $registry }, $class;
42 print "ListenerSocket::new [$self] mux<$mux> port<$port> " .
43 "registry<$registry>\n" if ($main::debug
);
45 $self->initialise($mux, $port, $registry);
51 my ($self, $mux, $port, $registry) = @_;
54 print "ListenerSocket::initialise [$self] mux<$mux> port<$port> " .
55 "registry<$registry>\n" if ($main::debug
);
57 # Create a listening socket and add it to the multiplexor.
58 my $sock = new IO
::Socket
::INET
(Proto
=> 'tcp',
64 print " adding $self $sock\n" if ($main::debug
);
66 $mux->set_callback_object($self, $sock);
67 $self->{'listener'} = $sock;
70 # Handle new connections by instantiating a new client class.
72 my ($self, $mux, $fh) = @_;
75 print "ListenerSocket::mux_connection [$self] mux<$mux> fh<$fh>\n"
78 # Make a new client connection.
79 $client = Client
->new($mux, $fh, $self->{'registry'});
80 print " new connection $self $client\n" if ($main::debug
);
86 print "ListenerSocket::DESTROY [$self]\n" if ($main::debug
);
88 close($self->{'listener'});
92 # CLIENT: general client object, represents a remote client channel
97 my ($class, $mux, $fh, $registry) = @_;
98 my $self = bless { 'mux' => $mux,
100 'registry' => $registry }, $class;
102 print "Client::new [$self] mux<$mux> fh<$fh> registry<$registry>\n"
105 $self->initialise($mux, $fh, $registry);
111 my ($self, $mux, $fh, $registry) = @_;
113 print "Client::initialise [$self] mux<$mux> fh<$fh> " .
114 "registry<$registry>\n" if ($main::debug
);
116 $mux->set_callback_object($self, $fh);
120 my ($self, $mux, $fh, $input) = @_;
122 print "Client::mux_input [$self] mux<$mux> fh<$fh> input<$$input>\n"
125 while ($$input =~ s/^(.*?)\n//) {
126 my ($cmd, $args) = split(' ', $1, 2);
127 my (%args) = Conmux
::decodeArgs
($args);
130 'status' => 'ENOSYS',
133 # Fill in the common results.
134 $reply->{'title'} = 'registry';
136 # Handle this command.
137 if ($cmd eq "LOOKUP") {
138 my $r = $self->{'registry'}->lookup($args{'service'});
141 $reply->{'result'} = $r;
142 $reply->{'status'} = 'OK';
145 $reply->{'status'} = 'ENOENT entry not found';
148 } elsif ($cmd eq "ADD") {
149 $self->{'registry'}->add($args{'service'},
151 $reply->{'status'} = 'OK';
153 } elsif ($cmd eq "LIST") {
154 $reply->{'result'} = $self->{'registry'}->list();
155 $reply->{'status'} = 'OK';
158 $fh->write(Conmux
::encodeArgs
($reply) . "\n");
162 my ($self, $mux, $fh, $input) = @_;
164 print "Client::mux_eof [$self] mux<$mux> fh<$fh> input<$input>\n"
167 # Handle any pending input, then remove myself.
168 $self->mux_input($mux, $fh, $input);
170 # Tell the multiplexor we no longer are using this channel.
171 $mux->shutdown($fh, 1);
174 my ($self, $mux, $fn) = @_;
176 print "Client::close [$self]\n" if ($main::debug
);
182 print "Client::DESTROY [$self]\n" if ($main::debug
);
186 # REGISTRY: registry elements.
191 my ($class, $store) = @_;
192 my $self = bless { 'store' => $store }, $class;
196 print "Registry::new [$self] store<$store>\n" if ($main::debug
);
198 # Open the store and populate the keys.
199 open(S
, '<', $store) || die "Registry::new: $store: open failed - $!\n";
203 ($key, $val) = split(' ', $_);
205 $self->{'key'}->{$key} = $val;
213 my ($self, $what, $where) = @_;
217 print "Registry::add [$self] what<$what> where<$where>\n"
220 $self->{'key'}->{$what} = $where;
222 print "$what at $where\n";
224 if (open(S
, '>', $self->{'store'} . '.new')) {
225 foreach $key (sort keys %{$self->{'key'}}) {
226 print S
"$key $self->{'key'}->{$key}\n";
229 rename $self->{'store'} . '.new', $self->{'store'};
232 warn "$P: $self->{'store'}.new: open failed - $!";
237 my ($self, $what) = @_;
239 print "Registry::lookup [$self] what<$what>\n" if ($main::debug
);
241 $self->{'key'}->{$what};
248 print "Registry::list [$self]\n" if ($main::debug
);
250 foreach $key (sort keys %{$self->{'key'}}) {
251 $r .= "$key $self->{'key'}->{$key}\n";
258 # MAIN: makes the IO multiplexor, listener and registry and stitches
265 print STDERR
"Usage: $P <local port> <store>\n";
268 my ($lport, $store) = @ARGV;
270 # Make a new multiplexer.
271 my $mux = new IO
::Multiplex
;
273 # Make the registry object.
274 my $registry = Registry
->new($store);
276 # Create the client listener socket.
277 my $listener = ListenerSocket
->new($mux, $lport, $registry);
279 # Hand over to the multiplexor.