Beispiel #1
0
class NetworkListener(NetworkManager):
    notify = directNotify.newCategory('NetworkListener')

    def __init__(self, address, port, handler, backlog=10000):
        NetworkManager.__init__(self)

        self.__address = address
        self.__port = port
        self.__handler = handler
        self.__backlog = backlog

        self.__manager = QueuedConnectionManager()
        self.__listener = QueuedConnectionListener(self.__manager, 0)
        self.__reader = QueuedConnectionReader(self.__manager, 0)
        self.__writer = ConnectionWriter(self.__manager, 0)

        self.__socket = None
        self.__handlers = {}

        self.__listen_task = None
        self.__read_task = None
        self.__disconnect_task = None

    def setup(self):
        if not self.__socket:
            self.__socket = self.__manager.open_TCP_server_rendezvous(
                self.__address, self.__port, self.__backlog)

            if not self.__socket:
                raise NetworkError(
                    'Failed to bind TCP socket on address: <%s:%d>!' %
                    (self.__address, self.__port))

            self.__listener.add_connection(self.__socket)

        self.__listen_task = task_mgr.add(
            self.__listen_incoming,
            self.get_unique_name('listen-incoming'),
            taskChain=task_chain)

        self.__read_task = task_mgr.add(self.__read_incoming,
                                        self.get_unique_name('read-incoming'),
                                        taskChain=task_chain)

        self.__disconnect_task = task_mgr.add(
            self.__listen_disconnect,
            self.get_unique_name('listen-disconnect'),
            taskChain=task_chain)

    def __listen_incoming(self, task):
        """
        Polls for incoming connections
        """

        if self.__listener.new_connection_available():
            rendezvous = PointerToConnection()
            address = NetAddress()
            connection = PointerToConnection()

            if self.__listener.get_new_connection(rendezvous, address,
                                                  connection):
                self.__handle_connection(rendezvous, address, connection.p())

        return task.cont

    def __read_incoming(self, task):
        """
        Polls for incoming data
        """

        if self.__reader.data_available():
            datagram = NetworkDatagram()

            if self.__reader.get_data(datagram):
                self.__handle_data(datagram, datagram.get_connection())

        return task.cont

    def __listen_disconnect(self, task):
        """
        Watches all connected socket objects and determines if the stream has ended...
        """

        for handler in self.__handlers.values():
            if not self.__reader.is_connection_ok(handler.connection):
                handler.handle_disconnected()

        return task.cont

    def __has_handler(self, connection):
        """
        Returns True if the handler is queued else False
        """

        return connection in self.__handlers

    def __add_handler(self, handler):
        """
        Adds a handler to the handlers dictionary
        """

        if self.__has_handler(handler.connection):
            return

        handler.setup()
        self.__handlers[handler.connection] = handler
        self.__reader.add_connection(handler.connection)

    def __remove_handler(self, handler):
        """
        Removes a handler from the handlers dictionary
        """

        if not self.__has_handler(handler.connection):
            return

        handler.shutdown()
        self.__reader.remove_connection(handler.connection)
        del self.__handlers[handler.connection]

    def __handle_connection(self, rendezvous, address, connection):
        """
        Handles an incoming connection from the connection listener
        """

        handler = self.__handler(self, rendezvous, address, connection)
        self.__add_handler(handler)

    def __handle_data(self, datagram, connection):
        """
        Handles new data incoming from the connection reader
        """

        if not self.__has_handler(connection):
            return

        self.__handlers[connection].queue(datagram)

    def get_handler_from_channel(self, channel):
        """
        Returns a handler instance if one is associated with that channel
        """

        for connection, handler in self.__handlers.items():

            if handler.channel == channel:
                return handler

        return None

    def handle_send_datagram(self, datagram, connection):
        """
        Sends a datagram to a specific connection
        """

        if not self.__has_handler(connection):
            return

        self.__writer.send(datagram, connection)

    def handle_disconnect(self, handler):
        """
        Disconnects the handlers client socket instance
        """

        self.__manager.close_connection(handler.connection)

    def handle_disconnected(self, handler):
        """
        Handles disconnection of a client socket instance
        """

        self.__remove_handler(handler)

    def shutdown(self):
        if self.__listen_task:
            task_mgr.remove(self.__listen_task)

        if self.__read_task:
            task_mgr.remove(self.__read_task)

        if self.__disconnect_task:
            task_mgr.remove(self.__disconnect_task)

        self.__listen_task = None
        self.__read_task = None
        self.__disconnect_task = None

        self.__listener.remove_connection(self.__socket)
class Server(EventUser):
    def __init__(self):
        super().__init__()

        # Support objects
        self.manager = QueuedConnectionManager()
        self.listener = QueuedConnectionListener(self.manager, 0)
        self.reader = QueuedConnectionReader(self.manager, 0)
        self.writer = ConnectionWriter(self.manager, 0)
        self.handler = Handler(self)

        # Server model
        self.session_manager = SessionManager()
        self.notifier_manager = NotifierManager(self)
        self.task_manager = TaskManager(self)
        self.connections = []

        # Socket
        self.tcp_socket = self.manager.open_TCP_server_rendezvous(15000, 1000)
        self.listener.add_connection(self.tcp_socket)

        self.accept_event(Event.CLIENT_DISCONNECTION_PUBLISHED, self.close_connection)

    def run(self):
        """
        Creates threads with active targets for accepting new connections and
        receiving data from existing ones
        """
        Thread(target=self.listen_for_new_connections, daemon=True).start()
        Thread(target=self.listen_for_new_data, daemon=True).start()

    def listen_for_new_connections(self):
        """
        Listens to new connections, when avalibe, creates new session
        and event notifier
        """
        while True:
            if self.listener.new_connection_available():
                rendezvous = PointerToConnection()
                net_address = NetAddress()
                new_connection = PointerToConnection()
                if self.listener.get_new_connection(
                    rendezvous, net_address, new_connection
                ):
                    new_connection = new_connection.p()

                    session = self.session_manager.new_session(
                        new_connection,
                    )

                    self.connections.append(new_connection)
                    self.notifier_manager.new_notifier(session, new_connection)
                    self.task_manager.new_session_task_manager(session, new_connection)
                    self.reader.add_connection(new_connection)

    def listen_for_new_data(self):
        """
        Listens for new data from active connections
        """
        while True:
            if self.reader.data_available():
                datagram = NetDatagram()
                if self.reader.get_data(datagram):
                    connection = datagram.getConnection()
                    session = self.session_manager.for_connection(connection)
                    self.handler.handle_data(
                        datagram,
                        connection,
                        session,
                    )
            time.sleep(0.01)

    def close_connection(self, connection):
        self.manager.close_connection(connection)
        self.connections.remove(connection)

    def find_connection_by_hash(self, connection_hash):
        for connection in self.connections:
            if hash(connection) == connection_hash:
                return connection