Example #1
0
    def _define_responsibility_chain(self):
        self.m_StopHandler = StopHandler()

        self.m_DisconnectHandler = DisconnectHandler()
        self.m_DisconnectHandler.setNextHandler(self.m_StopHandler)

        self.m_SendDataHandler = SendDataHandler()
        self.m_SendDataHandler.setNextHandler(self.m_DisconnectHandler)

        self.m_SendDisconnectionHandler = SendDisconnectionDataHandler()
        self.m_SendDisconnectionHandler.setNextHandler(self.m_SendDataHandler)

        # first handler in chain of responsibility and should be called first
        self.m_SendConnectionHandler = SendConnectionDataHandler()
        self.m_SendConnectionHandler.setNextHandler(self.m_SendDisconnectionHandler)
Example #2
0
class FederationServerService(ServerServiceInterface, ServiceBase):

    def __init__(self):
        self._define_responsibility_chain()
        self.pipe = None
        self.federates: {str: Federate} = {}
        self.sel = selectors.DefaultSelector()

    def _send_connected_clients(self, connection):
        try:
            clients = self.db.query_user()
        except Exception as e:
            logger.warning("error thrown in getting clients from DataBase to send to federates " + str(e))
            return None
        for client in clients:
            try:
                proto_obj = FederatedEvent()
                proto_obj.contact.uid = str(client.uid)
                proto_obj.contact.callsign = str(client.CoT.detail.contact.callsign)
                proto_obj.contact.operation = 1
                proto_str = proto_obj.SerializeToString()
                header = self._generate_header(len(proto_str))
                connection.send(header+proto_str)
            except Exception as e:
                logger.warning("error thrown sending federate data to newly connected federate " + str(e))
                continue

    def _create_context(self) ->None:
        self.context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
        self.context.load_cert_chain(MainConfig.federationCert, MainConfig.federationKey,
                                     password=MainConfig.federationKeyPassword)

    def _create_listener(self, ip: str, port: int)->None:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        sock.bind((ip, port))
        sock.listen()
        ssock = self.context.wrap_socket(sock, server_side=True)
        ssock.setblocking(False)
        self.sel.register(ssock, selectors.EVENT_READ, data=None)

    def _define_responsibility_chain(self):
        self.m_StopHandler = StopHandler()

        self.m_DisconnectHandler = DisconnectHandler()
        self.m_DisconnectHandler.setNextHandler(self.m_StopHandler)

        self.m_SendDataHandler = SendDataHandler()
        self.m_SendDataHandler.setNextHandler(self.m_DisconnectHandler)

        self.m_SendDisconnectionHandler = SendDisconnectionDataHandler()
        self.m_SendDisconnectionHandler.setNextHandler(self.m_SendDataHandler)

        # first handler in chain of responsibility and should be called first
        self.m_SendConnectionHandler = SendConnectionDataHandler()
        self.m_SendConnectionHandler.setNextHandler(self.m_SendDisconnectionHandler)

    def main(self):
        from defusedxml import ElementTree as etree
        while True:
            time.sleep(0.1)
            command = self.receive_command_data(self.pipe)
            if command:
                try:
                    self.m_SendConnectionHandler.Handle(self, command)
                except Exception as e:
                    pass
            else:
                pass
            try:
                data = self.receive_data_from_federate(1)
            except ssl.SSLWantReadError:
                data = None
            if data:
                for protobuf_object in data:
                    # TODO: clean all of this up as it's just a PoC

                    # event = etree.Element('event')
                    # SpecificCoTObj = XMLCoTController().categorize_type(protobuf_object.type)
                    try:
                        detail = etree.fromstring(protobuf_object.event.other)
                        protobuf_object.event.other = ''
                        fts_obj = ProtobufSerializer().from_format_to_fts_object(protobuf_object, Event.FederatedCoT())
                        specific_obj = SendOther()
                        event = XmlSerializer().from_fts_object_to_format(fts_obj)
                        xmlstring = event
                        xmlstring.find('detail').remove(xmlstring.find('detail').find('remarks'))
                        xmlstring.find('detail').extend([child for child in detail])
                        # specific_obj.xmlString = etree.tostring(xmlstring)
                        print(etree.tostring(xmlstring))
                        specific_obj.xmlString = etree.tostring(xmlstring)
                        self.pipe.send(specific_obj)
                    except Exception as e:
                        pass
                    """if isinstance(SpecificCoTObj, SendOtherController):
                        detail = protobuf_object.event.other
                        protobuf_object.event.other = ''
                        fts_obj = ProtobufSerializer().from_format_to_fts_object(protobuf_object, Event.Other())
                        protobuf_object.event.other = detail
                        SpecificCoTObj.object = fts_obj
                        SpecificCoTObj.Object =
                    else:
                        fts_obj = ProtobufSerializer().from_format_to_fts_object(protobuf_object, SpecificCoTObj().object)
                        self.pipe.send(data)"""
            else:
                pass

    def receive_data_from_federate(self, timeout):
        """called whenever data is available from any federate and immediately proceeds to
        send data through process pipe
        """
        dataarray = []
        events = self.sel.select(timeout)
        for key, mask in events:
            if key.data is None:
                self._accept_connection(key.fileobj)
            else:
                federate_data = self._receive_new_data(key)
                if federate_data:
                    dataarray.append(federate_data)
        return dataarray

    def _receive_new_data(self, key):
        try:
            conn = key.fileobj
            header = conn.recv(4)
            if header:
                try:
                    buffer = self._get_header_length(header)
                    raw_protobuf_message = conn.recv(buffer)
                    print(raw_protobuf_message)
                    protobuf_object = FederatedEvent()
                    protobuf_object.ParseFromString(raw_protobuf_message)
                    return protobuf_object
                except Exception as e:
                    conn.recv(10000)
                    return None
            else:
                self.disconnect_client(key.data.uid)
        except OSError:
            return None
        except Exception as e:
            logger.warning("exception in receiving data from federate "+str(e))
            self.disconnect_client(key.data.uid)
    
    def _accept_connection(self, sock) -> None:
        try:
            import uuid
            conn, addr = sock.accept()  # Should be ready to read
            print('accepted connection from', addr)
            conn.setblocking(False)
            data = Federate()
            data.conn = conn
            # get federate certificate CN
            # data.name = dict(x[0] for x in conn.getpeercert()["subject"])["commonName"]
            data.name = addr[0]
            data.addr = addr
            data.uid = str(uuid.uuid4())
            events = selectors.EVENT_READ | selectors.EVENT_WRITE
            self._send_connected_clients(conn)
            self.sel.register(conn, events, data=data)
            self.federates[data.uid] = data

            self.db.create_ActiveFederation(id = data.uid, federate = "unknown", address = addr[0], port = addr[1], initiator = "Remote")
            return None
        except Exception as e:
            print(e)
            logger.warning("exception thrown accepting federation " + str(e))

    def _get_header_length(self, header):
        return int.from_bytes(header, 'big')

    def _generate_header(self, contentlength):
        return contentlength.to_bytes(4, byteorder="big")

    def send_data_to_clients(self, data):
        from defusedxml import ElementTree as etree
        try:
            if self.federates:
                xmlstring = data.xmlString
                detail = etree.fromstring(xmlstring).find('detail')
                protobuf = ProtobufSerializer().from_fts_object_to_format(data.modelObject)
                protobuf.event.other = etree.tostring(detail)
                protobufstring = protobuf.SerializeToString()
                header = self._generate_header(len(protobufstring))
                protobufstring = header + protobufstring
                print(protobufstring)
                for client in self.federates.values():
                    client.conn.send(protobufstring)
            else:
                return None
        except Exception as e:
            logger.warning("send data to clients failed with exception "+str(e))

    def disconnect_client(self, id: str) -> None:
        try:
            logger.info("disconnecting client")
            try:
                federate = self.federates[id]
            except Exception as e:
                logger.warning("federate array has no item with uid " + str(id) + " federates array is len " + str(
                    len(self.federates)))
                return None
            try:
                federate.conn.close()
                self.sel.unregister(federate.conn)
                del (self.federates[federate.uid])
            except Exception as e:
                logger.warning("exception thrown disconnecting client " + str(e))

            try:
                self.db.remove_ActiveFederation(f'id == "{federate.uid}"')
            except Exception as e:
                logger.warning("exception thrown removing outgoing federation from DB " + str(e))
            return None
        except Exception as e:
            logger.warning("exception thrown accessing client for disconnecting client " + str(e))

    def send_connection_data(self, CoT: ClientInformation):
        if self.federates:
            proto_obj = FederatedEvent()
            proto_obj.contact.uid = str(CoT.modelObject.uid)
            proto_obj.contact.callsign = str(CoT.modelObject.detail.contact.callsign)
            proto_obj.contact.operation = 1
            proto_str = proto_obj.SerializeToString()
            header = self._generate_header(len(proto_str))
            for fed in self.federates.values():
                fed.conn.send(header + proto_str)
        else:
            return None

    def send_disconnection_data(self, CoT: SendDisconnect):
        if self.federates:
            proto_obj = FederatedEvent()
            proto_obj.contact.uid = str(CoT.modelObject.detail.link.uid)
            proto_obj.contact.callsign = str(CoT.modelObject.detail.link.type)
            proto_obj.contact.operation = 4
            proto_str = proto_obj.SerializeToString()
            header = self._generate_header(len(proto_str))
            for fed in self.federates.values():
                fed.conn.send(header + proto_str)
        else:
            return None

    def start(self, pipe, ip, port):
        self.db = DatabaseController()
        self.pipe = pipe
        self._create_context()
        self._create_listener(ip, port)
        print('started federation server service')
        self.main()

    def stop(self):
        pass
class FederationClientServiceController(ServerServiceInterface, ServiceBase):
    #class FederationClientServiceController:
    """A service which controllers the connection too and transfer of data with
    federated servers.
    """
    def __init__(self):
        self._define_responsibility_chain()
        self.pipe = None
        self.federates: {str: Federate} = {}
        self.sel = selectors.DefaultSelector()

    def _send_connected_clients(self, connection):
        clients = self.db.query_user()
        for client in clients:
            try:
                proto_obj = FederatedEvent()
                proto_obj.contact.uid = str(client.uid)
                proto_obj.contact.callsign = str(
                    client.CoT.detail.contact.callsign)
                proto_obj.contact.operation = 1
                proto_str = proto_obj.SerializeToString()
                header = self._generate_header(len(proto_str))
                connection.send(header + proto_str)
            except Exception as e:
                logger.warning(
                    "error thrown sending federate data to newly connected federate "
                    + str(e))
                continue

    def _create_context(self):
        self.context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
        self.context.load_cert_chain(certfile=MainConfig.federationCert,
                                     keyfile=MainConfig.federationKey,
                                     password=MainConfig.federationKeyPassword)
        self.context.set_ciphers('DEFAULT@SECLEVEL=1')

    def _define_responsibility_chain(self):
        self.m_StopHandler = StopHandler()

        self.m_ConnectHandler = ConnectHandler()
        self.m_ConnectHandler.setNextHandler(self.m_StopHandler)

        self.m_DisconnectHandler = DisconnectHandler()
        self.m_DisconnectHandler.setNextHandler(self.m_ConnectHandler)

        self.m_SendDataHandler = SendDataHandler()
        self.m_SendDataHandler.setNextHandler(self.m_DisconnectHandler)

        self.m_SendDisconnectionHandler = SendDisconnectionDataHandler()
        self.m_SendDisconnectionHandler.setNextHandler(self.m_SendDataHandler)

        # first handler in chain of responsibility and should be called first
        self.m_SendConnectionHandler = SendConnectionDataHandler()
        self.m_SendConnectionHandler.setNextHandler(
            self.m_SendDisconnectionHandler)

    def main(self):
        from defusedxml import ElementTree as etree
        import time
        while True:
            time.sleep(0.1)
            command = self.receive_command_data(self.pipe)
            if command:
                try:
                    self.m_SendConnectionHandler.Handle(self, command)
                except Exception as e:
                    logger.debug("exception in command chain " + str(e))
            else:
                pass

            data = self.receive_data_from_federate(1)
            if data:
                for protobuf_object in data:
                    # TODO: clean all of this up as it's just a PoC

                    try:
                        detail = etree.fromstring(protobuf_object.event.other)
                        protobuf_object.event.other = ''
                        fts_obj = ProtobufSerializer(
                        ).from_format_to_fts_object(protobuf_object,
                                                    Event.FederatedCoT())
                        specific_obj = SendOther()
                        event = XmlSerializer().from_fts_object_to_format(
                            fts_obj)
                        xmlstring = event
                        xmlstring.find('detail').remove(
                            xmlstring.find('detail').find('remarks'))
                        xmlstring.find('detail').extend(
                            [child for child in detail])
                        # specific_obj.xmlString = etree.tostring(xmlstring)
                        print(etree.tostring(xmlstring))
                        specific_obj.xmlString = etree.tostring(xmlstring)
                        self.pipe.send(specific_obj)
                    except Exception as e:
                        pass
                    """if isinstance(SpecificCoTObj, SendOtherController):
                        detail = protobuf_object.event.other
                        protobuf_object.event.other = ''
                        fts_obj = ProtobufSerializer().from_format_to_fts_object(protobuf_object, Event.Other())
                        protobuf_object.event.other = detail
                        SpecificCoTObj.object = fts_obj
                        SpecificCoTObj.Object =
                    else:
                        fts_obj = ProtobufSerializer().from_format_to_fts_object(protobuf_object, SpecificCoTObj().object)
                        self.pipe.send(data)"""
            else:
                pass

    def connect_to_server(self, server_vars: Tuple[str, str]) -> None:
        try:
            federate_db_obj = self.db.query_Federation(
                f'id == "{server_vars[0]}"')[0]
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
            ssock = self.context.wrap_socket(
                sock, server_hostname=federate_db_obj.address)
            ssock.settimeout(10)
            ssock.connect(
                (str(federate_db_obj.address), int(federate_db_obj.port)))
            ssock.setblocking(False)
            federate = Federate()
            federate.uid = server_vars[0]
            federate.addr = federate_db_obj.address
            federate.conn = ssock
            federate.name = federate_db_obj.name
            events = selectors.EVENT_READ | selectors.EVENT_WRITE
            self.sel.register(ssock, events, federate)
            self.federates[server_vars[0]] = federate
            self._send_connected_clients(ssock)
            self.db.create_ActiveFederation(id=federate_db_obj.id,
                                            address=federate_db_obj.address,
                                            port=federate_db_obj.port,
                                            initiator="Self")
            self.db.update_Federation({"lastError": None},
                                      query=f'id == "{federate_db_obj.id}"')
            return None
        except Exception as e:
            try:
                self.db.remove_ActiveFederation(f'id == "{server_vars[0]}"')
            except Exception as e:
                logger.warning(
                    "exception thrown removing outgoing federation from DB " +
                    str(e))
            logger.warning("exception thrown creating new federation " +
                           str(e))
            try:
                self.db.update_Federation(
                    {
                        "status": "Disabled",
                        "lastError": str(e)
                    },
                    query=f'id == "{server_vars[0]}"')
            except Exception as e:
                logger.warning("exception thrown updating federate in db " +
                               str(e))

    def disconnect_client(self, id: str) -> None:
        try:
            try:
                federate = self.federates[id]
            except Exception as e:
                logger.warning("federate array has no item with uid " +
                               str(id) + " federates array is len " +
                               str(len(self.federates)))
                return None
            try:
                federate.conn.close()
                self.sel.unregister(federate.conn)
                del (self.federates[federate.uid])
            except Exception as e:
                logger.warning("exception thrown disconnecting client " +
                               str(e))
            try:
                self.db.remove_ActiveFederation(f'id == "{federate.uid}"')
            except Exception as e:
                logger.warning(
                    "exception thrown removing outgoing federation from DB " +
                    str(e))
            return None
        except Exception as e:
            logger.warning(
                "exception thrown accessing client for disconnecting client " +
                str(e))

    def receive_data_from_federate(self, timeout):
        """called whenever data is available from any federate and immediately proceeds to
        send data through process pipe
        """
        dataarray = []
        if self.federates:
            events = self.sel.select(timeout)
            for key, mask in events:
                conn = key.fileobj
                try:
                    header = conn.recv(4)
                except Exception as e:
                    continue
                if header:
                    try:
                        buffer = self._get_header_length(header)
                        raw_protobuf_message = conn.recv(buffer)
                        print(raw_protobuf_message)
                        protobuf_object = FederatedEvent()
                        protobuf_object.ParseFromString(raw_protobuf_message)
                        dataarray.append(protobuf_object)
                    except Exception as e:
                        conn.recv(10000)
                        continue
                else:
                    self.disconnect_client(key.data.uid)
            return dataarray
        else:
            return None

    def _get_header_length(self, header):
        return int.from_bytes(header, 'big')

    def _generate_header(self, contentlength):
        return contentlength.to_bytes(4, byteorder="big")

    def send_data_to_clients(self, data):
        from defusedxml import ElementTree as etree
        try:
            if self.federates:
                xmlstring = data.xmlString
                detail = etree.fromstring(xmlstring).find('detail')
                if detail:
                    protobuf = ProtobufSerializer().from_fts_object_to_format(
                        data.modelObject)
                    try:
                        protobuf.event.other = etree.tostring(detail)
                        protobufstring = protobuf.SerializeToString()
                        header = self._generate_header(len(protobufstring))
                        protobufstring = header + protobufstring
                        print(protobufstring)
                    except Exception as e:
                        logger.warning("creating protobuf message failed " +
                                       str(e))
                        return None
                    for client in self.federates.values():
                        client.conn.send(protobufstring)
                else:
                    return None
            else:
                return None
        except Exception as e:
            import traceback
            trace = traceback.format_exc()
            logger.warning("sending data to federates failed " + str(e))

    def send_connection_data(self, CoT: ClientInformation) -> None:
        try:
            if self.federates:
                logger.debug(
                    "connection data received in send_connection_data")
                proto_obj = FederatedEvent()
                proto_obj.contact.uid = str(CoT.modelObject.uid)
                proto_obj.contact.callsign = str(
                    CoT.modelObject.detail.contact.callsign)
                proto_obj.contact.operation = 1
                proto_str = proto_obj.SerializeToString()
                header = self._generate_header(len(proto_str))
                for fed in self.federates.values():
                    fed.conn.send(header + proto_str)
                return None

            else:
                return None

        except Exception as e:
            logger.warning(
                "exception throw sending new connection data to federates " +
                str(e))
            return None

    def send_disconnection_data(self, CoT: SendDisconnect):
        if self.federates:
            proto_obj = FederatedEvent()
            proto_obj.contact.uid = str(CoT.modelObject.detail.link.uid)
            proto_obj.contact.callsign = str(CoT.modelObject.detail.link.type)
            proto_obj.contact.operation = 4
            proto_str = proto_obj.SerializeToString()
            header = self._generate_header(len(proto_str))
            for fed in self.federates.values():
                fed.conn.send(header + proto_str)
        else:
            return None

    def start(self, pipe):
        self.db = DatabaseController()
        self.pipe = pipe
        self._create_context()
        print('started federation federate service')
        self.main()

    def stop(self):
        pass