| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Event::RPC::Connection; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 20 |  |  | 20 |  | 152 | use strict; | 
|  | 20 |  |  |  |  | 74 |  | 
|  | 20 |  |  |  |  | 767 |  | 
| 4 | 19 |  |  | 19 |  | 107 | use utf8; | 
|  | 19 |  |  |  |  | 58 |  | 
|  | 19 |  |  |  |  | 286 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 19 |  |  | 19 |  | 478 | use Carp; | 
|  | 19 |  |  |  |  | 32 |  | 
|  | 19 |  |  |  |  | 3261 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 19 |  |  | 19 |  | 7624 | use Event::RPC::Message::Negotiate; | 
|  | 19 |  |  |  |  | 93 |  | 
|  | 19 |  |  |  |  | 77325 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | #-- This can be changed for testing purposes e.g. to simulate | 
| 11 |  |  |  |  |  |  | #-- old servers which don't perform any format negotitation. | 
| 12 |  |  |  |  |  |  | $Event::RPC::Server::DEFAULT_MESSAGE_FORMAT = "Event::RPC::Message::Negotiate"; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | my $CONNECTION_ID; | 
| 15 |  |  |  |  |  |  |  | 
| 16 | 258 |  |  | 258 | 0 | 1193 | sub get_cid                     { shift->{cid}                          } | 
| 17 | 284 |  |  | 284 | 0 | 4257 | sub get_sock                    { shift->{sock}                         } | 
| 18 | 845 |  |  | 845 | 0 | 3851 | sub get_server                  { shift->{server}                       } | 
| 19 |  |  |  |  |  |  |  | 
| 20 | 214 |  |  | 214 | 0 | 1165 | sub get_classes                 { shift->{server}->{classes}            } | 
| 21 | 0 |  |  | 0 | 0 | 0 | sub get_loaded_classes          { shift->{server}->{loaded_classes}     } | 
| 22 | 50 |  |  | 50 | 0 | 135 | sub get_objects                 { shift->{server}->{objects}            } | 
| 23 | 60 |  |  | 60 | 0 | 394 | sub get_client_oids             { shift->{client_oids}                  } | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 155 |  |  | 155 | 0 | 2553 | sub get_message_format          { shift->{message_format}               } | 
| 26 | 18 |  |  | 18 | 0 | 122 | sub get_watcher                 { shift->{watcher}                      } | 
| 27 | 266 |  |  | 266 | 0 | 1393 | sub get_write_watcher           { shift->{write_watcher}                } | 
| 28 | 142 |  |  | 142 | 0 | 366 | sub get_message                 { shift->{message}                      } | 
| 29 | 2 |  |  | 2 | 0 | 20 | sub get_is_authenticated        { shift->{is_authenticated}             } | 
| 30 | 0 |  |  | 0 | 0 | 0 | sub get_auth_user               { shift->{auth_user}                    } | 
| 31 |  |  |  |  |  |  |  | 
| 32 | 29 |  |  | 29 | 0 | 109 | sub set_message_format          { shift->{message_format}       = $_[1] } | 
| 33 | 18 |  |  | 18 | 0 | 74 | sub set_watcher                 { shift->{watcher}              = $_[1] } | 
| 34 | 266 |  |  | 266 | 0 | 637 | sub set_write_watcher           { shift->{write_watcher}        = $_[1] } | 
| 35 | 284 |  |  | 284 | 0 | 728 | sub set_message                 { shift->{message}              = $_[1] } | 
| 36 | 1 |  |  | 1 | 0 | 3 | sub set_is_authenticated        { shift->{is_authenticated}     = $_[1] } | 
| 37 | 1 |  |  | 1 | 0 | 4 | sub set_auth_user               { shift->{auth_user}            = $_[1] } | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | sub new { | 
| 40 | 18 |  |  | 18 | 0 | 79 | my $class = shift; | 
| 41 | 18 |  |  |  |  | 100 | my ($server, $sock) = @_; | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 18 |  |  |  |  | 77 | my $cid = ++$CONNECTION_ID; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 18 |  |  |  |  | 185 | my $self = bless { | 
| 46 |  |  |  |  |  |  | cid                     => $cid, | 
| 47 |  |  |  |  |  |  | sock                    => $sock, | 
| 48 |  |  |  |  |  |  | server                  => $server, | 
| 49 |  |  |  |  |  |  | is_authenticated        => (!$server->get_auth_required), | 
| 50 |  |  |  |  |  |  | auth_user               => "", | 
| 51 |  |  |  |  |  |  | watcher                 => undef, | 
| 52 |  |  |  |  |  |  | write_watcher           => undef, | 
| 53 |  |  |  |  |  |  | message                 => undef, | 
| 54 |  |  |  |  |  |  | client_oids             => {}, | 
| 55 |  |  |  |  |  |  | message_format          => $Event::RPC::Server::DEFAULT_MESSAGE_FORMAT, | 
| 56 |  |  |  |  |  |  | }, $class; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 18 | 50 |  |  |  | 136 | if ( $sock ) { | 
| 59 | 18 |  |  |  |  | 444 | $self->log (2, | 
| 60 |  |  |  |  |  |  | "Got new RPC connection. Connection ID is $cid" | 
| 61 |  |  |  |  |  |  | ); | 
| 62 |  |  |  |  |  |  | $self->{watcher} = $self->get_server->get_loop->add_io_watcher ( | 
| 63 |  |  |  |  |  |  | fh   => $sock, | 
| 64 |  |  |  |  |  |  | poll => 'r', | 
| 65 | 142 |  |  | 142 |  | 132951 | cb   => sub { $self->input; 1 }, | 
|  | 142 |  |  |  |  | 1225 |  | 
| 66 | 18 |  |  |  |  | 147 | desc => "rpc client cid=$cid", | 
| 67 |  |  |  |  |  |  | ); | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 18 |  |  |  |  | 183 | my $connection_hook = $server->get_connection_hook; | 
| 71 | 18 | 50 |  |  |  | 256 | &$connection_hook($self, "connect") if $connection_hook; | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 18 |  |  |  |  | 345 | return $self; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | sub disconnect { | 
| 77 | 18 |  |  | 18 | 0 | 67 | my $self = shift; | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 18 |  |  |  |  | 117 | $self->get_server->get_loop->del_io_watcher($self->get_watcher); | 
| 80 | 18 | 50 |  |  |  | 84 | $self->get_server->get_loop->del_io_watcher($self->get_write_watcher) | 
| 81 |  |  |  |  |  |  | if $self->get_write_watcher; | 
| 82 | 18 |  |  |  |  | 104 | $self->set_watcher(undef); | 
| 83 | 18 |  |  |  |  | 87 | $self->set_write_watcher(undef); | 
| 84 | 18 |  |  |  |  | 68 | close $self->get_sock; | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 18 |  |  |  |  | 131 | my $server = $self->get_server; | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 18 |  |  |  |  | 75 | $server->set_clients_connected ( $self->get_server->get_clients_connected - 1 ); | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 18 |  |  |  |  | 61 | foreach my $oid ( keys %{$self->get_client_oids} ) { | 
|  | 18 |  |  |  |  | 203 |  | 
| 91 | 23 |  |  |  |  | 91 | $server->deregister_object($oid); | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 | 18 |  |  |  |  | 143 | $self->log(2, "Client disconnected"); | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 18 |  |  |  |  | 126 | my $connection_hook = $server->get_connection_hook; | 
| 97 | 18 | 50 |  |  |  | 244 | &$connection_hook($self, "disconnect") if $connection_hook; | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 18 |  |  |  |  | 127 | 1; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | sub get_client_object { | 
| 103 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 104 | 0 |  |  |  |  | 0 | my ($oid) = @_; | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | croak "No object registered with oid '$oid'" | 
| 107 | 0 | 0 |  |  |  | 0 | unless $self->get_client_objects->{$oid}; | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 0 |  |  |  |  | 0 | return $self->get_client_objects->{$oid}; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | sub log { | 
| 113 | 256 |  |  | 256 | 0 | 447 | my $self = shift; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 256 |  |  |  |  | 358 | my ($level, $msg); | 
| 116 | 256 | 100 |  |  |  | 814 | if ( @_ == 2 ) { | 
| 117 | 251 |  |  |  |  | 625 | ($level, $msg) = @_; | 
| 118 |  |  |  |  |  |  | } else { | 
| 119 | 5 |  |  |  |  | 22 | ($msg) = @_; | 
| 120 | 5 |  |  |  |  | 14 | $level = 1; | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 256 |  |  |  |  | 829 | $msg = "cid=".$self->get_cid.": $msg"; | 
| 124 |  |  |  |  |  |  |  | 
| 125 | 256 |  |  |  |  | 712 | return $self->get_server->log ($level, $msg); | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | sub input { | 
| 129 | 142 |  |  | 142 | 0 | 330 | my $self = shift; | 
| 130 | 142 |  |  |  |  | 285 | my ($e) = @_; | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 142 |  |  |  |  | 451 | my $server  = $self->get_server; | 
| 133 | 142 |  |  |  |  | 478 | my $message = $self->get_message; | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 142 | 50 |  |  |  | 503 | if ( not $message ) { | 
| 136 | 142 |  |  |  |  | 415 | $message = $self->get_message_format->new ($self->get_sock); | 
| 137 | 142 |  |  |  |  | 617 | $self->set_message($message); | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 142 |  | 100 |  |  | 252 | my $request = eval { $message->read } || ''; | 
| 141 | 142 |  |  |  |  | 1701 | my $error = $@; | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 142 | 50 | 66 |  |  | 829 | return if $request eq '' && $error eq ''; | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 142 |  |  |  |  | 458 | $self->set_message(undef); | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 142 | 100 | 66 |  |  | 1277 | return $self->disconnect | 
| 148 |  |  |  |  |  |  | if $request eq "DISCONNECT\n" or | 
| 149 |  |  |  |  |  |  | $error =~ /DISCONNECTED/; | 
| 150 |  |  |  |  |  |  |  | 
| 151 | 124 |  |  |  |  | 570 | $server->set_active_connection($self); | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 124 |  |  |  |  | 205 | my ($cmd, $rc); | 
| 154 | 124 | 100 |  |  |  | 441 | $cmd = $request->{cmd} if not $error; | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 124 |  |  |  |  | 532 | $self->log(4, "RPC command: $cmd"); | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 124 | 100 | 66 |  |  | 1192 | if ( $error ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 159 | 3 |  |  |  |  | 23 | $self->log ("Unexpected error on incoming RPC call: $@"); | 
| 160 | 3 |  |  |  |  | 92 | $rc = { | 
| 161 |  |  |  |  |  |  | ok  => 0, | 
| 162 |  |  |  |  |  |  | msg => "Unexpected error on incoming RPC call: $@", | 
| 163 |  |  |  |  |  |  | }; | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  | elsif ( $cmd eq 'neg_formats_avail') { | 
| 166 |  |  |  |  |  |  | $rc = { | 
| 167 |  |  |  |  |  |  | ok       => 1, | 
| 168 | 13 |  |  |  |  | 49 | msg      => join(",", @{$self->get_server->get_message_formats}) | 
|  | 13 |  |  |  |  | 66 |  | 
| 169 |  |  |  |  |  |  | }; | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  | elsif ( $cmd eq 'neg_format_set') { | 
| 172 | 13 |  |  |  |  | 269 | $rc = $self->client_requests_message_format($request->{msg}); | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  | elsif ( $cmd eq 'version' ) { | 
| 175 |  |  |  |  |  |  | #-- Probably we have fallen back to Storable because an old | 
| 176 |  |  |  |  |  |  | #-- client has connected. so we change the negotiation | 
| 177 |  |  |  |  |  |  | #-- message handler to the fallback handler for further | 
| 178 |  |  |  |  |  |  | #-- communication on this connection. | 
| 179 | 16 |  |  |  |  | 97 | $self->set_message_format(ref $message); | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 16 |  |  |  |  | 711 | $rc = { | 
| 182 |  |  |  |  |  |  | ok       => 1, | 
| 183 |  |  |  |  |  |  | version  => $Event::RPC::VERSION, | 
| 184 |  |  |  |  |  |  | protocol => $Event::RPC::PROTOCOL, | 
| 185 |  |  |  |  |  |  | }; | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | elsif ( $cmd eq 'auth' ) { | 
| 188 | 2 |  |  |  |  | 7 | $rc = $self->authorize_user ($request); | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  | elsif ( $server->get_auth_required && !$self->get_is_authenticated ) { | 
| 191 | 0 |  |  |  |  | 0 | $rc = { | 
| 192 |  |  |  |  |  |  | ok  => 0, | 
| 193 |  |  |  |  |  |  | msg => "Authorization required", | 
| 194 |  |  |  |  |  |  | }; | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  | elsif ( $cmd eq 'new' ) { | 
| 197 | 8 |  |  |  |  | 47 | $rc = $self->create_new_object ($request); | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  | elsif ( $cmd eq 'exec' ) { | 
| 200 | 50 |  |  |  |  | 171 | $rc = $self->execute_object_method ($request); | 
| 201 |  |  |  |  |  |  | } | 
| 202 |  |  |  |  |  |  | elsif ( $cmd eq 'classes_list' ) { | 
| 203 | 0 |  |  |  |  | 0 | $rc = $self->get_classes_list ($request); | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  | elsif ( $cmd eq 'class_info' ) { | 
| 206 | 0 |  |  |  |  | 0 | $rc = $self->get_class_info ($request); | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  | elsif ( $cmd eq 'class_info_all' ) { | 
| 209 | 15 |  |  |  |  | 362 | $rc = $self->get_class_info_all ($request); | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  | elsif ( $cmd eq 'client_destroy' ) { | 
| 212 | 4 |  |  |  |  | 50 | $rc = $self->object_destroyed_on_client ($request); | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  | else { | 
| 215 | 0 |  |  |  |  | 0 | $self->log ("Unknown request command '$cmd'"); | 
| 216 | 0 |  |  |  |  | 0 | $rc = { | 
| 217 |  |  |  |  |  |  | ok  => 0, | 
| 218 |  |  |  |  |  |  | msg => "Unknown request command '$cmd'", | 
| 219 |  |  |  |  |  |  | }; | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 124 |  |  |  |  | 678 | $server->set_active_connection(undef); | 
| 223 |  |  |  |  |  |  |  | 
| 224 | 124 |  |  |  |  | 621 | $message->set_data($rc); | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | my $watcher = $self->get_server->get_loop->add_io_watcher ( | 
| 227 |  |  |  |  |  |  | fh      => $self->get_sock, | 
| 228 |  |  |  |  |  |  | poll    => 'w', | 
| 229 |  |  |  |  |  |  | cb      => sub { | 
| 230 | 124 | 50 |  | 124 |  | 1781 | if ( $message->write ) { | 
| 231 | 124 | 50 |  |  |  | 473 | $self->get_server->get_loop->del_io_watcher($self->get_write_watcher) | 
| 232 |  |  |  |  |  |  | if $self->get_write_watcher; | 
| 233 | 124 |  |  |  |  | 390 | $self->set_write_watcher(); | 
| 234 |  |  |  |  |  |  | } | 
| 235 | 124 |  |  |  |  | 1644 | 1; | 
| 236 |  |  |  |  |  |  | }, | 
| 237 | 124 |  |  |  |  | 373 | ); | 
| 238 |  |  |  |  |  |  |  | 
| 239 | 124 |  |  |  |  | 464 | $self->set_write_watcher($watcher); | 
| 240 |  |  |  |  |  |  |  | 
| 241 | 124 |  |  |  |  | 848 | 1; | 
| 242 |  |  |  |  |  |  | } | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | sub client_requests_message_format { | 
| 245 | 13 |  |  | 13 | 0 | 45 | my $self = shift; | 
| 246 | 13 |  |  |  |  | 55 | my ($client_format) = @_; | 
| 247 |  |  |  |  |  |  |  | 
| 248 | 13 |  |  |  |  | 42 | foreach my $format ( @{$self->get_server->get_message_formats} ) { | 
|  | 13 |  |  |  |  | 62 |  | 
| 249 | 13 | 50 |  |  |  | 91 | if ( $client_format eq $format ) { | 
| 250 |  |  |  |  |  |  | $self->set_message_format( | 
| 251 |  |  |  |  |  |  | Event::RPC::Message::Negotiate->known_message_formats | 
| 252 | 13 |  |  |  |  | 94 | ->{$client_format} | 
| 253 |  |  |  |  |  |  | ); | 
| 254 |  |  |  |  |  |  |  | 
| 255 | 13 |  |  | 12 |  | 57 | eval "use ".$self->get_message_format; | 
|  | 12 |  |  |  |  | 143 |  | 
|  | 12 |  |  |  |  | 56 |  | 
|  | 12 |  |  |  |  | 445 |  | 
| 256 | 13 | 50 |  |  |  | 81 | return { ok => 0, msg => "Server rejected format '$client_format': $@" } | 
| 257 |  |  |  |  |  |  | if $@; | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 13 |  |  |  |  | 84 | return { ok => 1 }; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 | 0 |  |  |  |  | 0 | return { ok => 0, msg => "Server rejected format '$client_format'" }; | 
| 264 |  |  |  |  |  |  | } | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | sub authorize_user { | 
| 267 | 2 |  |  | 2 | 0 | 3 | my $self = shift; | 
| 268 | 2 |  |  |  |  | 3 | my ($request) = @_; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 2 |  |  |  |  | 4 | my $user = $request->{user}; | 
| 271 | 2 |  |  |  |  | 5 | my $pass = $request->{pass}; | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 2 |  |  |  |  | 5 | my $auth_module = $self->get_server->get_auth_module; | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | return { | 
| 276 | 2 | 50 |  |  |  | 14 | ok  => 1, | 
| 277 |  |  |  |  |  |  | msg => "Not authorization required", | 
| 278 |  |  |  |  |  |  | } unless $auth_module; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 2 |  |  |  |  | 14 | my $ok = $auth_module->check_credentials ($user, $pass); | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 2 | 100 |  |  |  | 16 | if ( $ok ) { | 
| 283 | 1 |  |  |  |  | 5 | $self->set_auth_user($user); | 
| 284 | 1 |  |  |  |  | 6 | $self->set_is_authenticated(1); | 
| 285 | 1 |  |  |  |  | 6 | $self->log("User '$user' successfully authorized"); | 
| 286 |  |  |  |  |  |  | return { | 
| 287 | 1 |  |  |  |  | 16 | ok  => 1, | 
| 288 |  |  |  |  |  |  | msg => "Credentials Ok", | 
| 289 |  |  |  |  |  |  | }; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  | else { | 
| 292 | 1 |  |  |  |  | 4 | $self->log("Illegal credentials for user '$user'"); | 
| 293 |  |  |  |  |  |  | return { | 
| 294 | 1 |  |  |  |  | 5 | ok  => 0, | 
| 295 |  |  |  |  |  |  | msg => "Illegal credentials", | 
| 296 |  |  |  |  |  |  | }; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | sub create_new_object { | 
| 301 | 8 |  |  | 8 | 0 | 23 | my $self = shift; | 
| 302 | 8 |  |  |  |  | 38 | my ($request) = @_; | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | # Let's create a new object | 
| 305 | 8 |  |  |  |  | 33 | my $class_method = $request->{method}; | 
| 306 | 8 |  |  |  |  | 18 | my $class = $class_method; | 
| 307 | 8 |  |  |  |  | 78 | $class =~ s/::[^:]+$//; | 
| 308 | 8 |  |  |  |  | 60 | $class_method =~ s/^.*:://; | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | # check if access to this class/method is allowed | 
| 311 | 8 | 50 | 33 |  |  | 34 | if ( not defined $self->get_classes->{$class}->{$class_method} or | 
| 312 |  |  |  |  |  |  | $self->get_classes->{$class}->{$class_method} ne '_constructor' ) { | 
| 313 | 0 |  |  |  |  | 0 | $self->log ("Illegal constructor access to $class->$class_method"); | 
| 314 |  |  |  |  |  |  | return { | 
| 315 | 0 |  |  |  |  | 0 | ok  => 0, | 
| 316 |  |  |  |  |  |  | msg => "Illegal constructor access to $class->$class_method" | 
| 317 |  |  |  |  |  |  | }; | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | # ok, load class and execute the method | 
| 322 | 8 |  |  |  |  | 22 | my $object = eval { | 
| 323 |  |  |  |  |  |  | # load the class if not done yet | 
| 324 | 8 | 50 |  |  |  | 30 | $self->load_class($class) if $self->get_server->get_load_modules; | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | # resolve object params | 
| 327 | 8 |  |  |  |  | 54 | $self->resolve_object_params ($request->{params}); | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 8 |  |  |  |  | 23 | $class->$class_method (@{$request->{params}}) | 
|  | 8 |  |  |  |  | 95 |  | 
| 330 |  |  |  |  |  |  | }; | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | # report error | 
| 333 | 8 | 50 |  |  |  | 248 | if ( $@ ) { | 
| 334 | 0 |  |  |  |  | 0 | $self->log ("Error: can't create object ". | 
| 335 |  |  |  |  |  |  | "($class->$class_method): $@"); | 
| 336 |  |  |  |  |  |  | return { | 
| 337 | 0 |  |  |  |  | 0 | ok  => 0, | 
| 338 |  |  |  |  |  |  | msg => $@, | 
| 339 |  |  |  |  |  |  | }; | 
| 340 |  |  |  |  |  |  | } | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | # register object | 
| 343 | 8 |  |  |  |  | 36 | $self->get_server->register_object ($object, $class); | 
| 344 | 8 |  |  |  |  | 35 | $self->get_client_oids->{"$object"} = 1; | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | # log and return | 
| 347 | 8 |  |  |  |  | 61 | $self->log (5, | 
| 348 |  |  |  |  |  |  | "Created new object $class->$class_method with oid '$object'", | 
| 349 |  |  |  |  |  |  | ); | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | return { | 
| 352 | 8 |  |  |  |  | 71 | ok  => 1, | 
| 353 |  |  |  |  |  |  | oid => "$object", | 
| 354 |  |  |  |  |  |  | }; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | sub load_class { | 
| 358 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 359 | 0 |  |  |  |  | 0 | my ($class) = @_; | 
| 360 |  |  |  |  |  |  |  | 
| 361 | 0 |  |  |  |  | 0 | my $mtime; | 
| 362 | 0 |  |  |  |  | 0 | my $load_class_info = $self->get_loaded_classes->{$class}; | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 0 | 0 | 0 |  |  | 0 | if ( not $load_class_info or | 
|  |  |  | 0 |  |  |  |  | 
| 365 |  |  |  |  |  |  | ( $self->get_server->get_auto_reload_modules && | 
| 366 |  |  |  |  |  |  | ( $mtime = (stat($load_class_info->{filename}))[9]) | 
| 367 |  |  |  |  |  |  | > $load_class_info->{mtime} ) ) | 
| 368 |  |  |  |  |  |  | { | 
| 369 | 0 | 0 |  |  |  | 0 | if ( not $load_class_info->{filename} ) { | 
| 370 | 0 |  |  |  |  | 0 | my $filename; | 
| 371 | 0 |  |  |  |  | 0 | my $rel_filename = $class; | 
| 372 | 0 |  |  |  |  | 0 | $rel_filename =~ s!::!/!g; | 
| 373 | 0 |  |  |  |  | 0 | $rel_filename .= ".pm"; | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 0 |  |  |  |  | 0 | foreach my $dir ( @INC ) { | 
| 376 | 0 | 0 |  |  |  | 0 | $filename = "$dir/$rel_filename", last | 
| 377 |  |  |  |  |  |  | if -f "$dir/$rel_filename"; | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  |  | 
| 380 | 0 | 0 |  |  |  | 0 | croak "File for class '$class' not found\n" | 
| 381 |  |  |  |  |  |  | if not $filename; | 
| 382 |  |  |  |  |  |  |  | 
| 383 | 0 |  |  |  |  | 0 | $load_class_info->{filename} = $filename; | 
| 384 | 0 |  |  |  |  | 0 | $load_class_info->{mtime} = 0; | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  |  | 
| 387 | 0 |  | 0 |  |  | 0 | $mtime ||= 0; | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | $self->log (3, "Class '$class' ($load_class_info->{filename}) changed on disk. Reloading...") | 
| 390 | 0 | 0 |  |  |  | 0 | if $mtime > $load_class_info->{mtime}; | 
| 391 |  |  |  |  |  |  |  | 
| 392 | 0 |  |  |  |  | 0 | do $load_class_info->{filename}; | 
| 393 |  |  |  |  |  |  |  | 
| 394 | 0 | 0 |  |  |  | 0 | if ( $@ ) { | 
| 395 | 0 |  |  |  |  | 0 | $self->log ("Can't load class '$class': $@"); | 
| 396 | 0 |  |  |  |  | 0 | $load_class_info->{mtime} = 0; | 
| 397 | 0 |  |  |  |  | 0 | die "Can't load class $class: $@"; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  | else { | 
| 400 | 0 |  |  |  |  | 0 | $self->log (3, "Class '$class' successfully loaded"); | 
| 401 | 0 |  |  |  |  | 0 | $load_class_info->{mtime} = time; | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | $self->log (5, "filename=".$load_class_info->{filename}. | 
| 406 | 0 |  |  |  |  | 0 | ", mtime=".$load_class_info->{mtime} ); | 
| 407 |  |  |  |  |  |  |  | 
| 408 | 0 |  | 0 |  |  | 0 | $self->get_loaded_classes->{$class} ||= $load_class_info; | 
| 409 |  |  |  |  |  |  |  | 
| 410 | 0 |  |  |  |  | 0 | 1; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | sub execute_object_method { | 
| 414 | 50 |  |  | 50 | 0 | 72 | my $self = shift; | 
| 415 | 50 |  |  |  |  | 82 | my ($request) = @_; | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | # Method call of an existent object | 
| 418 | 50 |  |  |  |  | 87 | my $oid = $request->{oid}; | 
| 419 | 50 |  |  |  |  | 132 | my $object_entry = $self->get_objects->{$oid}; | 
| 420 | 50 |  |  |  |  | 95 | my $method = $request->{method}; | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 50 | 50 |  |  |  | 150 | if ( not defined $object_entry ) { | 
| 423 |  |  |  |  |  |  | # object does not exist | 
| 424 | 0 |  |  |  |  | 0 | $self->log ("Illegal access to unknown object with oid=$oid"); | 
| 425 |  |  |  |  |  |  | return { | 
| 426 | 0 |  |  |  |  | 0 | ok  => 0, | 
| 427 |  |  |  |  |  |  | msg => "Illegal access to unknown object with oid=$oid" | 
| 428 |  |  |  |  |  |  | }; | 
| 429 |  |  |  |  |  |  | } | 
| 430 |  |  |  |  |  |  |  | 
| 431 | 50 |  |  |  |  | 92 | my $class = $object_entry->{class}; | 
| 432 | 50 | 50 | 33 |  |  | 118 | if ( not defined $self->get_classes->{$class} or | 
| 433 |  |  |  |  |  |  | not defined $self->get_classes->{$class}->{$method} ) | 
| 434 |  |  |  |  |  |  | { | 
| 435 |  |  |  |  |  |  | # illegal access to this method | 
| 436 | 0 |  |  |  |  | 0 | $self->log ("Illegal access to $class->$method"); | 
| 437 |  |  |  |  |  |  | return { | 
| 438 | 0 |  |  |  |  | 0 | ok  => 0, | 
| 439 |  |  |  |  |  |  | msg => "Illegal access to $class->$method" | 
| 440 |  |  |  |  |  |  | }; | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  |  | 
| 443 | 50 |  |  |  |  | 119 | my $return_type = $self->get_classes->{$class}->{$method}; | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  | # ok, try loading class and executing the method | 
| 446 | 50 |  |  |  |  | 86 | my @rc = eval { | 
| 447 |  |  |  |  |  |  | # (re)load the class if not done yet | 
| 448 | 50 | 50 |  |  |  | 102 | $self->load_class($class) if $self->get_server->get_load_modules; | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | # resolve object params | 
| 451 | 50 |  |  |  |  | 164 | $self->resolve_object_params ($request->{params}); | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | # exeute method | 
| 454 | 50 |  |  |  |  | 101 | $object_entry->{object}->$method (@{$request->{params}}) | 
|  | 50 |  |  |  |  | 288 |  | 
| 455 |  |  |  |  |  |  | }; | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | # report error | 
| 458 | 50 | 50 |  |  |  | 4586 | if ( $@ ) { | 
| 459 | 0 |  |  |  |  | 0 | $self->log ("Error: can't call '$method' of object ". | 
| 460 |  |  |  |  |  |  | "with oid=$oid: $@"); | 
| 461 |  |  |  |  |  |  | return { | 
| 462 | 0 |  |  |  |  | 0 | ok  => 0, | 
| 463 |  |  |  |  |  |  | msg => "$@", | 
| 464 |  |  |  |  |  |  | }; | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | # log | 
| 468 | 50 |  |  |  |  | 214 | $self->log (4, "Called method '$method' of object ". | 
| 469 |  |  |  |  |  |  | "with oid=$oid"); | 
| 470 |  |  |  |  |  |  |  | 
| 471 | 50 | 100 |  |  |  | 146 | if ( $return_type eq '_object' ) { | 
| 472 |  |  |  |  |  |  | # check if objects are returned by this method | 
| 473 |  |  |  |  |  |  | # and register them in our internal object table | 
| 474 |  |  |  |  |  |  | # (if not already done yet) | 
| 475 | 11 |  |  |  |  | 25 | my $key; | 
| 476 | 11 |  |  |  |  | 28 | foreach my $rc ( @rc ) { | 
| 477 | 12 | 100 | 100 |  |  | 203 | if ( ref ($rc) and ref ($rc) !~ /ARRAY|HASH|SCALAR/ ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | # returns a single object | 
| 479 | 9 |  |  |  |  | 64 | $self->log (4, "Method returns object: $rc"); | 
| 480 | 9 |  |  |  |  | 23 | $key = "$rc"; | 
| 481 | 9 |  |  |  |  | 39 | $self->get_client_oids->{$key} = 1; | 
| 482 | 9 |  |  |  |  | 30 | $self->get_server->register_object($rc, ref $rc); | 
| 483 | 9 |  |  |  |  | 26 | $rc = $key; | 
| 484 |  |  |  |  |  |  |  | 
| 485 |  |  |  |  |  |  | } | 
| 486 |  |  |  |  |  |  | elsif ( ref $rc eq 'ARRAY' ) { | 
| 487 |  |  |  |  |  |  | # possibly returns a list of objects | 
| 488 |  |  |  |  |  |  | # make a copy, otherwise the original object references | 
| 489 |  |  |  |  |  |  | # will be overwritten | 
| 490 | 1 |  |  |  |  | 2 | my @val = @{$rc}; | 
|  | 1 |  |  |  |  | 3 |  | 
| 491 | 1 |  |  |  |  | 3 | $rc = \@val; | 
| 492 | 1 |  |  |  |  | 3 | foreach my $val ( @val ) { | 
| 493 | 10 | 50 | 33 |  |  | 56 | if ( ref ($val) and ref ($val) !~ /ARRAY|HASH|SCALAR/ ) { | 
| 494 | 10 |  |  |  |  | 31 | $self->log (4, "Method returns object lref: $val"); | 
| 495 | 10 |  |  |  |  | 15 | $key = "$val"; | 
| 496 | 10 |  |  |  |  | 21 | $self->get_client_oids->{$key} = 1; | 
| 497 | 10 |  |  |  |  | 18 | $self->get_server->register_object($val, ref $val); | 
| 498 | 10 |  |  |  |  | 23 | $val = $key; | 
| 499 |  |  |  |  |  |  | } | 
| 500 |  |  |  |  |  |  | } | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  | elsif ( ref $rc eq 'HASH' ) { | 
| 503 |  |  |  |  |  |  | # possibly returns a hash of objects | 
| 504 |  |  |  |  |  |  | # make a copy, otherwise the original object references | 
| 505 |  |  |  |  |  |  | # will be overwritten | 
| 506 | 1 |  |  |  |  | 4 | my %val = %{$rc}; | 
|  | 1 |  |  |  |  | 8 |  | 
| 507 | 1 |  |  |  |  | 2 | $rc = \%val; | 
| 508 | 1 |  |  |  |  | 5 | foreach my $val ( values %val ) { | 
| 509 | 10 | 50 | 33 |  |  | 58 | if ( ref ($val) and ref ($val) !~ /ARRAY|HASH|SCALAR/ ) { | 
| 510 | 10 |  |  |  |  | 63 | $self->log (4, "Method returns object href: $val"); | 
| 511 | 10 |  |  |  |  | 17 | $key = "$val"; | 
| 512 | 10 |  |  |  |  | 24 | $self->get_client_oids->{$key} = 1; | 
| 513 | 10 |  |  |  |  | 19 | $self->get_server->register_object($val, ref $val); | 
| 514 | 10 |  |  |  |  | 20 | $val = $key; | 
| 515 |  |  |  |  |  |  | } | 
| 516 |  |  |  |  |  |  | } | 
| 517 |  |  |  |  |  |  | } | 
| 518 |  |  |  |  |  |  | } | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | # return rc | 
| 522 |  |  |  |  |  |  | return { | 
| 523 | 50 |  |  |  |  | 372 | ok => 1, | 
| 524 |  |  |  |  |  |  | rc => \@rc, | 
| 525 |  |  |  |  |  |  | }; | 
| 526 |  |  |  |  |  |  | } | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | sub object_destroyed_on_client { | 
| 529 | 4 |  |  | 4 | 0 | 11 | my $self = shift; | 
| 530 | 4 |  |  |  |  | 10 | my ($request) = @_; | 
| 531 |  |  |  |  |  |  |  | 
| 532 | 4 |  |  |  |  | 25 | $self->log(5, "Object with oid=$request->{oid} destroyed on client"); | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 4 |  |  |  |  | 35 | delete $self->get_client_oids->{$request->{oid}}; | 
| 535 | 4 |  |  |  |  | 17 | $self->get_server->deregister_object($request->{oid}); | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | return { | 
| 538 | 4 |  |  |  |  | 15 | ok => 1 | 
| 539 |  |  |  |  |  |  | }; | 
| 540 |  |  |  |  |  |  | } | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | sub get_classes_list { | 
| 543 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 544 | 0 |  |  |  |  | 0 | my ($request) = @_; | 
| 545 |  |  |  |  |  |  |  | 
| 546 | 0 |  |  |  |  | 0 | my @classes = keys %{$self->get_classes}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | return { | 
| 549 | 0 |  |  |  |  | 0 | ok      => 1, | 
| 550 |  |  |  |  |  |  | classes => \@classes, | 
| 551 |  |  |  |  |  |  | } | 
| 552 |  |  |  |  |  |  | } | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | sub get_class_info { | 
| 555 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 556 | 0 |  |  |  |  | 0 | my ($request) = @_; | 
| 557 |  |  |  |  |  |  |  | 
| 558 | 0 |  |  |  |  | 0 | my $class = $request->{class}; | 
| 559 |  |  |  |  |  |  |  | 
| 560 | 0 | 0 |  |  |  | 0 | if ( not defined $self->get_classes->{$class} ) { | 
| 561 | 0 |  |  |  |  | 0 | $self->log ("Unknown class '$class'"); | 
| 562 |  |  |  |  |  |  | return { | 
| 563 | 0 |  |  |  |  | 0 | ok  => 0, | 
| 564 |  |  |  |  |  |  | msg => "Unknown class '$class'" | 
| 565 |  |  |  |  |  |  | }; | 
| 566 |  |  |  |  |  |  | } | 
| 567 |  |  |  |  |  |  |  | 
| 568 | 0 |  |  |  |  | 0 | $self->log (4, "Class info for '$class' requested"); | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | return { | 
| 571 |  |  |  |  |  |  | ok           => 1, | 
| 572 | 0 |  |  |  |  | 0 | methods      => $self->get_classes->{$class}, | 
| 573 |  |  |  |  |  |  | }; | 
| 574 |  |  |  |  |  |  | } | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | sub get_class_info_all { | 
| 577 | 15 |  |  | 15 | 0 | 61 | my $self = shift; | 
| 578 | 15 |  |  |  |  | 48 | my ($request) = @_; | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | return { | 
| 581 | 15 |  |  |  |  | 127 | ok             => 1, | 
| 582 |  |  |  |  |  |  | class_info_all => $self->get_classes, | 
| 583 |  |  |  |  |  |  | } | 
| 584 |  |  |  |  |  |  | } | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | sub resolve_object_params { | 
| 587 | 58 |  |  | 58 | 0 | 87 | my $self = shift; | 
| 588 | 58 |  |  |  |  | 84 | my ($params) = @_; | 
| 589 |  |  |  |  |  |  |  | 
| 590 | 58 |  |  |  |  | 84 | my $key; | 
| 591 | 58 |  |  |  |  | 77 | foreach my $par ( @{$params} ) { | 
|  | 58 |  |  |  |  | 161 |  | 
| 592 | 33 | 50 |  |  |  | 80 | if ( defined $self->get_classes->{ref($par)} ) { | 
| 593 | 0 |  |  |  |  | 0 | $key = ${$par}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 594 | 0 |  |  |  |  | 0 | $key = "$key"; | 
| 595 |  |  |  |  |  |  | croak "unknown object with key '$key'" | 
| 596 | 0 | 0 |  |  |  | 0 | if not defined $self->get_objects->{$key}; | 
| 597 | 0 |  |  |  |  | 0 | $par = $self->get_objects->{$key}->{object}; | 
| 598 |  |  |  |  |  |  | } | 
| 599 |  |  |  |  |  |  | } | 
| 600 |  |  |  |  |  |  |  | 
| 601 | 58 |  |  |  |  | 121 | 1; | 
| 602 |  |  |  |  |  |  | } | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | 1; | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | __END__ |