Class: Arachni::RPC::Server::Dispatcher::Node

Inherits:
Object
  • Object
show all
Includes:
UI::Output
Defined in:
lib/arachni/rpc/server/dispatcher/node.rb

Overview

Dispatcher node class, helps maintain a list of all available Dispatchers in the grid and announce itself to neighbouring Dispatchers.

As soon as a new Node is fired up it checks-in with its neighbour and grabs a list of all available peers.

As soon as it receives the peer list it then announces itself to them.

Upon convergence there will be a grid of Dispatchers each one with its own copy of all available Dispatcher URLs.

Author:

Instance Method Summary collapse

Methods included from UI::Output

#debug?, #debug_off, #debug_on, #disable_only_positives, #included, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #unmute, #verbose?, #verbose_on

Constructor Details

#initialize(options, logfile = nil) ⇒ Node

Initializes the node by:

* Adding the neighbour (if the user has supplied one) to the peer list.
* Getting the neighbour's peer list and appending them to its own.
* Announces itself to the neighbour and instructs it to propagate our URL
  to the others.

Parameters:



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 40

def initialize( options, logfile = nil )
    @options = options
    @options.dispatcher.external_address ||= @options.rpc.server_address

    @url = "#{@options.dispatcher.external_address}:#{@options.rpc.server_port}"

    reroute_to_file( logfile ) if logfile

    print_status 'Initializing grid node...'

    @dead_nodes = []
    @neighbours = Set.new
    @nodes_info_cache = []

    if (neighbour = @options.dispatcher.neighbour)
        # Grab the neighbour's neighbours.
        connect_to_peer( neighbour ).neighbours do |urls|
            if urls.rpc_exception?
                add_dead_neighbour( neighbour )
                print_info "Neighbour seems dead: #{neighbour}"
                add_dead_neighbour( neighbour )
                next
            end

            # Add neighbour and announce it to everyone.
            add_neighbour( neighbour, true )

            urls.each { |url| @neighbours << url if url != @url }
        end
    end

    print_status( 'Node ready.' )

    log_updated_neighbours

    Reactor.global.at_interval( @options.dispatcher.node_ping_interval ) do
        ping
        check_for_comebacks
    end
end

Instance Method Details

#add_neighbour(node_url, propagate = false) ⇒ Object

Adds a neighbour to the peer list.

Parameters:

  • node_url (String)

    URL of a neighbouring node.

  • propagate (Boolean) (defaults to: false)

    Whether or not to announce the new node to the peers.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 93

def add_neighbour( node_url, propagate = false )
    # we don't want ourselves in the Set
    return false if node_url == @url
    return false if @neighbours.include?( node_url )

    print_status "Adding neighbour: #{node_url}"

    @neighbours << node_url
    log_updated_neighbours
    announce( node_url ) if propagate

    connect_to_peer( node_url ).add_neighbour( @url, propagate ) do |res|
        next if !res.rpc_exception?
        add_dead_neighbour( node_url )
        print_status "Neighbour seems dead: #{node_url}"
    end
    true
end

#alive?Boolean

Returns:

  • (Boolean)


168
169
170
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 168

def alive?
    true
end

#grid_member?Boolean

Returns ‘true` if grid member, `false` otherwise.

Returns:

  • (Boolean)

    ‘true` if grid member, `false` otherwise.



83
84
85
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 83

def grid_member?
    @neighbours.any?
end

#infoHash

Returns * ‘url` – This node’s URL.

  • ‘pipe_id` – Bandwidth Pipe ID

  • ‘weight` – Weight

  • ‘nickname` – Nickname

  • ‘cost` – Cost.

Returns:

  • (Hash)
    • ‘url` – This node’s URL.

    • ‘pipe_id` – Bandwidth Pipe ID

    • ‘weight` – Weight

    • ‘nickname` – Nickname

    • ‘cost` – Cost



158
159
160
161
162
163
164
165
166
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 158

def info
    {
        'url'      => @url,
        'pipe_id'  => @options.dispatcher.node_pipe_id,
        'weight'   => @options.dispatcher.node_weight,
        'nickname' => @options.dispatcher.node_nickname,
        'cost'     => @options.dispatcher.node_cost
    }
end

#neighboursArray

Returns Neighbour/node/peer URLs.

Returns:

  • (Array)

    Neighbour/node/peer URLs.



114
115
116
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 114

def neighbours
    @neighbours.to_a
end

#neighbours_with_info(&block) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/arachni/rpc/server/dispatcher/node.rb', line 118

def neighbours_with_info( &block )
    fail 'This method requires a block!' if !block_given?

    @neighbours_cmp = ''

    if @nodes_info_cache.empty? || @neighbours_cmp != neighbours.to_s
        @neighbours_cmp = neighbours.to_s

        each = proc do |neighbour, iter|
            connect_to_peer( neighbour ).info do |info|
                if info.rpc_exception?
                    print_info "Neighbour seems dead: #{neighbour}"
                    add_dead_neighbour( neighbour )
                    log_updated_neighbours

                    iter.return( nil )
                else
                    iter.return( info )
                end
            end
        end

        after = proc do |nodes|
            @nodes_info_cache = nodes.compact
            block.call( @nodes_info_cache )
        end

        Reactor.global.create_iterator( neighbours ).map( each, after )
    else
        block.call( @nodes_info_cache )
    end
end