Source

imalse / core / nodes / server.py

Full commit
"""This file defines the Server Command Meta Description"""

import copy
import jsonpickle

from core.cmd import CMD, UnknownEventException
from core.cmd.description import ServerDescription
from core.cmd.command import EchoCmd

class ServerCMD(CMD):
    
    """
    
    This class is a subclass of CMD. It extends the default CMD with commands
    related to a server.
    
    """
    
    name =  'server_cmd'
    
    def __init__(self, desc=None):
        """Initialize"""
        if desc == None:
            desc = ServerDescription()
        CMD.__init__(self, desc)
        self.srv_sock = None
    
    def start(self):
        """ Start the server.
        
        This method overrides the one in CMD.
        In real mode the server will call the 'accept' method in blocking way.
        In simulation mode the server will set the 'SetAcceptCallBack'.
        
        """
        self.srv_sock = self.node.create_sock({'type':'server', 'proto':'tcp'})
        self.node.bind(self.srv_sock, (self.addr, self.port))
        self.node.listen(self.srv_sock, 5)
                
        if self.node.NODE_TYPE.startswith('real'):
            while True:
                client_sock, address = self.node.accept(self.srv_sock)                
                self.trigger('recv_request_conn', client_sock, address)
        elif self.node.NODE_TYPE.startswith('sim'):
            self.sim_node_init()
        else:
            raise Exception("Unknown Node Type")

    @property
    def addr(self): 
        """Returns the server address."""
        return self.desc.server_address

    @property
    def port(self):
        """Returns the server port."""
        return self.desc.server_port

    def sim_node_init(self):
        """
        
        Initialize the server for a ns3 simulated node. A ns3 sim node doesn't
        support blocking methods, so we need to set the callback 
        'SetAcceptCallback'.
        
        """
        self.logger.debug('sim_node initialization')
        def connect_request(sock, addr):
            """Callback function when a request for a connection is received."""
            self.logger.info(' receive connect_request at sock [%s] from [%s]'
                             %(str(sock), str(addr)))
            return True

        def connect_created(client_sock, address):
            """Callback function when a connection has been established."""
            self.logger.info('connect_created for client sock [%s] \
                            and address[%s]' % (str(client_sock), str(address)))
            self.node.sockets[client_sock] = {'type':'client', 'proto': 'tcp'}
            self.trigger('recv_request_conn', client_sock, address)

        self.srv_sock.SetAcceptCallback(connect_request, connect_created)

    def recv_request_conn(self, client_sock, address):
        """Callback when connection request is received."""
        self.logger.info('receive request from addr: %s'%(str(address)))
        self.node.send(client_sock, 'connect_ack')        
        self.node.recv(client_sock, 512, self.node.dispatcher, threaded=True)

    def dispatcher(self, sock, data):
        """Try to execute commands present in data."""
        
        try:
            CMD.dispatcher(self, sock, data)
        except UnknownEventException as err:
            self.logger.error('unknown message: %s from %s'\
                              % (data, self.node.sockets[sock]))
            self.logger.exception("\n----------------\n the error is: \n" + \
                    str(err) + \
                    "\n----------------\n")
            self.node.send(sock, 'you have sent me a unknown message')

    def verify_master(self, sock, data):
        """Verify the identity of the bot master."""        
        if data.password == self.desc.master_password:            
            self.logger.info( 'bot master password verified' )
            self.node.set_master_sock(sock)
            self.node.send(sock, jsonpickle.encode(EchoCmd()))

    def echo_bots(self, sock, data):
        """Send the echo command to all bots."""
        self.logger.info('start to echo_bots' )
        new_data = copy.deepcopy(data)
        new_data.event = 'echo'
        for client_sock in self.node.client_socks:
            self.node.send(client_sock, jsonpickle.encode(new_data))
    
    def forward_to_bots(self, sock, data):
        """Forward data to all the bots"""        
        self.logger.info('start to echo_bots' )
        new_data = copy.deepcopy(data)
        new_data.event = data.bot_event
        del new_data.bot_event
        
        for client_sock in self.node.client_socks:            
            self.node.send(client_sock, jsonpickle.encode(new_data))
            
    def send_to_bot(self, sock, data):
        """Forward data to all the bots"""
        self.logger.info('send cmd to bot' )
        new_data = copy.deepcopy(data)
        new_data.event = data.bot_event
        
        del new_data.bot_event
        del new_data.addr
        
        for sock in self.node.sockets:
            if self.node.sockets[sock]['type'] == 'client':
                if self.node.sockets[sock]['addr'] == data.addr: 
                    self.node.send(sock, jsonpickle.encode(new_data))
    
    def send_to_botmaster(self, sock, data):
        """Forward data to botmaster"""
        print "forwarding to botmaster"
        new_data = copy.deepcopy(data)
        new_data.event = data.botmaster_event
        del new_data.botmaster_event
        
        self.node.send(self.node.master_sock, jsonpickle.encode(new_data))
                
    def disconnect(self):
        """Log a disconnect request."""
        self.logger.info('receive disconnect request')
        return False