Пример #1
0
 def neighbours_within_distance(self, id, distance):
     """
     naive correct version simply compares all nodes
     """
     assert is_integer(id)
     nodes = list(n for n in self if n.id_distance(id) <= distance)
     return sorted(nodes, key=operator.methodcaller('id_distance', id))
Пример #2
0
 def recv_find_node(self, remote, targetid):
     # FIXME, amplification attack (need to ping pong ping pong first)
     assert isinstance(remote, Node)
     assert is_integer(targetid)
     self.update(remote)
     found = self.routing.neighbours(targetid)
     log.debug('recv find_node', remoteid=remote, found=len(found))
     self.wire.send_neighbours(remote, found)
Пример #3
0
 def find_node(self, targetid, via_node=None):
     # FIXME, amplification attack (need to ping pong ping pong first)
     assert is_integer(targetid)
     assert not via_node or isinstance(via_node, Node)
     self._find_requests[targetid] = time.time() + k_request_timeout
     if via_node:
         self.wire.send_find_node(via_node, targetid)
     else:
         self._query_neighbours(targetid)
Пример #4
0
 def __init__(self, ip, udp_port, tcp_port=0, from_binary=False):
     tcp_port = tcp_port or udp_port
     if from_binary:
         self.udp_port = dec_port(udp_port)
         self.tcp_port = dec_port(tcp_port)
     else:
         assert is_integer(udp_port)
         assert is_integer(tcp_port)
         self.udp_port = udp_port
         self.tcp_port = tcp_port
     try:
         # `ip` could be in binary or ascii format, independent of
         # from_binary's truthy. We use ad-hoc regexp to determine format
         _ip = str_to_bytes(ip)
         _ip = (bytes_to_str(ip) if PY3 else unicode(ip)) if ip_pattern.match(_ip) else _ip
         self._ip = ipaddress.ip_address(_ip)
     except ipaddress.AddressValueError as e:
         log.debug("failed to parse ip", error=e, ip=ip)
         raise e
Пример #5
0
 def neighbours(self, node, k=k_bucket_size):
     """
     sorting by bucket.midpoint does not work in edge cases
     build a short list of k * 2 nodes and sort and shorten it
     """
     assert isinstance(node, Node) or is_integer(node)
     if isinstance(node, Node):
         node = node.id
     nodes = []
     for bucket in self.buckets_by_id_distance(node):
         for n in bucket.nodes_by_id_distance(node):
             if n is not node:
                 nodes.append(n)
                 if len(nodes) == k * 2:
                     break
     return sorted(nodes, key=operator.methodcaller('id_distance',
                                                    node))[:k]
Пример #6
0
    def __init__(self,
                 protocol_id,
                 cmd_id,
                 payload,
                 sequence_id,
                 window_size,
                 is_chunked_n=False,
                 frames=None,
                 frame_cipher=None):
        payload = memoryview(payload)
        assert is_integer(window_size)
        assert window_size % self.padding == 0
        assert isinstance(cmd_id, int) and cmd_id < 256
        self.cmd_id = cmd_id
        self.payload = payload
        if frame_cipher:
            self.frame_cipher = frame_cipher
        self.frames = frames or []
        assert protocol_id < 2**16
        self.protocol_id = protocol_id
        assert sequence_id is None or sequence_id < 2**16
        self.sequence_id = sequence_id
        self.is_chunked_n = is_chunked_n
        self.frames.append(self)

        # chunk payloads resulting in frames exceeding window_size
        fs = self.frame_size()
        if fs > window_size:
            if not is_chunked_n:
                self.is_chunked_0 = True
                self.total_payload_size = self.body_size()
            # chunk payload
            self.payload = payload[:window_size - fs]
            assert self.frame_size() <= window_size
            remain = payload[len(self.payload):]
            assert len(remain) + len(self.payload) == len(payload)
            Frame(protocol_id,
                  cmd_id,
                  remain,
                  sequence_id,
                  window_size,
                  is_chunked_n=True,
                  frames=self.frames,
                  frame_cipher=frame_cipher)
        assert self.frame_size() <= window_size
Пример #7
0
    def __init__(self,
                 proto,
                 targetid,
                 via_node=None,
                 timeout=k_request_timeout,
                 callback=None):
        assert isinstance(proto, KademliaProtocol)
        assert is_integer(targetid)
        assert not via_node or isinstance(via_node, Node)
        self.proto = proto
        self.targetid = targetid
        self.via_node = via_node
        self.timeout = time.time() + timeout
        self.callback = callback

        if via_node:
            self.wire.send_find_node(via_node, targetid)
        else:
            self._query_neighbours(targetid)
Пример #8
0
    def send_find_node(self, node, target_node_id):
        """
        ### Find Node (type 0x03)

        Find Node packets are sent to locate nodes close to a given target ID.
        The receiver should reply with a Neighbors packet containing the `k`
        nodes closest to target that it knows about.

        FindNode packet-type: 0x03
        struct FindNode             <= 76 bytes
        {
            NodeId target; // Id of a node. The responding node will send back nodes closest to the target.
            unsigned expiration;
        };
        """
        assert is_integer(target_node_id)
        target_node_id = utils.int_to_big_endian(target_node_id).rjust(kademlia.k_pubkey_size // 8, b'\0')
        assert len(target_node_id) == kademlia.k_pubkey_size // 8
        log.debug('>>> find_node', remoteid=node)
        message = self.pack(self.cmd_id_map['find_node'], [target_node_id])
        self.send(node, message)
Пример #9
0
    def recv_neighbours(self, remote, neighbours):
        """
        if one of the neighbours is closer than the closest known neighbour
            if not timed out
                query closest node for neighbours
        add all nodes to the list
        """
        assert isinstance(neighbours, list)
        log.debug('recv neighbours',
                  remoteid=remote,
                  num=len(neighbours),
                  local=self.this_node,
                  neighbours=neighbours)
        neighbours = [n for n in neighbours if n != self.this_node]
        neighbours = [n for n in neighbours if n not in self.routing]

        # we don't map requests to responses, thus forwarding to all FIXME
        for nodeid, timeout in self._find_requests.items():
            assert is_integer(nodeid)
            closest = sorted(neighbours,
                             key=operator.methodcaller('id_distance', nodeid))
            if time.time() < timeout:
                closest_known = self.routing.neighbours(nodeid)
                closest_known = closest_known[0] if closest_known else None
                assert closest_known != self.this_node
                # send find_node requests to k_find_concurrency closests
                for close_node in closest[:k_find_concurrency]:
                    if not closest_known or \
                            close_node.id_distance(nodeid) < closest_known.id_distance(nodeid):
                        log.debug('forwarding find request',
                                  closest=close_node,
                                  closest_known=closest_known)
                        self.wire.send_find_node(close_node, nodeid)

        # add all nodes to the list
        for node in neighbours:
            if node != self.this_node:
                self.ping(node)
Пример #10
0
 def buckets_by_id_distance(self, id):
     assert is_integer(id)
     return sorted(self.buckets,
                   key=operator.methodcaller('id_distance', id))
Пример #11
0
 def __init__(self, counter=0, sender=''):
     assert is_integer(counter)
     assert isinstance(sender, bytes)
     super(Token, self).__init__(counter, sender)