Event-RPC
view release on metacpan or search on metacpan
lib/Event/RPC/Server.pm view on Meta::CPAN
my $self = shift;
my $rpc_socket = $self->get_rpc_socket;
close ($rpc_socket) if $rpc_socket;
1;
}
sub probe_message_formats {
my $class = shift;
my ($user_supplied_formats, $insecure_msg_fmt_ok) = @_;
my $order_lref = Event::RPC::Message::Negotiate->message_format_order;
my $modules_by_name = Event::RPC::Message::Negotiate->known_message_formats;
my %probe_formats;
if ( $user_supplied_formats ) {
@probe_formats{@{$user_supplied_formats}} =
(1) x @{$user_supplied_formats};
}
else {
%probe_formats = %{$modules_by_name};
}
#-- By default we probe all supported formats, but
#-- not Storable. User has to activate this explicitely.
if ( not $insecure_msg_fmt_ok ) {
delete $probe_formats{STOR};
}
Event::RPC::Message::Negotiate->set_storable_fallback_ok($insecure_msg_fmt_ok);
my @supported_formats;
foreach my $name ( @{$order_lref} ) {
next unless $probe_formats{$name};
my $module = $modules_by_name->{$name};
eval "use $module";
push @supported_formats, $name unless $@;
}
return \@supported_formats;
}
sub setup_listeners {
my $self = shift;
#-- Listener options
my $host = $self->get_host;
my $port = $self->get_port;
my @LocalHost = $host ? ( LocalHost => $host ) : ();
$host ||= "*";
#-- get event loop manager
my $loop = $self->get_loop;
#-- setup rpc listener
my $rpc_socket;
if ( $self->get_ssl ) {
eval { require IO::Socket::SSL };
croak "SSL requested, but IO::Socket::SSL not installed" if $@;
croak "ssl_key_file not set" unless $self->get_ssl_key_file;
croak "ssl_cert_file not set" unless $self->get_ssl_cert_file;
my $ssl_opts = $self->get_ssl_opts;
$rpc_socket = IO::Socket::SSL->new (
Listen => SOMAXCONN,
@LocalHost,
LocalPort => $port,
Proto => 'tcp',
ReuseAddr => 1,
SSL_key_file => $self->get_ssl_key_file,
SSL_cert_file => $self->get_ssl_cert_file,
SSL_passwd_cb => $self->get_ssl_passwd_cb,
($ssl_opts?%{$ssl_opts}:()),
) or die "can't start SSL RPC listener: $IO::Socket::SSL::ERROR";
}
elsif ($host eq "unix/") {
require IO::Socket::UNIX;
unlink $port;
$rpc_socket = IO::Socket::UNIX->new (
Type => IO::Socket::UNIX::SOCK_STREAM(),
Listen => SOMAXCONN,
Local => $port,
) or die "can't start Unix Domain RPC listener at $port: $!";
}
else {
require IO::Socket::INET;
$rpc_socket = IO::Socket::INET->new (
Listen => SOMAXCONN,
@LocalHost,
LocalPort => $port,
Proto => 'tcp',
ReuseAddr => 1,
) or die "can't start TCP RPC listener: $!";
}
$self->set_rpc_socket($rpc_socket);
$loop->add_io_watcher (
fh => $rpc_socket,
poll => 'r',
cb => sub { $self->accept_new_client($rpc_socket); 1 },
desc => "rpc listener port $port",
);
if ( $self->get_ssl ) {
$self->log ("Started SSL RPC listener on port $host:$port");
} else {
$self->log ("Started RPC listener on $host:$port");
}
# setup log listener
if ( $self->get_start_log_listener ) {
my $log_socket;
if ($host eq "unix/") {
$port =~ s/\.sock//;
$port .= ".log.sock";
unlink $port;
$log_socket = IO::Socket::UNIX->new (
Type => IO::Socket::UNIX::SOCK_STREAM(),
Listen => SOMAXCONN,
Local => $port,
) or die "can't start Unix Domain log listener at $port: $!";
}
else {
$log_socket = IO::Socket::INET->new (
Listen => SOMAXCONN,
LocalPort => $port + 1,
@LocalHost,
Proto => 'tcp',
ReuseAddr => 1,
) or die "can't start log listener: $!";
}
$loop->add_io_watcher (
lib/Event/RPC/Server.pm view on Meta::CPAN
Socket and specify "unix/" as host parameter.
=item B<classes>
This is a hash ref with the following structure:
classes => {
"Class1" => {
new => "_constructor",
simple_method => 1,
object_returner => "_object",
},
"Class2" => { ... },
...
},
Each class which should be accessible for clients needs to
be listed here at the first level, assigned a hash of methods
allowed to be called. Event::RPC disuinguishes three types
of methods by classifying their return value:
=over 4
=item B<Constructors>
A constructor method creates a new object of the corresponding class
and returns it. You need to assign the string "_constructor" to
the method entry to mark a method as a constructor.
=item B<Singleton constructors>
For singleton classes the method which returns the singleton
instance should be declared with "_singleton". This way the server
takes care that references get never destroyed on server side.
=item B<Simple methods>
What's simple about these methods is their return value: it's
a scalar, array, hash or even any complex reference structure
(Ok, not simple anymore ;), but in particular it returns B<NO> objects,
because this needs to handled specially (see below).
Declare simple methods by assigning 1 in the method declaration.
=item B<Object returners>
Methods which return objects need to be declared by assigning
"_object" to the method name here. They're not bound to return
just one scalar object reference and may return an array or list
reference with a bunch of objects as well.
=back
=back
=head2 SSL OPTIONS
The client/server protocol of Event::RPC is not encrypted by default,
so everyone listening on your network can read or even manipulate
data. To prevent this efficiently you can enable SSL encryption.
Event::RPC uses the IO::Socket::SSL Perl module for this.
First you need to generate a server key and certificate for your server
using the openssl command which is part of the OpenSSL distribution,
e.g. by issueing these commands (please refer to the manpage of openssl
for details - this is a very rough example, which works in general, but
probably you want to tweak some parameters):
% openssl genrsa -des3 -out server.key 1024
% openssl req -new -key server.key -out server.csr
% openssl x509 -req -days 3600 -in server.csr \
-signkey server.key -out server.crt
After executing these commands you have the following files
server.crt
server.key
server.csr
Event::RPC needs the first two of them to operate with SSL encryption.
To enable SSL encryption you need to pass the following options
to the constructor:
=over 4
=item B<ssl>
The ssl option needs to be set to 1.
=item B<ssl_key_file>
This is the filename of the server.key you generated with
the openssl command.
=item B<ssl_cert_file>
This is the filename of the server.crt file you generated with
the openssl command.
=item B<ssl_passwd_cb>
Your server key is encrypted with a password you entered during the
key creation process described above. This callback must return
it. Depending on how critical your application is you probably must
request the password from the user during server startup or place it
into a more or less secured file. For testing purposes you
can specify a simple anonymous sub here, which just returns the
password, e.g.
ssl_passwd_cb => sub { return "topsecret" }
But note: having the password in plaintext in your program code is
insecure!
=item B<ssl_opts>
This optional parameter takes a hash reference of options
passed to IO::Socket::SSL->new(...) to have more control
over the server SSL listener.
=back
=head2 AUTHENTICATION OPTIONS
SSL encryption is fine, now it's really hard for an attacker to
listen or modify your network communication. But without any further
configuration any user on your network is able to connect to your
server. To prevent this users resp. connections to your server
needs to be authenticated somehow.
Since version 0.87 Event::RPC has an API to delegate authentication
tasks to a module, which can be implemented outside Event::RPC.
To be compatible with prior releases it ships the module
Event::RPC::AuthPasswdHash which implements the old behaviour
transparently.
This default implementation is a simple user/password based model. For now
this controls just the right to connect to your server, so knowing
one valid user/password pair is enough to access all exported methods
of your server. Probably a more differentiated model will be added later
which allows granting access to a subset of exported methods only
for each user who is allowed to connect.
The following options control the authentication:
=over 4
=item B<auth_required>
Set this to 1 to enable authentication and nobody can connect your server
until he passes a valid user/password pair.
=item B<auth_passwd_href>
If you like to use the builtin Event::RPC::AuthPasswdHash module
simply set this attribute. If you decide to use B<auth_module>
(explained beyound) it's not necessary.
B<auth_passwd_href> is a hash of valid user/password pairs. The password
stored here needs to be encrypted using Perl's crypt() function, using
the username as the salt.
Event::RPC has a convenience function for generating such a crypted
password, although it's currently just a 1:1 wrapper around Perl's
builtin crypt() function, but probably this changes someday, so better
use this method:
$crypted_pass = Event::RPC->crypt($user, $pass);
This is a simple example of setting up a proper B<auth_passwd_href> with
two users:
auth_passwd_href => {
fred => Event::RPC->crypt("fred", $freds_password),
nick => Event::RPC->crypt("nick", $nicks_password),
},
=item B<auth_module>
( run in 0.664 second using v1.01-cache-2.11-cpan-5b529ec07f3 )