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
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()
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),]
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)
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()
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))
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)
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()
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)