Exemplo n.º 1
0
    def __init__(self, watch_stack, watch_stack_lock, watch_queue, response_queue, client_address, client_socket):
        """
        Watching process to handle response from the bus and forward these on the client socket stream

        :param watch_stack: List of address watched
        :param watch_stack_lock: Lock on the address watched
        :param watch_queue: Queue of address watched to send back to the client (deprecated)
        :param response_queue:queue of response to send back to the client (deprecated)
        :param client_address: client socket address reference
        :param client_socket: client socket reference
        """
        threading.Thread.__init__(self)
        self.parser = Parser()
        self.watch_stack = watch_stack              # list of address watched
        self.watch_stack_lock = watch_stack_lock    # lock on the watch address list to share this between threads
        self.watch_queue = watch_queue              # queue of watching response to send back to the client socket
        self.response_queue = response_queue        # queue of response to send back to the client socket
        self.client_address = client_address        # client address for socket communication
        self.client_socket = client_socket          # client socket reference
        self.cache_ok = False                       # Flag to indicate cache status (activated or not) - deprecated
        self.eibd_connection = None                 # Eibd connection reference
        self.remote_socket = None                   # Eibd socket connection reference
        self.connected = False                      # Flag to indicate EIBD connection status
        self.buff = None                            # Buffer to deal with eibd data
        self.src = None                             # Source address for eibd transaction (data exchange)
        self.dest = None                            # Destination address for eibd transaction (data exchange)
        self.parser = Parser()                      # Reference to the parser to use to parse information (translation)
        self.is_running = False                     # Flag to indicate if the thread is running or if it has to be stop
Exemplo n.º 2
0
    def __init__(self, client_socket, client_address, buffer_size=BUFF_SIZE, options=None):
        threading.Thread.__init__(self)             # thread initialization
        self.client_socket = client_socket          # client socket information
        self.client_address = client_address        # client address information

        self.parser = Parser()                      # define the parser for the thread
        self.processor = Processor()                # define the process launcher for the thread ...
        self.processor.set_parser(self.parser)      # ... and configure it
        self.name = "anonymous"                     # define the name of the client
        self.logged_in = False                      # tag user as not logged in (according to the protocol
        self.failed_attempt = 0                     # current number of failed response handling attempt
        self.max_failed_attempt = 10                # maximum number of failed response handling attempt

        self.options = options                      # optional configuration option
        self.buffer_size = buffer_size              # size of the buffer to read / write data from / to the socket

        self.watch_stack = []                       # stack to store watched addresses
        self.watch_stack_lock = threading.RLock()   # lock on the watch_stack
        self.watch_queue = Queue.Queue()            # queue for watching response
        self.read_queue = Queue.Queue()             # queue for reading from eibd socket
        self.write_queue = Queue.Queue()            # queue for write to eibd socket
        self.is_running = False                     # indicates if the thread is running or has been broked (idle convenience)

        # define the daemon to write on the queue
        self.writer_daemon = EibdWriter(self.write_queue, self.watch_stack_lock)

        # define the daemon to listen connection on the queue
        self.listener_daemon = EibdWatcher(self.watch_stack, self.watch_stack_lock, self.watch_queue, self.read_queue, self.client_address, self.client_socket)
Exemplo n.º 3
0
    def __init__(self, processor=None):
        super(Spy, self).__init__()
        if processor is None:
            self.processor = Processor("ip:127.0.0.1", Parser())
        else:
            self.processor = processor

        self._stop = threading.Event()
Exemplo n.º 4
0
    def __init__(self, queue, watch_stack_lock, eibd_addr='ip:127.0.0.1', parser=None):
        threading.Thread.__init__(self)
        self.queue = queue
        self.watch_stack_lock = watch_stack_lock

        self.queue_wait_time = 0.0
        self.dpt = Dpt_Types.dpt_type(self)

        # may be use for parsing, but normally, the parser should do the job
        self.AddrRegex = re.compile(r"(?:|(\d+)[\x2F|\x2E])(\d+)[\x2F|\x2E](\d+)$", re.MULTILINE)

        #self.eibmutex = threading.RLock()  # no longer use due to queue management implementation

        self.eibd_address = eibd_addr
        self.command = None
        self.eibd_connection = None
        self.connected = False
        self.is_running = False
        if parser is None:
            self.parser = Parser()
        else:
            self.parser = parser
Exemplo n.º 5
0
        print "Quit handled"
        self.stop()
        self.join(2)

    def run(self):
        self.processor.connect()
        self.processor.init_watcher()
        while True:
            resp = self.processor.watch()
            print "Response received : %s" % resp
        self.processor.disconnect()

if __name__ == '__main__':
    import sys
    from cmd_parser import Parser
    parser = Parser()
    processor = Processor("ip:127.0.0.1", parser)
    addr = sys.argv[1]
    val = sys.argv[2]
    #addr = '15/0/2'
    #val = '00'
    print 'Connecting'
    try:
        processor.connect()

        spy = Spy()
        spy.start()

        _len = processor.write(addr, val)
        print "Len written is %d" % _len
        print "Eibd data : %s\n" % processor.last_data
Exemplo n.º 6
0
def handler(client_socket, client_address, buffer_size=1024):
    """
    This method will run for each client. It is a thread callback,
    It means that it is execute inside a thread.

    This thread should have many references to be able to dial with the client.

    :param clientsock: Reference to the client socket
    :param addr: address of the socket.
    """

    parser = Parser()               # define the parser for the thread
    processor = Processor()         # define the process launcher for the thread ...
    processor.set_parser(parser)    # ... and configure it
    name = "anonymous"              # define the name of the client
    logged_in = False               # tag user as not logged in (according to the protocol

    while 1:
        data = client_socket.recv(buffer_size)
        if not data or data.rstrip() == 'quit':     # hang off in this case
            break

        #### command validation ... ####
        command = data.rstrip()
        liblogging.log("Receive command [%s] from %s" % (command, client_address), liblogging.DEBUG)
        if not parser.is_valid_command(command):
            msg = "nE E22, \"%s: Invalid argument\"\n" % command
            liblogging.log("Invalid command [%s] received from[ %s]" % (command, client_address), liblogging.WARNING)
            client_socket.send(msg)
            continue

        # command parsing process
        header = libkonext.get_header(command)
        liblogging.log("Receive header [%s] from %s" % (header, client_address), liblogging.DEBUG)

        # first, check if the login command has been sent
        if not logged_in and header != libkonext.HELO_PREFIX:
            msg = "nE E13, \"%s: Permission denied\"\n" % command
            liblogging.log("Permission denied for %s, client not connected" % client_address, liblogging.WARNING)
            client_socket.send(msg)
            continue

        # check if the command is a valid helo command
        if not logged_in and header == libkonext.HELO_PREFIX and not parser.is_valid_helo_command(command):
            msg = "nE E22, \"%s: Invalid argument\"\n" % command
            liblogging.log("Invalid helo command [%s] received from[ %s]" % (command, client_address), liblogging.WARNING)
            client_socket.send(msg)
            continue

        #### end of command validation ... ####

        #### command processing ####

        # log in client
        if header == libkonext.HELO_PREFIX:
            name = libkonext.get_client_name(command)
            liblogging.log("The client %s is now connected with %s" % (client_address, name), liblogging.INFO)
            msg = "%s\n" % (libkonext.get_ack(header) % name)
            client_socket.send(msg)
            logged_in = True
        else:
            try:
                # manage command case ...
                response = libkonext.send_command(command, processor, parser)
                client_socket.send(response)
                continue
            except Exception:
                msg = "nE E22, \"%s: Invalid argument\"\n" % command
                liblogging.log("Invalid command [%s] received from[ %s]" % (command, client_address), liblogging.WARNING)
                client_socket.send(msg)

        # try:
        #     msg = "%s\n" % (libkonext.get_ack(header) % name)
        # except TypeError:
        #     msg = "%s\n" % libkonext.get_ack(header)
        #
        # client_socket.send(msg)


    #### Connection closing ####
    header = libkonext.get_header(libkonext.BYE_ACK)
    msg = "%s %s\n" %(header, name)
    client_socket.send(msg)
    client_socket.close()
    liblogging.log("Connection closed from (%s,%s)." % client_address)
Exemplo n.º 7
0
class EibdWatcher(threading.Thread):
    """
    Watch the eibd queue and send back response to the client
    """

    READ_COMMAND_HEADER = "RE"
    SEND_COMMAND_HEADER = "SE"
    WATCH_COMMAND_HEADER = "WE"
    UNWATCH_COMMAND_HEADER = "UE"

    READ_COMMAND_CODE = 0x1
    SEND_COMMAND_CODE = 0x2
    WATCH_COMMAND_CODE = 0x3
    UNWATCH_COMMAND_CODE = 0x4
    KNX_READ_FLAG = 0x00
    KNX_RESPONSE_FLAG = 0x40
    KNX_WRITE_FLAG = 0x80

    def __init__(self, watch_stack, watch_stack_lock, watch_queue, response_queue, client_address, client_socket):
        """
        Watching process to handle response from the bus and forward these on the client socket stream

        :param watch_stack: List of address watched
        :param watch_stack_lock: Lock on the address watched
        :param watch_queue: Queue of address watched to send back to the client (deprecated)
        :param response_queue:queue of response to send back to the client (deprecated)
        :param client_address: client socket address reference
        :param client_socket: client socket reference
        """
        threading.Thread.__init__(self)
        self.parser = Parser()
        self.watch_stack = watch_stack              # list of address watched
        self.watch_stack_lock = watch_stack_lock    # lock on the watch address list to share this between threads
        self.watch_queue = watch_queue              # queue of watching response to send back to the client socket
        self.response_queue = response_queue        # queue of response to send back to the client socket
        self.client_address = client_address        # client address for socket communication
        self.client_socket = client_socket          # client socket reference
        self.cache_ok = False                       # Flag to indicate cache status (activated or not) - deprecated
        self.eibd_connection = None                 # Eibd connection reference
        self.remote_socket = None                   # Eibd socket connection reference
        self.connected = False                      # Flag to indicate EIBD connection status
        self.buff = None                            # Buffer to deal with eibd data
        self.src = None                             # Source address for eibd transaction (data exchange)
        self.dest = None                            # Destination address for eibd transaction (data exchange)
        self.parser = Parser()                      # Reference to the parser to use to parse information (translation)
        self.is_running = False                     # Flag to indicate if the thread is running or if it has to be stop

    # --------------------------------------------------------- #

                        #### logging commands ####

    # --------------------------------------------------------- #

    # TODO refactor the logging methods to use a more common / convenient way
    def log(self, message, level=liblogging.INFO):
        liblogging.log(message, level)

    def debug(self, message):
        self.log(message, liblogging.DEBUG)

    def info(self, message):
        self.log(message)

    def warn(self, message):
        self.log(message, liblogging.WARNING)

    def error(self, message):
        self.log(message, liblogging.ERROR)

    def critical(self, message):
        self.log(message, liblogging.CRITICAL)

    def fatal(self, message):
        self.log(message, liblogging.FATAL)

    # --------------------------------------------------------- #

    def connect(self, eibd_address='ip:127.0.0.1'):
        self.eibd_connection = EIBConnection.EIBConnection()
        self.remote_socket = self.eibd_connection.EIBSocketURL(eibd_address)
        self.connected = True

    def disconnect(self):
        self.eibd_connection.EIBClose()
        self.remote_socket = None
        self.eibd_connection = None
        self.connected = False

    def init_cache(self):
        """
        Initialize cache reading options
        """
        warnings.warn("Cache is now deprecated in init_cache", category=DeprecationWarning)
        self.debug("Eibd listener trying to intialize")
        if not self.cache_ok:
            self.debug("Cache opening is required")
            self.eibd_connection.EIB_Cache_Enable()
            self.cache_ok = True
            self.debug("Cache successfully opened")
        else:
            self.debug("Cache already opened, skip process")

    def init_data(self):
        """
        Initialize data to use with the connection
        """
        self.debug("Eibd listener intializing data (buffer, source and destination) to handle information published on the eibd connection")
        self.buff = EIBConnection.EIBBuffer()
        self.src = EIBConnection.EIBAddr()
        self.dest = EIBConnection.EIBAddr()
        self.debug("Eibd listener successfully initialized data (buffer, source and destination)")

    def open_connection(self):
        self.debug("Eibd listener opening connection")
        if self.eibd_connection is None:
            self.connect()
        self.eibd_connection.EIBOpen_GroupSocket_async(0)
        self.debug("Eibd listener successfully opened connection")

    def send_back(self, message):
        self.client_socket.send(message)

    def is_watched_address(self, addr):
        self.watch_stack_lock.acquire()
        if addr in self.watch_stack:
            result = True
        else:
            result = False
        self.watch_stack_lock.release()
        return result

    def try_to_sendback_to_watchers(self, resp_kind, physical_address, group_address, resp_val_str):
        if not self.is_watched_address(group_address):
            return True
        try:
            header_ack = libkonext.get_ack(libkonext.READ)
            response_body = "%s=%s" % (group_address, resp_val_str)
            message = "%s %s\n" % (header_ack, response_body)
            self.send_back(message)
            return True
        except BaseException:
            self.error("Eibd listener genreic exception.")
            return False

    def send_back_response(self, resp_kind, physical_address, group_address, resp_val_str):
        try:
            header_ack = libkonext.get_ack(libkonext.READ)
            response_body = "%s=%s" % (group_address, resp_val_str)
            end_of_command = libkonext.END_ACK
            message = "%s %s\n%s\n" % (header_ack, response_body, end_of_command)
            self.send_back(message)
            return True
        except BaseException:
            self.error("Eibd listener genreic exception.")
            return False

    def prepare_and_send_response(self, resp_kind, raw_response):
        try:
            self.debug("Eibd listener process to dispatch command (response or write handled).")
            # do response processing ...
            physical_address = self.parser._decode_physical_addr(self.src.data)
            self.debug("Eibd listener : source (physical address) of the packet is %s." % physical_address)
            group_address = self.parser._decode_group_addr(self.dest.data)
            self.debug("Eibd listener : destination (group address) of the packet is %s." % group_address)
            resp_val_str = self.parser.format_result(raw_response)
            self.debug("Eibd listener : response value associate to the packet is %s." % resp_val_str)
            r = self.send_back_response(resp_kind, physical_address, group_address, resp_val_str)
            if not r:
                self.error("Error occurred during sending back the response to the client socket")
                return False
            r = self.try_to_sendback_to_watchers(resp_kind, physical_address, group_address, resp_val_str)
            if not r:
                self.error("Error occurred during sending back the watching response to the client socket")
                return False
            self.debug("Response successfully managed by the process")
            return True
        except BaseException:
            self.error("Eibd listener genreic exception.")
            return False

    def stop(self):
        self.is_running = False

    def run(self):
        self.info("Eibd listener starting ...")
        self.open_connection()
        self.init_cache()
        self.init_data()
        self.info("Eibd listener configuration process sucessfully made")
        self.is_running = True

        while self.is_running:
            self.info("Eibd listener waiting for information")
            resp_len = self.eibd_connection.EIBGetGroup_Src(self.buff, self.src, self.dest)
            resp = self.buff.buffer
            self.info("Eibd listener handling incoming information")

            if resp_len == -1:
                self.critical("Eibd listener failed to read incoming data")
            elif resp_len < 2:
                self.error("Eibd listener handling an invalid packet")
            elif resp[0] & 0x3 or (resp[1] & 0xC0) == 0xC0:
                self.error("Eibd listener handling an unknown APDU")
            else:
                self.debug("Eibd listener handling a valid packet, dispatching it.")
                # manage response type
                resp_kind = resp[1] & 0xC0
                if resp_kind == self.KNX_READ_FLAG:
                    # read is ignored by the process since it doesn't require an action...
                    self.debug("Eibd listener handling a read datagram, ignoring it.")
                elif resp_kind == self.KNX_RESPONSE_FLAG or resp_kind == self.KNX_WRITE_FLAG:
                    if resp_kind == self.KNX_WRITE_FLAG:
                        self.debug("Eibd listener handling a write datagram.")
                    else:
                        self.debug("Eibd listener handling a response datagram.")

                    proc_result = self.prepare_and_send_response(resp_kind, resp)
                    if not proc_result:
                        self.debug("Eibd listener handling an error during sending back information to the client socket")
                    else:
                        self.debug("Eibd listener successgfully handling and manage request.")
                else:
                    self.warn("Eibd listener : Unknown datagram handled")

        self.info("Eibd listener Exit from the listening thread")
        self.disconnect()
        # TODO : dispose all resources from the current object to be able to reinit it later without redundant call
        self.info("Eibd listener disconnected from the KNX Bus")
Exemplo n.º 8
0
class EibdWriter(threading.Thread):

    READ_COMMAND_HEADER = "RE"
    SEND_COMMAND_HEADER = "SE"
    WATCH_COMMAND_HEADER = "WE"
    UNWATCH_COMMAND_HEADER = "UE"

    READ_COMMAND_CODE = 0x1
    SEND_COMMAND_CODE = 0x2
    WATCH_COMMAND_CODE = 0x3
    UNWATCH_COMMAND_CODE = 0x4

    KNX_READ_FLAG = 0x00
    KNX_RESPONSE_FLAG = 0x40
    KNX_WRITE_FLAG = 0x80

    def __init__(self, queue, watch_stack_lock, eibd_addr='ip:127.0.0.1', parser=None):
        threading.Thread.__init__(self)
        self.queue = queue
        self.watch_stack_lock = watch_stack_lock

        self.queue_wait_time = 0.0
        self.dpt = Dpt_Types.dpt_type(self)

        # may be use for parsing, but normally, the parser should do the job
        self.AddrRegex = re.compile(r"(?:|(\d+)[\x2F|\x2E])(\d+)[\x2F|\x2E](\d+)$", re.MULTILINE)

        #self.eibmutex = threading.RLock()  # no longer use due to queue management implementation

        self.eibd_address = eibd_addr
        self.command = None
        self.eibd_connection = None
        self.connected = False
        self.is_running = False
        if parser is None:
            self.parser = Parser()
        else:
            self.parser = parser

    # --------------------------------------------------------- #

                        #### logging commands ####

    # --------------------------------------------------------- #

    # TODO refactor the logging methods to use a more common / convenient way
    def log(self, message, level=liblogging.INFO):
        liblogging.log(message, level)

    def debug(self, message):
        self.log(message, liblogging.DEBUG)

    def info(self, message):
        self.log(message)

    def warn(self, message):
        self.log(message, liblogging.WARNING)

    def error(self, message):
        self.log(message, liblogging.ERROR)

    def critical(self, message):
        self.log(message, liblogging.CRITICAL)

    def fatal(self, message):
        self.log(message, liblogging.FATAL)

    # --------------------------------------------------------- #

    def connect(self, eibd_address='ip:127.0.0.1'):
        self.eibd_connection = EIBConnection.EIBConnection()
        self.remote_socket = self.eibd_connection.EIBSocketURL(eibd_address)
        self.connected = True

    def disconnect(self):
        self.eibd_connection.EIBClose()
        self.remote_socket = None
        self.eibd_connection = None
        self.connected = False

    def send_write(self, address, value, flag=0x80):
        if not self.connected:
            self.connect()

        self.eibd_connection.EIBOpen_GroupSocket(0)
        _address = self.parser.read_group_address(address)
        _value = self.parser.read_hex(value)

        apdu = [0, flag]

        if type(_value) == int:
            apdu.append(_value)
        elif type(value) == list:
            apdu = apdu + _value
        else:
            msg = "invalid Message  %r to %r" % (value, address)
            self.error(msg)
            raise Exception(msg)

        self.debug("Sending write order ...")
        resp = self.eibd_connection.EIBSendGroup(_address, apdu)
        self.debug("Write order sent !")
        self.last_data = self.eibd_connection.data
        return resp

    def send_read(self, address, flag=0x00):
        if not self.connected:
            self.connect()
        self.eibd_connection.EIBOpen_GroupSocket(0)
        _address = self.parser.read_group_address(address)
        apdu = [flag] * 2
        self.debug("Sending read order ...")
        resp = self.eibd_connection.EIBSendGroup(_address, apdu)
        self.debug("Read order sent !")

        self.last_data = self.eibd_connection.data
        self.debug("data %s" % self.last_data)
        return resp

    def stop(self):
        self.is_running = False

    def run(self):
        self.info("Running the watcher")
        self.is_running = True
        while self.is_running:
            try:
                self.debug("Trying to extract something from the queue")
                task = self.queue.get()
            except Queue.Empty, qe:
                self.debug("Attempt to fetch something from the queue failed due to empty queue, sleeping for 1 sec. [%s]" % qe.message)
                time.sleep(1)
                pass
            except BaseException:
                self.info("Generic error occurred in the request queue processor, but ignoring it ")
                pass
            else: