Пример #1
0
    def __init__(self, node):
        self.node = node
        self.version = "EC\x00\x01"

        self.remote_nodes = NodeStore()

        self._started = False
        self._running_transactions = {}

        self.on_query_sent = []
        self.on_query_received = []
        self.on_response_sent = []
        self.on_response_received = []

        # Init handlers
        handlers = [
            NodeStoreHandler, NodeInvalidater, PingHandler, FindNodeHandler,
            GetPeersHandler, AnnouncePeerHandler, MetaDataSpy]

        for handlerClass in handlers:
            handlerClass(self)
Пример #2
0
class DHTServer(object):

    def __init__(self, node):
        self.node = node
        self.version = "EC\x00\x01"

        self.remote_nodes = NodeStore()

        self._started = False
        self._running_transactions = {}

        self.on_query_sent = []
        self.on_query_received = []
        self.on_response_sent = []
        self.on_response_received = []

        # Init handlers
        handlers = [
            NodeStoreHandler, NodeInvalidater, PingHandler, FindNodeHandler,
            GetPeersHandler, AnnouncePeerHandler, MetaDataSpy]

        for handlerClass in handlers:
            handlerClass(self)

    def start(self):
        if self._started:
            raise Exception

        self._started = True
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._sock.bind(("0.0.0.0", self.node.dht_port)) # bind all adapters

        Thread(target=self._receiver).start()

    def _receiver(self):
        """
        Run in a different thread, and have as only goal to receive messages,
        parse them, and put them into a thread safe queue for further handling
        """
        while True:
            try:
                # Receive message
                raw_message, connect_info = self._sock.recvfrom(4096)
                message = bdecode(raw_message)
#                print "Received f " + str(connect_info) + ":\t" + str(message)

                # This is a query from another peer.
                if message['y'] == 'q':
                    # Retrieve or create source node.
                    id_26 = message['a']['id'] + socket.inet_aton(connect_info[0]) + struct.pack(r'!H', connect_info[1])
                    source_node = self.remote_nodes.get_node(id_26) or Node.from_id_26(id_26)

                    transaction = Transaction(query=message, query_node=source_node, response_node=self.node) # create transaction
                    self._running_transactions[transaction.id] = transaction # Add it to running transactions

                    for handler in self.on_query_received:
                        handler(transaction)  # Notify listeners

                elif message['y'] == 'e':
                    raise Exception

                # This is a response to a transaction we started.
                elif message['y'] == 'r':
                    transaction = self._running_transactions.pop(message["t"]) # pop transaction
                    transaction.response = message

                    for handler in self.on_response_received:
                        handler(transaction)  # Notify listeners

                else:
                    raise Exception

            except socket.timeout:
                pass
            except BTFailure:
                pass
            except:
                print traceback.format_exc()

    def send_ping_query(self, target_node):
        return self.send_query(Transaction(
            query_node=self.node,
            response_node=target_node,
            query={
                "y": "q",
                "t": urandom(2),
                "q": "ping",
                "a": {"id": self.node.id_20},
                "v": self.version
            }
        ))

    def send_find_node(self, target_node, target_id):
        return self.send_query(Transaction(
            query_node=self.node,
            response_node=target_node,
            query={
                "y": "q",
                "t": urandom(2),
                "q": "find_node",
                "a": {"id": self.node.id_20, "target": target_id},
                "v": self.version
            }
        ))

    def send_get_peers(self, target_node, info_hash):
        return self.send_query(Transaction(
            query_node=self.node,
            response_node=target_node,
            query={
                "y": "q",
                "t": urandom(2),
                "q": "get_peers",
                "a": {"id": self.node.id_20, "info_hash": info_hash},
                "v": self.version
            }
        ))

    def send_announce_peer(self, target_node, info_hash, token, port):
        return self.send_query(Transaction(
            query_node=self.node,
            response_node=target_node,
            query={
                "y": "q",
                "t": urandom(2),
                "q": "announce_peer",
                "a": {"id": self.node.id_20, "info_hash": info_hash, "token": token, "port": port},
                "v": self.version
            }
        ))

    def send_response(self, transaction):
#        print "sending to " + str(transaction.query_node.dht_connect_info) + ":\t" + str(transaction.response)
        del self._running_transactions[transaction.id]
        self._sock.sendto(
            bencode(transaction.response),
            transaction.query_node.dht_connect_info
        )

        for handler in self.on_response_sent:
            handler(transaction)

    def send_query(self, transaction):
#        print "sending to " + str(transaction.response_node.dht_connect_info) + ":\t" + str(transaction.query)
        self._running_transactions[transaction.id] = transaction
        self._sock.sendto(
            bencode(transaction.query),
            transaction.response_node.dht_connect_info
        )

        for handler in self.on_query_sent:
            handler(transaction)
        return transaction