Project

General

Profile

Download (4.24 KB) Statistics
| Branch: | Tag: | Revision:
ecdabe95 Marc Dequènes (Duck)
#--
# CyborgHood, a distributed system management software.
364e4a96 Marc Dequènes (Duck)
# Copyright (c) 2009-2011 Marc Dequènes (Duck) <Duck@DuckCorp.org>
ecdabe95 Marc Dequènes (Duck)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++

429ebb9c Marc Dequènes (Duck)
require 'cyborghood/cyborg'
d7ae0ab2 Marc Dequènes (Duck)
require 'cyborghood/cyborg/botnet/interface'
require 'cyborghood/cyborg/botnet/conversation'
require 'cyborghood/cyborg/botnet/dsl'
c501ebc2 Marc Dequènes (Duck)
require 'set'
ecdabe95 Marc Dequènes (Duck)
module CyborgHood
c712f2db Marc Dequènes (Duck)
module BotNet
355ba318 Marc Dequènes (Duck)
CORE_API_VERSION = "1.0~"

c712f2db Marc Dequènes (Duck)
def self.included(base)
case Config.instance.botnet.connection_type
when 'unix_socket'
d7ae0ab2 Marc Dequènes (Duck)
return base.class_eval("include BotNetUNIXSocket")
c712f2db Marc Dequènes (Duck)
else
raise CyberError.new(:unrecoverable, "config", "Unknown botnet connection type")
end
end

def setup
super
d7ae0ab2 Marc Dequènes (Duck)
c712f2db Marc Dequènes (Duck)
@comm_list = {}
@comm_list_attempt = {}
d7ae0ab2 Marc Dequènes (Duck)
7466fc08 Marc Dequènes (Duck)
# default empty interface
define_interface("0") {}
end

def define_interface(version, &block)
c2b0e202 Marc Dequènes (Duck)
@interface_creation = Proc.new do
interface = DSL::ServerApiNode.new(self, &block)
# additional behavior to comply with the Cyborg API
interface.add_behavior do
node "_cyborg_" do
on_request do |request|
request.reply.results = {
:name => bot.name,
:product_name => PRODUCT,
:product_version => VERSION,
:core_api_version => CORE_API_VERSION,
:cyborg_api_version => version
}
feb16bd0 Marc Dequènes (Duck)
request.send_reply
c2b0e202 Marc Dequènes (Duck)
end
7466fc08 Marc Dequènes (Duck)
end
end
c2b0e202 Marc Dequènes (Duck)
interface
end # @interface_creation
end

def interface
# recreate dynamic interface each time, to ensure concurrent calls do not clash
@interface_creation.call
c712f2db Marc Dequènes (Duck)
end

429ebb9c Marc Dequènes (Duck)
def contact_peer(peer, block, dont_open_new_connection = false)
3e80678a Marc Dequènes (Duck)
if @comm_list.has_key? peer
a089227c Marc Dequènes (Duck)
if @comm_list[peer].usuable?
logger.debug "Botnet: Reusing connection for peer #{peer}"
return block.call @comm_list[peer]
end
3e80678a Marc Dequènes (Duck)
end
429ebb9c Marc Dequènes (Duck)
return if dont_open_new_connection

3e80678a Marc Dequènes (Duck)
logger.debug "Botnet: Trying to open a new connection to peer #{peer}"

429ebb9c Marc Dequènes (Duck)
if @comm_list_attempt.has_key? peer
@comm_list_attempt[peer] << block
d57fd602 Marc Dequènes (Duck)
else
429ebb9c Marc Dequènes (Duck)
@comm_list_attempt[peer] = [block]

# demultiplex callbacks
callback = proc do |conversation|
block_list = @comm_list_attempt[peer]
# purge list at once to avoid races
@comm_list_attempt.delete(peer)

block_list.each do |block|
block.call conversation
0299bce8 Marc Dequènes (Duck)
end
35e0fb89 Marc Dequènes (Duck)
end
429ebb9c Marc Dequènes (Duck)
begin
yield(callback)
rescue
3e80678a Marc Dequènes (Duck)
logger.debug "Botnet: connection attempt to peer #{peer} failed: " + $!
429ebb9c Marc Dequènes (Duck)
# TODO: retry (wait_timer + recursive call + counter)
block.call false
end
d57fd602 Marc Dequènes (Duck)
end
end
d1e614b5 Marc Dequènes (Duck)
bc642412 Marc Dequènes (Duck)
# used to quit properly and later to reuse communication channels
def register_communication(peer, conversation)
a089227c Marc Dequènes (Duck)
logger.debug "Botnet: conversation with '#{peer}' ready"
bc642412 Marc Dequènes (Duck)
@comm_list[peer] = conversation
end

def unregister_communication(peer)
a089227c Marc Dequènes (Duck)
logger.debug "Botnet: conversation with '#{peer}' closed"
bc642412 Marc Dequènes (Duck)
@comm_list.delete(peer)
7d493229 Marc Dequènes (Duck)
@pending_conversation_close.delete(peer)
d1e614b5 Marc Dequènes (Duck)
end

a089227c Marc Dequènes (Duck)
def stop(condition)
super do
@comm_list.each_value{|conv| conv.stop(condition) }
end
d1e614b5 Marc Dequènes (Duck)
end

f292535b Marc Dequènes (Duck)
protected

7d493229 Marc Dequènes (Duck)
def process_system_notification(msg)
if msg[:topic] == 'CONVERSATION IDLE'
peer = @comm_list[msg[:peer]]
return if peer.nil?

peer.bye
else
super
end
end

f292535b Marc Dequènes (Duck)
def ready_to_stop?
4d9f2962 Marc Dequènes (Duck)
@comm_list.empty? and super
f292535b Marc Dequènes (Duck)
end
d1e614b5 Marc Dequènes (Duck)
end
d7ae0ab2 Marc Dequènes (Duck)
autoload :BotNetUNIXSocket, 'cyborghood/cyborg/botnet/backend/unix'
ecdabe95 Marc Dequènes (Duck)
end