class NetworkConnector(NetworkManager): notify = directNotify.newCategory('NetworkConnector') def __init__(self, dc_loader, address, port, channel, timeout=5000): NetworkManager.__init__(self) self._dc_loader = dc_loader self.__address = address self.__port = port self._channel = channel self.__timeout = timeout self.__manager = QueuedConnectionManager() self.__reader = QueuedConnectionReader(self.__manager, 0) self.__writer = ConnectionWriter(self.__manager, 0) self.__socket = None self.__read_task = None self.__disconnect_task = None @property def dc_loader(self): return self._dc_loader @property def channel(self): return self._channel @channel.setter def channel(self, channel): self._channel = channel def setup(self): if not self.__socket: self.__socket = self.__manager.open_TCP_client_connection( self.__address, self.__port, self.__timeout) if not self.__socket: raise NetworkError( 'Failed to connect TCP socket on address: <%s:%d>!' % (self.__address, self.__port)) self.__reader.add_connection(self.__socket) self.register_for_channel(self._channel) 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 register_for_channel(self, channel): """ Registers our connections channel with the MessageDirector """ datagram = NetworkDatagram() datagram.add_control_header(channel, types.CONTROL_SET_CHANNEL) self.handle_send_connection_datagram(datagram) def unregister_for_channel(self, channel): """ Unregisters our connections channel from the MessageDirector """ datagram = NetworkDatagram() datagram.add_control_header(channel, types.CONTROL_REMOVE_CHANNEL) self.handle_send_connection_datagram(datagram) 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) return task.cont def __listen_disconnect(self, task): """ Watches our connected socket object and determines if the stream has ended.. """ if not self.__reader.is_connection_ok(self.__socket): self.handle_disconnected() return task.done return task.cont def __handle_data(self, datagram): """ Handles incoming data from the connector """ if not datagram.get_length(): return di = NetworkDatagramIterator(datagram) code = di.get_uint8() self.handle_datagram(di.get_uint64(), di.get_uint64(), di.get_uint16(), di) def handle_send_connection_datagram(self, datagram): """ Sends a datagram to our connection """ self.__writer.send(datagram, self.__socket) def handle_datagram(self, channel, sender, message_type, di): """ Handles a datagram that was pulled from the queue """ def handle_disconnect(self): """ Disconnects our client socket instance """ self.__manager.close_connection(self.__socket) def handle_disconnected(self): """ Handles disconnection when the socket connection closes """ self.unregister_for_channel(self._channel) self.__reader.remove_connection(self.__socket) def shutdown(self): if self.__read_task: task_mgr.remove(self.__read_task) if self.__disconnect_task: task_mgr.remove(self.__disconnect_task) self.__read_task = None self.__disconnect_task = None
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