File Coverage

blib/lib/Event/RPC/Server.pm
Criterion Covered Total %
statement 235 287 81.8
branch 45 68 66.1
condition 2 4 50.0
subroutine 65 94 69.1
pod 10 77 12.9
total 357 530 67.3


line stmt bran cond sub pod time code
1             #-----------------------------------------------------------------------
2             # Copyright (C) 2005-2015 by Jörn Reder .
3             # All Rights Reserved. See file COPYRIGHT for details.
4             #
5             # This module is part of Event::RPC, which is free software; you can
6             # redistribute it and/or modify it under the same terms as Perl itself.
7             #-----------------------------------------------------------------------
8              
9             package Event::RPC::Server;
10              
11 34     34   756955 use Event::RPC;
  34         143  
  34         1046  
12 22     22   9146 use Event::RPC::Connection;
  22         71  
  22         695  
13 22     22   8760 use Event::RPC::LogConnection;
  22         69  
  22         623  
14 22     22   123 use Event::RPC::Message::Negotiate;
  22         59  
  22         475  
15              
16 22     22   97 use Carp;
  22         42  
  22         1042  
17 22     22   127 use strict;
  22         67  
  22         405  
18 22     22   111 use utf8;
  22         46  
  22         106  
19              
20 22     22   5599 use IO::Socket::INET;
  22         190454  
  22         286  
21 22     22   21727 use Sys::Hostname;
  22         50322  
  22         72578  
22              
23 20     20 0 65 sub get_host { shift->{host} }
24 20     20 0 65 sub get_port { shift->{port} }
25 20     20 0 337 sub get_name { shift->{name} }
26 444     444 0 2203 sub get_loop { shift->{loop} }
27 20     20 0 71 sub get_classes { shift->{classes} }
28 49     49 0 177 sub get_singleton_classes { shift->{singleton_classes} }
29 0     0 0 0 sub get_loaded_classes { shift->{loaded_classes} }
30 68     68 1 509 sub get_clients_connected { shift->{clients_connected} }
31 40     40 1 374 sub get_log_clients_connected { shift->{log_clients_connected} }
32 40     40 0 278 sub get_logging_clients { shift->{logging_clients} }
33 575     575 0 1062 sub get_logger { shift->{logger} }
34 20     20 0 83 sub get_start_log_listener { shift->{start_log_listener} }
35 76     76 0 192 sub get_objects { shift->{objects} }
36 0     0 0 0 sub get_rpc_socket { shift->{rpc_socket} }
37 40     40 0 178 sub get_ssl { shift->{ssl} }
38 6     6 0 25 sub get_ssl_key_file { shift->{ssl_key_file} }
39 6     6 0 27 sub get_ssl_cert_file { shift->{ssl_cert_file} }
40 3     3 0 205 sub get_ssl_passwd_cb { shift->{ssl_passwd_cb} }
41 3     3 0 8 sub get_ssl_opts { shift->{ssl_opts} }
42 125     125 0 1314 sub get_auth_required { shift->{auth_required} }
43 4     4 0 16 sub get_auth_passwd_href { shift->{auth_passwd_href} }
44 11     11 0 32 sub get_auth_module { shift->{auth_module} }
45 20     20 0 265 sub get_listeners_started { shift->{listeners_started} }
46 46     46 0 139 sub get_connection_hook { shift->{connection_hook} }
47 60     60 0 179 sub get_load_modules { shift->{load_modules} }
48 0     0 0 0 sub get_auto_reload_modules { shift->{auto_reload_modules} }
49 3     3 1 15 sub get_active_connection { shift->{active_connection} }
50 56     56 0 346 sub get_message_formats { shift->{message_formats} }
51 20     20 0 104 sub get_insecure_msg_fmt_ok { shift->{insecure_msg_fmt_ok} }
52              
53 0     0 0 0 sub set_host { shift->{host} = $_[1] }
54 0     0 0 0 sub set_port { shift->{port} = $_[1] }
55 0     0 0 0 sub set_name { shift->{name} = $_[1] }
56 0     0 0 0 sub set_loop { shift->{loop} = $_[1] }
57 0     0 0 0 sub set_classes { shift->{classes} = $_[1] }
58 0     0 0 0 sub set_singleton_classes { shift->{singleton_classes} = $_[1] }
59 0     0 0 0 sub set_loaded_classes { shift->{loaded_classes} = $_[1] }
60 46     46 0 123 sub set_clients_connected { shift->{clients_connected} = $_[1] }
61 40     40 0 119 sub set_log_clients_connected { shift->{log_clients_connected}= $_[1] }
62 0     0 0 0 sub set_logging_clients { shift->{logging_clients} = $_[1] }
63 0     0 0 0 sub set_logger { shift->{logger} = $_[1] }
64 0     0 0 0 sub set_start_log_listener { shift->{start_log_listener} = $_[1] }
65 0     0 0 0 sub set_objects { shift->{objects} = $_[1] }
66 20     20 0 102 sub set_rpc_socket { shift->{rpc_socket} = $_[1] }
67 0     0 0 0 sub set_ssl { shift->{ssl} = $_[1] }
68 0     0 0 0 sub set_ssl_key_file { shift->{ssl_key_file} = $_[1] }
69 0     0 0 0 sub set_ssl_cert_file { shift->{ssl_cert_file} = $_[1] }
70 0     0 0 0 sub set_ssl_passwd_cb { shift->{ssl_passwd_cb} = $_[1] }
71 0     0 0 0 sub set_ssl_opts { shift->{ssl_opts} = $_[1] }
72 0     0 0 0 sub set_auth_required { shift->{auth_required} = $_[1] }
73 0     0 0 0 sub set_auth_passwd_href { shift->{auth_passwd_href} = $_[1] }
74 4     4 0 15 sub set_auth_module { shift->{auth_module} = $_[1] }
75 20     20 0 62 sub set_listeners_started { shift->{listeners_started} = $_[1] }
76 0     0 0 0 sub set_connection_hook { shift->{connection_hook} = $_[1] }
77 0     0 0 0 sub set_load_modules { shift->{load_modules} = $_[1] }
78 0     0 0 0 sub set_auto_reload_modules { shift->{auto_reload_modules} = $_[1] }
79 298     298 0 603 sub set_active_connection { shift->{active_connection} = $_[1] }
80 20     20 0 138 sub set_message_formats { shift->{message_formats} = $_[1] }
81 0     0 0 0 sub set_insecure_msg_fmt_ok { shift->{insecure_msg_fmt_ok} = $_[1] }
82              
83             my $INSTANCE;
84 4     4 1 47 sub instance { $INSTANCE }
85              
86             sub get_max_packet_size {
87 0     0 1 0 return Event::RPC::Message->get_max_packet_size;
88             }
89              
90             sub set_max_packet_size {
91 1     1 1 7 my $class = shift;
92 1         3 my ($value) = @_;
93 1         16 Event::RPC::Message->set_max_packet_size($value);
94             }
95              
96             sub new {
97 20     20 0 29661 my $class = shift;
98 20         628 my %par = @_;
99             my ($host, $port, $classes, $name, $logger, $start_log_listener) =
100 20         149 @par{'host','port','classes','name','logger','start_log_listener'};
101             my ($ssl, $ssl_key_file, $ssl_cert_file, $ssl_passwd_cb, $ssl_opts) =
102 20         99 @par{'ssl','ssl_key_file','ssl_cert_file','ssl_passwd_cb','ssl_opts'};
103             my ($auth_required, $auth_passwd_href, $auth_module, $loop) =
104 20         150 @par{'auth_required','auth_passwd_href','auth_module','loop'};
105             my ($connection_hook, $auto_reload_modules) =
106 20         78 @par{'connection_hook','auto_reload_modules'};
107             my ($load_modules, $message_formats, $insecure_msg_fmt_ok) =
108 20         105 @par{'load_modules','message_formats','insecure_msg_fmt_ok'};
109              
110 20   50     162 $name ||= "Event-RPC-Server";
111 20 100       115 $insecure_msg_fmt_ok = 1 unless defined $insecure_msg_fmt_ok;
112              
113             #-- for backwards compatibility 'load_modules' defaults to 1
114 20 50       95 if ( !exists $par{load_modules} ) {
115 0         0 $load_modules = 1;
116             }
117              
118 20 50       115 if ( not $loop ) {
119 20         168 foreach my $impl ( qw/AnyEvent Event Glib/ ) {
120 20         77 $loop = "Event::RPC::Loop::$impl";
121 20     20   1671 eval "use $loop";
  20         10377  
  20         67  
  20         365  
122 20 50       123 if ( $@ ) {
123 0         0 $loop = undef;
124             }
125             else {
126 20         143 $loop = $loop->new;
127 20         100 last;
128             }
129             }
130 20 50       151 die "It seems no supported event loop module is installed"
131             unless $loop;
132             }
133              
134 20         1301 my $self = bless {
135             host => $host,
136             port => $port,
137             name => $name,
138             classes => $classes,
139             singleton_classes => {},
140             logger => $logger,
141             start_log_listener => $start_log_listener,
142             loop => $loop,
143              
144             ssl => $ssl,
145             ssl_key_file => $ssl_key_file,
146             ssl_cert_file => $ssl_cert_file,
147             ssl_passwd_cb => $ssl_passwd_cb,
148             ssl_opts => $ssl_opts,
149              
150             auth_required => $auth_required,
151             auth_passwd_href => $auth_passwd_href,
152             auth_module => $auth_module,
153              
154             load_modules => $load_modules,
155             auto_reload_modules => $auto_reload_modules,
156             connection_hook => $connection_hook,
157              
158             message_formats => $message_formats,
159             insecure_msg_fmt_ok => $insecure_msg_fmt_ok,
160              
161             rpc_socket => undef,
162             loaded_classes => {},
163             objects => {},
164             logging_clients => {},
165             clients_connected => 0,
166             listeners_started => 0,
167             log_clients_connected => 0,
168             active_connection => undef,
169             }, $class;
170              
171 20         79 $INSTANCE = $self;
172              
173 20         249 $self->log ($self->get_name." started");
174              
175 20         165 return $self;
176             }
177              
178             sub DESTROY {
179 0     0   0 my $self = shift;
180              
181 0         0 my $rpc_socket = $self->get_rpc_socket;
182 0 0       0 close ($rpc_socket) if $rpc_socket;
183              
184 0         0 1;
185             }
186              
187             sub probe_message_formats {
188 33     33 0 89 my $class = shift;
189 33         121 my ($user_supplied_formats, $insecure_msg_fmt_ok) = @_;
190              
191 33         503 my $order_lref = Event::RPC::Message::Negotiate->message_format_order;
192 33         322 my $modules_by_name = Event::RPC::Message::Negotiate->known_message_formats;
193              
194 33         133 my %probe_formats;
195 33 100       126 if ( $user_supplied_formats ) {
196 25         265 @probe_formats{@{$user_supplied_formats}} =
197 25         55 (1) x @{$user_supplied_formats};
  25         61  
198             }
199             else {
200 8         17 %probe_formats = %{$modules_by_name};
  8         214  
201             }
202              
203             #-- By default we probe all supported formats, but
204             #-- not Storable. User has to activate this explicitely.
205 33 100       130 if ( not $insecure_msg_fmt_ok ) {
206 3         8 delete $probe_formats{STOR};
207             }
208              
209 33         243 Event::RPC::Message::Negotiate->set_storable_fallback_ok($insecure_msg_fmt_ok);
210              
211 33         140 my @supported_formats;
212 33         57 foreach my $name ( @{$order_lref} ) {
  33         216  
213 132 100       421 next unless $probe_formats{$name};
214              
215 96         283 my $module = $modules_by_name->{$name};
216 96     21   4919 eval "use $module";
  21     21   9393  
  21     21   51  
  21     21   331  
  21         8381  
  0         0  
  0         0  
  21         9306  
  21         78  
  21         426  
  21         8242  
  21         70  
  21         381  
217              
218 96 100       651 push @supported_formats, $name unless $@;
219             }
220              
221 33         312 return \@supported_formats;
222             }
223              
224             sub setup_listeners {
225 20     20 1 115 my $self = shift;
226              
227             #-- Listener options
228 20         178 my $host = $self->get_host;
229 20         90 my $port = $self->get_port;
230 20 50       111 my @LocalHost = $host ? ( LocalHost => $host ) : ();
231 20   50     333 $host ||= "*";
232              
233             #-- get event loop manager
234 20         71 my $loop = $self->get_loop;
235              
236             #-- setup rpc listener
237 20         49 my $rpc_socket;
238 20 100       111 if ( $self->get_ssl ) {
239 3         7 eval { require IO::Socket::SSL };
  3         20  
240 3 50       14 croak "SSL requested, but IO::Socket::SSL not installed" if $@;
241 3 50       12 croak "ssl_key_file not set" unless $self->get_ssl_key_file;
242 3 50       12 croak "ssl_cert_file not set" unless $self->get_ssl_cert_file;
243              
244 3         15 my $ssl_opts = $self->get_ssl_opts;
245              
246             $rpc_socket = IO::Socket::SSL->new (
247             Listen => SOMAXCONN,
248             @LocalHost,
249             LocalPort => $port,
250             Proto => 'tcp',
251             ReuseAddr => 1,
252             SSL_key_file => $self->get_ssl_key_file,
253             SSL_cert_file => $self->get_ssl_cert_file,
254             SSL_passwd_cb => $self->get_ssl_passwd_cb,
255 3 50       14 ($ssl_opts?%{$ssl_opts}:()),
  0 50       0  
256             ) or die "can't start SSL RPC listener: $IO::Socket::SSL::ERROR";
257             }
258             else {
259 17 50       430 $rpc_socket = IO::Socket::INET->new (
260             Listen => SOMAXCONN,
261             @LocalHost,
262             LocalPort => $port,
263             Proto => 'tcp',
264             ReuseAddr => 1,
265             ) or die "can't start RPC listener: $!";
266             }
267              
268 20         24934 $self->set_rpc_socket($rpc_socket);
269              
270             $loop->add_io_watcher (
271             fh => $rpc_socket,
272             poll => 'r',
273 24     24   38048 cb => sub { $self->accept_new_client($rpc_socket); 1 },
  24         3381  
274 20         230 desc => "rpc listener port $port",
275             );
276              
277 20 100       114 if ( $self->get_ssl ) {
278 3         18 $self->log ("Started SSL RPC listener on port $host:$port");
279             } else {
280 17         101 $self->log ("Started RPC listener on $host:$port");
281             }
282              
283             # setup log listener
284 20 50       92 if ( $self->get_start_log_listener ) {
285 20 50       216 my $log_socket = IO::Socket::INET->new (
286             Listen => SOMAXCONN,
287             LocalPort => $port + 1,
288             @LocalHost,
289             Proto => 'tcp',
290             ReuseAddr => 1,
291             ) or die "can't start log listener: $!";
292              
293             $loop->add_io_watcher (
294             fh => $log_socket,
295             poll => 'r',
296 20     20   4474010 cb => sub { $self->accept_new_log_client($log_socket); 1 },
  20         156  
297 20         6033 desc => "log listener port ".($port+1),
298             );
299              
300 20         124 $self->log ("Started log listener on $host:".($port+1));
301             }
302              
303 20         114 $self->determine_singletons;
304              
305 20         152 $self->set_listeners_started(1);
306              
307 20         47 1;
308             }
309              
310             sub setup_auth_module {
311 20     20 0 47 my $self = shift;
312              
313             #-- Exit if no auth is required or setup already
314 20 100       155 return if not $self->get_auth_required;
315 4 50       23 return if $self->get_auth_module;
316              
317             #-- Default to Event::RPC::AuthPasswdHash
318 4         1794 require Event::RPC::AuthPasswdHash;
319              
320             #-- Setup an instance
321 4         26 my $passwd_href = $self->get_auth_passwd_href;
322 4         29 my $auth_module = Event::RPC::AuthPasswdHash->new ($passwd_href);
323 4         20 $self->set_auth_module($auth_module);
324              
325 4         10 1;
326             }
327              
328             sub prepare {
329 20     20 0 45 my $self = shift;
330              
331 20 50       168 $self->setup_listeners
332             unless $self->get_listeners_started;
333              
334 20         102 $self->setup_auth_module;
335              
336             #-- Filter unsupported message formats
337 20         109 $self->set_message_formats(
338             $self->probe_message_formats(
339             $self->get_message_formats,
340             $self->get_insecure_msg_fmt_ok
341             )
342             );
343              
344 20         51 1;
345             }
346              
347             sub start {
348 20     20 1 350 my $self = shift;
349              
350             #-- Prepare server for startup
351 20         173 $self->prepare;
352              
353 20         97 my $loop = $self->get_loop;
354              
355 20         137 $self->log ("Enter main loop using ".ref($loop));
356              
357 20         178 $loop->enter;
358              
359 20         81 $self->log ("Server stopped");
360              
361 20         54 1;
362             }
363              
364             sub stop {
365 20     20 1 123 my $self = shift;
366              
367 20         104 $self->get_loop->leave;
368              
369 20         46 1;
370             }
371              
372             sub determine_singletons {
373 20     20 0 53 my $self = shift;
374              
375 20         128 my $classes = $self->get_classes;
376 20         150 my $singleton_classes = $self->get_singleton_classes;
377              
378 20         50 foreach my $class ( keys %{$classes} ) {
  20         184  
379 40         107 foreach my $method ( keys %{$classes->{$class}} ) {
  40         262  
380             # check for singleton returner
381 211 100       509 if ( $classes->{$class}->{$method} eq '_singleton' ) {
382             # change to constructor
383 20         62 $classes->{$class}->{$method} = '_constructor';
384             # track that this class is a singleton
385 20         57 $singleton_classes->{$class} = 1;
386 20         71 last;
387             }
388             }
389             }
390              
391 20         101 1;
392             }
393              
394             sub accept_new_client {
395 24     24 0 71 my $self = shift;
396 24         83 my ($rpc_socket) = @_;
397              
398 24 100       227 my $client_socket = $rpc_socket->accept or return;
399              
400 23         42515 Event::RPC::Connection->new ($self, $client_socket);
401              
402 23         141 $self->set_clients_connected ( 1 + $self->get_clients_connected );
403              
404 23         46 1;
405             }
406              
407             sub accept_new_log_client {
408 20     20 0 94 my $self = shift;
409 20         93 my ($log_socket) = @_;
410              
411 20 50       444 my $client_socket = $log_socket->accept or return;
412              
413 20         5420 my $log_client =
414             Event::RPC::LogConnection->new($self, $client_socket);
415              
416 20         132 $self->set_log_clients_connected ( 1 + $self->get_log_clients_connected );
417 20         96 $self->get_logging_clients->{$log_client->get_cid} = $log_client;
418 20 50       119 $self->get_logger->add_fh($client_socket)
419             if $self->get_logger;
420              
421 20         94 $self->log(2, "New log client connected");
422              
423 20         43 1;
424             }
425              
426             sub load_class {
427 0     0 0 0 my $self = shift;
428 0         0 my ($class) = @_;
429              
430 0         0 Event::RPC::Connection->new ($self)->load_class($class);
431              
432 0         0 return $class;
433             }
434              
435             sub log {
436 535     535 1 924 my $self = shift;
437 535         1296 my $logger = $self->get_logger;
438 535 50       1562 return unless $logger;
439 0         0 $logger->log(@_);
440 0         0 1;
441             }
442              
443             sub remove_object {
444 8     8 0 12 my $self = shift;
445 8         66 my ($object) = @_;
446              
447 8         36 my $objects = $self->get_objects;
448              
449 8 50       26 if ( not $objects->{"$object"} ) {
450 0         0 warn "Object $object not registered";
451 0         0 return;
452             }
453              
454 8         60 delete $objects->{"$object"};
455              
456 8         37 $self->log(5, "Object '$object' removed");
457              
458 8         13 1;
459             }
460              
461             sub register_object {
462 39     39 0 107 my $self = shift;
463 39         105 my ($object, $class) = @_;
464              
465 39         112 my $objects = $self->get_objects;
466              
467 39         75 my $refcount;
468 39 100       197 if ( $objects->{"$object"} ) {
469 10         32 $refcount = ++$objects->{"$object"}->{refcount};
470             } else {
471 29         60 $refcount = 1;
472 29         239 $objects->{"$object"} = {
473             object => $object,
474             class => $class,
475             refcount => 1,
476             };
477             }
478              
479 39         230 $self->log(5, "Object '$object' registered. Refcount=$refcount");
480              
481 39         113 1;
482             }
483              
484             sub deregister_object {
485 29     29 0 63 my $self = shift;
486 29         64 my ($object) = @_;
487              
488 29         5557 my $objects = $self->get_objects;
489              
490 29 50       112 if ( not $objects->{"$object"} ) {
491 0         0 warn "Object $object not registered";
492 0         0 return;
493             }
494              
495 29         78 my $refcount = --$objects->{"$object"}->{refcount};
496              
497 29         97 my ($class) = split(/=/, $object);
498 29 100       87 if ( $self->get_singleton_classes->{$class} ) {
499             # never deregister singletons
500 21         102 $self->log(4, "Skip deregistration of singleton '$object'");
501 21         66 return;
502             }
503              
504 8         38 $self->log(5, "Object '$object' deregistered. Refcount=$refcount");
505              
506 8 50       36 $self->remove_object($object) if $refcount == 0;
507              
508 8         21 1;
509             }
510              
511             sub print_object_register {
512 0     0 0 0 my $self = shift;
513              
514 0         0 print "-"x70,"\n";
515              
516 0         0 my $objects = $self->get_objects;
517 0         0 foreach my $oid ( sort keys %{$objects} ) {
  0         0  
518 0         0 print "$oid\t$objects->{$oid}->{refcount}\n";
519             }
520              
521 0         0 1;
522             }
523              
524             1;
525              
526             __END__