Ejemplo n.º 1
0
    def read_response(self, stream: IngressStream):
        if (stream.read(2) != b"OK"):
            raise IOError("Peer returned bad response")

        size = struct.unpack("!I", stream.read(4))[0]
        data = stream.read(size)
        stream.close()
        return data
Ejemplo n.º 2
0
        def on_reply(stream: IngressStream):
            # Read number of capabilities
            capability_count = struct.unpack("!B", stream.read(1))[0]

            # Read the capabilities
            capabilities = [
                bytes([x]) for x in list(stream.read(capability_count))
            ]

            # Notify subscriber
            reply.on_next(capabilities)
            reply.on_completed()
Ejemplo n.º 3
0
        def read_response(stream: IngressStream):
            response = PathResponse.deserialise(stream)
            stream.close()

            # Prepend hop to respondant repeater
            # TODO these flags may need to be looked at some more or the 
            # PathNode object redesigned
            # HACK we should probably just get some sort of full representation
            # from the RPP repeater we ask the path from, but can't at the moment as we require peer info
            response.nodes.insert(0, PathNode.PathNode(stream.origin, PathNode.FLAGS_NONE, self.__muxer.get_peer_info(stream.origin)))

            # TODO generate many possible strategies
            return [PathStrategy(PathInfo([x.instance for x in response.nodes]), response.nodes[0].peer_info),]
Ejemplo n.º 4
0
    def handle_request(self, stream: IngressStream):
        # New connection, see what they want
        command = stream.read(4)
        print(command)

        if (command == Protocol.REQUEST_TRUST_SET):
            # Trust set requested, get the public key
            public_key = VerifyKey(stream.read(32))

            # Certificate requested, do we have it?
            if (self.store.has_trust_set(public_key)):
                # Yes, get ready to reply
                def established(egress: EgressStream):
                    # Get the trust set
                    trust_set = self.store.get_trust_set(public_key)

                    # Send the trust set
                    self.send_response(trust_set.serialise(), egress)

                # Reply to the request
                self.instance.establish_stream(
                    stream.origin,
                    in_reply_to=stream.id).subscribe(established)

        elif (command == Protocol.REQUEST_SIGNATURE):
            # Signature requested, get the public key
            public_key = VerifyKey(stream.read(32))

            # Get the message hash
            digest = stream.read(64)

            # Do we have the private key for this public key?
            if (self.store.has_signing_key(public_key)):
                # Yes, get ready to reply
                def established(egress: EgressStream):
                    # Get the signing key
                    signing_key = self.store.get_signing_key(public_key)

                    # Create the time signature
                    signature = TimeSignature.sign(digest, signing_key)

                    # Send the signature
                    self.send_response(signature.serialise(), egress)

                # Reply to the request
                self.instance.establish_stream(
                    stream.origin,
                    in_reply_to=stream.id).subscribe(established)
Ejemplo n.º 5
0
    def __rx_stream(self, stream: IngressStream):
        # Figure out what data follows
        following = stream.read(1)

        if (following == DATA_FOLLOWING_ANSWER
                and CAPABILITY_QUERY_ANSWER in self.__capabilities):
            self.__handle_answer(stream)

        elif (following == DATA_FOLLOWING_QUERY
              and CAPABILITY_QUERY_ANSWER in self.__capabilities):
            self.__handle_query(stream)

        elif (following == DATA_FOLLOWING_REQUEST):
            self.__handle_request(stream)

        else:
            stream.close()
Ejemplo n.º 6
0
    def __handle_request(self, stream: IngressStream):
        # Get the request type
        request_type = stream.read(1)

        # Is the request one of our capabilities?
        if (request_type != b"C" and request_type not in self.__capabilities):
            # Ignore
            return

        # Handler to reply to the request
        def handle_stream(es: EgressStream):
            if (request_type == REQUEST_CAPABILITIES):
                Log.debug("Received capabilities request")
                capabilities = struct.pack("!B", len(self.__capabilities))
                capabilities += b"".join(self.__capabilities)
                es.write(capabilities)
                es.close()

            elif (request_type == REQUEST_ADDRESS):
                Log.debug("Received address request")
                address = self.__muxer.get_peer_info(es.target)
                es.write(address.serialise())
                es.close()

            elif (request_type == REQUEST_PEERS):
                Log.debug("Received peers request")
                # Select up to 5 peers to reply with
                peers = [
                ]  #[x for x in random.sample(self.__default_group.instances, min(5, len(self.__reachable_peers))) if x in self.__peer_connection_methods]

                # Send the count
                es.write(struct.pack("!B", len(peers)))

                for peer in peers:
                    # Get the peer's connection methods
                    methods = self.__peer_connection_methods[peer]

                    # Create an instance information object
                    info = InstanceInformation(peer, methods)

                    # Write the object to the stream
                    es.write(info.serialise())

        # Get a reply stream
        self.__transport.initialise_stream(
            stream.origin, in_reply_to=stream.id).subscribe(handle_stream)

        # Have we encountered this peer before?
        if (stream.origin not in self.__discovered_peers):
            # No, add it
            self.__discovered_peers.add(stream.origin)

            # Ask for capabilities
            self.__request_capabilities(stream.origin).subscribe(
                lambda x: self.__rx_capabilities(x, stream.origin))
Ejemplo n.º 7
0
    def __new_stream(self, stream: IngressStream):
        # New command, what is it?
        command_type = stream.read(1)

        # Announce
        if(command_type == COMMAND_ANNOUNCE):
            # Read announcement
            announcement = Announcement.deserialise(stream)

            # Get peer info and network
            info = self.__muxer.get_peer_info(stream.origin)
            network = self.__muxer.get_peer_network(stream.origin)

            Log.debug("Peer announced itself with {} attached instance/s".format(len(announcement.instances)))

            # Update records
            for instance in announcement.instances:
                self.instance_info[instance] = info
                self.instance_network[instance] = network

            # Also add info for the RPP peer
            self.instance_info[stream.origin] = info
            self.instance_network[stream.origin] = network

        # Join
        elif(command_type == COMMAND_JOIN):
            Log.debug("Repeater peer joined")
            # Add as repeater peer
            self.__repeaters.add(stream.origin)

            # Save instance info for flag lookups
            self.instance_info[stream.origin] = self.__muxer.get_peer_info(stream.origin)
            self.instance_network[stream.origin] = self.__muxer.get_peer_network(stream.origin)

        # Find path
        elif(command_type == COMMAND_FIND_PATH):
            # Read the query
            query = PathQuery.deserialise(stream)

            # Is it an instance directly connected to us?
            if(query.target in self.instance_info):
                # Yes, get the flags
                flags = self.__get_instance_flags(stream.origin, query.target)

                Log.debug("Servicing query for path to an instance that is currently connected")

                self.__query_respond(stream.origin, stream.id, PathResponse([]))

            elif(query.ttl > 0):
                Log.debug("Forwarding query for path to instance")
                # Instance is not directly connected, forward query if still alive
                self.__forward_query(stream.origin, stream.id, query)
Ejemplo n.º 8
0
        def on_reply(stream: IngressStream):
            # Read number of peers
            peer_count = struct.unpack("!B", stream.read(1))[0]

            # List to hold info
            info = []

            # Read the peers (instance info)
            for i in range(peer_count):
                info.append(InstanceInformation.deserialise(stream))

            # Notify subscriber
            reply.on_next(info)
            reply.on_completed()
Ejemplo n.º 9
0
    def __init__(self,
                 target: InstanceReference,
                 features,
                 identifier: bytes,
                 ping: float,
                 ingress=False):
        # Instansiate class members
        self.ingress = ingress
        self.features: List[Feature] = [x() for x in features]
        self.identifier = identifier
        self.open = True
        self.target = target

        self.outgoing_segment_queue = queue.Queue()
        self.last_send = 0

        self.best_ping = ping
        self.worst_ping = ping
        self.window_size = METRIC_WINDOW_SIZE
        self.adjustment_delta = 0
        self.redundant_resends = 0

        self.segment_number = 0
        self.segment_lock = Lock()
        self.segment_queue = queue.Queue()
        self.in_flight = {}
        self.segment_trips = set()
        self.segment_trackers = {}

        self.reconstruction = {}
        self.next_expected_sequence_number = 0
        self.incoming_app_data = rx.subject.Subject()

        self.reply_subject = None
        self.closed = rx.subject.Subject()

        if (ingress):
            close_subject = rx.subject.Subject()
            close_subject.subscribe(None, None, self.__handle_app_close)
            self.stream = IngressStream(self.identifier, self.target,
                                        self.incoming_app_data, close_subject)
        else:
            self.reply_subject = rx.subject.Subject()
            self.stream = EgressStream(self.identifier, self.target,
                                       self.__handle_app_data,
                                       self.__handle_app_close,
                                       self.reply_subject)