Parent

Included Modules

Arachni::RPC::EM::Server

EventMachine-based RPC server.

@author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>

Attributes

logger[R]

@return [Logger]

opts[R]

@return [Hash] Configuration options.

token[R]

@return [String] Authentication token.

Public Class Methods

new( opts ) click to toggle source

Starts EventMachine and the RPC server.

@example Example options:

{
    :host  => 'localhost',
    :port  => 7331,

    # optional authentication token, if it doesn't match the one
    # set on the server-side you'll be getting exceptions.
    :token => 'superdupersecret',

    # optional serializer (defaults to YAML)
    :serializer => Marshal,

    # serializer to use if the first choice fails
    :fallback_serializer => YAML,

    #
    # In order to enable peer verification one must first provide
    # the following:
    #
    # SSL CA certificate
    :ssl_ca     => cwd + '/../spec/pems/cacert.pem',
    # SSL private key
    :ssl_pkey   => cwd + '/../spec/pems/client/key.pem',
    # SSL certificate
    :ssl_cert   => cwd + '/../spec/pems/client/cert.pem'
}

@param [Hash] opts @option opts [String] :host Hostname/IP address. @option opts [Integer] :port Port number. @option opts [String] :socket Path to UNIX domain socket. @option opts [String] :token Optional authentication token. @option opts [.dump, .load] :serializer (YAML)

Serializer to use for message transmission.

@option opts [.dump, .load] :fallback_serializer

Optional fallback serializer to be used when the primary one fails.

@option opts [Integer] :max_retries

How many times to retry failed requests.

@option opts [String] :ssl_ca SSL CA certificate. @option opts [String] :ssl_pkey SSL private key. @option opts [String] :ssl_cert SSL certificate.

# File lib/arachni/rpc/em/server.rb, line 76
def initialize( opts )
    @opts = opts

    if @opts[:ssl_pkey] && @opts[:ssl_cert]
        if !File.exist?( @opts[:ssl_pkey] )
            raise "Could not find private key at: #{@opts[:ssl_pkey]}"
        end

        if !File.exist?( @opts[:ssl_cert] )
            raise "Could not find certificate at: #{@opts[:ssl_cert]}"
        end
    end

    @token = @opts[:token]

    @logger = ::Logger.new( STDOUT )
    @logger.level = Logger::INFO

    @host, @port = @opts[:host], @opts[:port]
    @socket = @opts[:socket]

    if !@socket && !(@host || @port)
        fail ArgumentError, 'Needs either a :socket or :host and :port options.'
    end

    @port = @port.to_i

    clear_handlers
end

Public Instance Methods

add_async_check( &block ) click to toggle source

@example

server.add_async_check do |method|
    #
    # Must return 'true' for async and 'false' for sync.
    #
    # Very simple check here...
    #
    'async' ==  method.name.to_s.split( '_' )[0]
end

@param [Block] block

Block to identify methods that pass their result to a block instead of
simply returning them (which is the most usual operation of async methods).
# File lib/arachni/rpc/em/server.rb, line 122
def add_async_check( &block )
    @async_checks << block
end
add_handler( name, obj ) click to toggle source

@example

server.add_handler( 'myclass', MyClass.new )

@param [String] name

Name by which to make the object available over RPC.

@param [Object] obj Instantiated server object to expose.

# File lib/arachni/rpc/em/server.rb, line 135
def add_handler( name, obj )
    @objects[name]       = obj
    @methods[name]       = Set.new
    @async_methods[name] = Set.new

    obj.class.public_instance_methods( false ).each do |method|
        @methods[name]       << method.to_s
        @async_methods[name] << method.to_s if async_check( obj.method( method ) )
    end
end
alive?() click to toggle source

@return [TrueClass]

# File lib/arachni/rpc/em/server.rb, line 224
def alive?
    true
end
call( connection ) click to toggle source

@note If the called method is asynchronous it will be sent by this method

directly, otherwise it will be handled by the {Handler}.

@param [Handler] connection

Connection with request information.

@return [Arachni::RPC::Response]

# File lib/arachni/rpc/em/server.rb, line 184
def call( connection )
    req          = connection.request
    peer_ip_addr = connection.peer_ip_addr

    expr, args = req.message, req.args
    meth_name, obj_name = parse_expr( expr )

    log_call( peer_ip_addr, expr, *args )

    if !object_exist?( obj_name )
        msg = "Trying to access non-existent object '#{obj_name}'."
        @logger.error( 'Call' ){ msg + " [on behalf of #{peer_ip_addr}]" }
        raise InvalidObject.new( msg )
    end

    if !public_method?( obj_name, meth_name )
        msg = "Trying to access non-public method '#{meth_name}'."
        @logger.error( 'Call' ){ msg + " [on behalf of #{peer_ip_addr}]" }
        raise InvalidMethod.new( msg )
    end

    # The handler needs to know if this is an async call because if it is
    # we'll have already send the response and it doesn't need to do
    # transmit anything.
    res = Response.new
    res.async! if async?( obj_name, meth_name )

    if res.async?
        @objects[obj_name].send( meth_name.to_sym, *args ) do |obj|
            res.obj = obj
            connection.send_response( res )
        end
    else
        res.obj = @objects[obj_name].send( meth_name.to_sym, *args )
    end

    res
end
clear_handlers() click to toggle source

Clears all handlers and their associated information like methods and async check blocks.

@see add_handler @see add_async_check

# File lib/arachni/rpc/em/server.rb, line 151
def clear_handlers
    @objects = {}
    @methods = {}

    @async_checks  = []
    @async_methods = {}
end
run() click to toggle source

Runs the server and blocks while EM ir running.

# File lib/arachni/rpc/em/server.rb, line 160
def run
    Arachni::RPC::EM.schedule { start }
    Arachni::RPC::EM.block
end
shutdown() click to toggle source

Shuts down the server after 2 seconds

# File lib/arachni/rpc/em/server.rb, line 229
def shutdown
    wait_for = 2

    @logger.info( 'System' ){ "Shutting down in #{wait_for} seconds..." }

    # Don't die before returning...
    ::EM.add_timer( wait_for ) do
        File.unlink( @socket ) if @socket
        ::EM.stop
    end
    true
end
start() click to toggle source

Starts the server but does not block.

# File lib/arachni/rpc/em/server.rb, line 166
def start
    @logger.info( 'System' ){ 'RPC Server started.' }
    @logger.info( 'System' ) do
        interface = @socket ? @socket : "#{@host}:#{@port}"
        "Listening on #{interface}"
    end

    opts = @socket ? @socket : [@host, @port]
    ::EM.start_server( *[opts, Handler, self].flatten )
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.