Пример #1
0
class hostbroker(Handler, DatagramProtocol):
    def __init__(self, server, addr, call_later):
        self.server = server
        self.addr = addr
        self.call_later = call_later

    def actually_start(self, transport, max_ul_rate, config, rlcount):
        self.transport = transport
        self.rltransport = KRateLimiter(transport, max_ul_rate,
                                        self.call_later, rlcount,
                                        config['max_rate_period'])
        self.connections = Cache(touch_on_access=True)
        self.hammerlock = Hammerlock(100, self.call_later)
        self.expire_connections(loop=True)
        self.config = config
        if not self.config.has_key('pause'):
            self.config['pause'] = False

    def expire_connections(self, loop=False):
        self.connections.expire(bttime() - KRPC_CONNECTION_CACHE_TIME)
        if loop:
            self.call_later(KRPC_CONNECTION_CACHE_TIME,
                            self.expire_connections, True)

    def datagramReceived(self, datagram, addr):
        self.data_came_in(addr, datagram)

    def data_came_in(self, addr, datagram):
        #if addr != self.addr:
        if not self.config['pause'] and self.hammerlock.check(addr):
            c = self.connectionForAddr(addr)
            c.datagramReceived(datagram, addr)

    def connection_lost(self, socket):
        ## this is like, bad
        print ">>> connection lost!", socket

    def connectionForAddr(self, addr):
        if addr == self.addr:
            raise KRPCSelfNodeError()
        if not self.connections.has_key(addr):
            conn = KRPC(addr, self.server, self.transport, self.rltransport,
                        self.call_later)
            self.connections[addr] = conn
        else:
            conn = self.connections[addr]
        return conn
Пример #2
0
class hostbroker(Handler, DatagramProtocol):       
    def __init__(self, server, addr, call_later):
        self.server = server
        self.addr = addr
        self.call_later = call_later
        
    def actually_start(self, transport, max_ul_rate, config, rlcount):
        self.transport = transport
        self.rltransport = KRateLimiter(transport, max_ul_rate, self.call_later, rlcount, config['max_rate_period'])
        self.connections = Cache(touch_on_access=True)
        self.hammerlock = Hammerlock(100, self.call_later)
        self.expire_connections(loop=True)
        self.config = config
        if not self.config.has_key('pause'):
            self.config['pause'] = False
        
    def expire_connections(self, loop=False):
        self.connections.expire(bttime() - KRPC_CONNECTION_CACHE_TIME)
        if loop:
            self.call_later(KRPC_CONNECTION_CACHE_TIME, self.expire_connections, True)

    def datagramReceived(self, datagram, addr):
      self.data_came_in(addr, datagram)
      
    def data_came_in(self, addr, datagram):
        #if addr != self.addr:
        if not self.config['pause'] and self.hammerlock.check(addr):
            c = self.connectionForAddr(addr)
            c.datagramReceived(datagram, addr)

    def connection_lost(self, socket):
        ## this is like, bad
        print ">>> connection lost!", socket

    def connectionForAddr(self, addr):
        if addr == self.addr:
            raise KRPCSelfNodeError()
        if not self.connections.has_key(addr):
            conn = KRPC(addr, self.server, self.transport, self.rltransport, self.call_later)
            self.connections[addr] = conn
        else:
            conn = self.connections[addr]
        return conn
Пример #3
0
class UTKhashmir(khashmir.KhashmirBase):
    _Node = UTNode

    def setup(self, host, port, data_dir, rlcount, checkpoint=True):
        khashmir.KhashmirBase.setup(self, host, port, data_dir, rlcount, checkpoint)
        self.cur_token = self.last_token = sha('')
        self.tcache = Cache()
        self.gen_token(loop=True)
        self.expire_cached_tokens(loop=True)
        
    def expire_cached_tokens(self, loop=False):
        self.tcache.expire(time() - TOKEN_UPDATE_INTERVAL)
        if loop:
            self.add_task(TOKEN_UPDATE_INTERVAL,
                                             self.expire_cached_tokens, True)
                                
    def gen_token(self, loop=False):
        self.last_token = self.cur_token
        self.cur_token = sha(newID())
        if loop:
            self.add_task(TOKEN_UPDATE_INTERVAL,
                                             self.gen_token, True)

    def get_token(self, host, port):
        x = self.cur_token.copy()
        x.update("%s%s" % (host, port))
        h = x.digest()
        return h

        
    def val_token(self, token, host, port):
        x = self.cur_token.copy()
        x.update("%s%s" % (host, port))
        a = x.digest()
        if token == a:
            return True

        x = self.last_token.copy()
        x.update("%s%s" % (host, port))
        b = x.digest()
        if token == b:
            return True

        return False

    def add_contact(self, host, port, callback=None):
      if khashmir.ip_pat.match(host):
        self._got_host(host, port, callback)
      else:
        d = getHostByName(host)
        d.addCallback(self._got_host, port, callback)
        d.addErrback(log_ex, "failed to lookup address for host=%s" % (host))

    def _got_host(self, host, port, callback):
        khashmir.KhashmirBase.add_contact(self, host, port, callback)

    def announce_peer(self, info_hash, port, callback=None):
        """ stores the value for key in the global table, returns immediately, no status 
            in this implementation, peers respond but don't indicate status to storing values
            a key can have many values
        """
        def _storeValueForKey(nodes, key=info_hash, value=port, response=callback , table=self.table):
            if not response:
                # default callback
                def _storedValueHandler(sender):
                    pass
                response=_storedValueHandler
            action = UTStoreValue(self, key, value, response, self.add_task, "announce_peer")
            self.add_task(0, action.goWithNodes, nodes)
            
        # this call is asynch
        self.findNode(info_hash, _storeValueForKey)
                    
    def krpc_announce_peer(self, info_hash, port, id, token, _krpc_sender):
        sender = {'id' : id}
        sender['host'] = _krpc_sender[0]
        sender['port'] = _krpc_sender[1]
        if not self.val_token(token, sender['host'], sender['port']):
            raise KRPCProtocolError("Invalid Write Token")
        value = compact_peer_info(_krpc_sender[0], port)
        self.store[info_hash] = value
        n = self.Node().initWithDict(sender)
        self.insertNode(n, contacted=0)
        return {"id" : self.node.id}

    def retrieve_values(self, key):
        try:
            l = self.store.sample(key, NUM_PEERS)
        except KeyError:
            l = []
        return l

    def get_peers(self, info_hash, callback, searchlocal = 1):
        """ returns the values found for key in global table
            callback will be called with a list of values for each peer that returns unique values
            final callback will be an empty list - probably should change to 'more coming' arg
        """
        nodes = self.table.findNodes(info_hash, invalid=True)
        l = [x for x in nodes if x.invalid]
        if len(l) > 4:
            nodes = sample(l , 4) + self.table.findNodes(info_hash, invalid=False)[:4]
        
        # get locals
        if searchlocal:
            l = self.retrieve_values(info_hash)
            if len(l) > 0:
                self.add_task(0, callback, [reducePeers(l)])
        else:
            l = []
        # create our search state
        state = GetValue(self, info_hash, callback, self.add_task, 'get_peers')
        self.add_task(0, state.goWithNodes, nodes, l)

    def get_peers_and_announce(self, info_hash, port, callback, searchlocal = 1):
        """ returns the values found for key in global table
            callback will be called with a list of values for each peer that returns unique values
            final callback will be an empty list - probably should change to 'more coming' arg
        """
        nodes = self.table.findNodes(info_hash, invalid=False)
        nodes += self.table.findNodes(info_hash, invalid=True)
        
        # get locals
        if searchlocal:
            l = self.retrieve_values(info_hash)
            if len(l) > 0:
                self.add_task(0, callback, [reducePeers(l)])
        else:
            l = []
        # create our search state
        x = lambda a: a
        state = GetAndStore(self, info_hash, port, callback, x, self.add_task, 'get_peers', "announce_peer")
        self.add_task(0, state.goWithNodes, nodes, l)

    def krpc_get_peers(self, info_hash, id, _krpc_sender):
        sender = {'id' : id}
        sender['host'] = _krpc_sender[0]
        sender['port'] = _krpc_sender[1]        
        n = self.Node().initWithDict(sender)
        self.insertNode(n, contacted=0)
    
        l = self.retrieve_values(info_hash)
        if len(l) > 0:
            return {'values' : [reducePeers(l)],
                    "id": self.node.id,
                    "token" : self.get_token(sender['host'], sender['port'])}
        else:
            nodes = self.table.findNodes(info_hash, invalid=False)
            nodes = [node.senderDict() for node in nodes]
            return {'nodes' : packNodes(nodes),
                    "id": self.node.id,
                    "token" : self.get_token(sender['host'], sender['port'])}
Пример #4
0
class UTKhashmir(khashmir.KhashmirBase):
    _Node = UTNode

    def setup(self, host, port, data_dir, rlcount, checkpoint=True):
        khashmir.KhashmirBase.setup(self, host, port, data_dir, rlcount,
                                    checkpoint)
        self.cur_token = self.last_token = sha('')
        self.tcache = Cache()
        self.gen_token(loop=True)
        self.expire_cached_tokens(loop=True)

    def expire_cached_tokens(self, loop=False):
        self.tcache.expire(time() - TOKEN_UPDATE_INTERVAL)
        if loop:
            self.add_task(TOKEN_UPDATE_INTERVAL, self.expire_cached_tokens,
                          True)

    def gen_token(self, loop=False):
        self.last_token = self.cur_token
        self.cur_token = sha(newID())
        if loop:
            self.add_task(TOKEN_UPDATE_INTERVAL, self.gen_token, True)

    def get_token(self, host, port):
        x = self.cur_token.copy()
        x.update("%s%s" % (host, port))
        h = x.digest()
        return h

    def val_token(self, token, host, port):
        x = self.cur_token.copy()
        x.update("%s%s" % (host, port))
        a = x.digest()
        if token == a:
            return True

        x = self.last_token.copy()
        x.update("%s%s" % (host, port))
        b = x.digest()
        if token == b:
            return True

        return False

    def add_contact(self, host, port, callback=None):
        if khashmir.ip_pat.match(host):
            self._got_host(host, port, callback)
        else:
            d = getHostByName(host)
            d.addCallback(self._got_host, port, callback)
            d.addErrback(log_ex,
                         "failed to lookup address for host=%s" % (host))

    def _got_host(self, host, port, callback):
        khashmir.KhashmirBase.add_contact(self, host, port, callback)

    def announce_peer(self, info_hash, port, callback=None):
        """ stores the value for key in the global table, returns immediately, no status 
            in this implementation, peers respond but don't indicate status to storing values
            a key can have many values
        """
        def _storeValueForKey(nodes,
                              key=info_hash,
                              value=port,
                              response=callback,
                              table=self.table):
            if not response:
                # default callback
                def _storedValueHandler(sender):
                    pass

                response = _storedValueHandler
            action = UTStoreValue(self, key, value, response, self.add_task,
                                  "announce_peer")
            self.add_task(0, action.goWithNodes, nodes)

        # this call is asynch
        self.findNode(info_hash, _storeValueForKey)

    def krpc_announce_peer(self, info_hash, port, id, token, _krpc_sender):
        sender = {'id': id}
        sender['host'] = _krpc_sender[0]
        sender['port'] = _krpc_sender[1]
        if not self.val_token(token, sender['host'], sender['port']):
            raise KRPCProtocolError("Invalid Write Token")
        value = compact_peer_info(_krpc_sender[0], port)
        self.store[info_hash] = value
        n = self.Node().initWithDict(sender)
        self.insertNode(n, contacted=0)
        return {"id": self.node.id}

    def retrieve_values(self, key):
        try:
            l = self.store.sample(key, NUM_PEERS)
        except KeyError:
            l = []
        return l

    def get_peers(self, info_hash, callback, searchlocal=1):
        """ returns the values found for key in global table
            callback will be called with a list of values for each peer that returns unique values
            final callback will be an empty list - probably should change to 'more coming' arg
        """
        nodes = self.table.findNodes(info_hash, invalid=True)
        l = [x for x in nodes if x.invalid]
        if len(l) > 4:
            nodes = sample(l, 4) + self.table.findNodes(info_hash,
                                                        invalid=False)[:4]

        # get locals
        if searchlocal:
            l = self.retrieve_values(info_hash)
            if len(l) > 0:
                self.add_task(0, callback, [reducePeers(l)])
        else:
            l = []
        # create our search state
        state = GetValue(self, info_hash, callback, self.add_task, 'get_peers')
        self.add_task(0, state.goWithNodes, nodes, l)

    def get_peers_and_announce(self, info_hash, port, callback, searchlocal=1):
        """ returns the values found for key in global table
            callback will be called with a list of values for each peer that returns unique values
            final callback will be an empty list - probably should change to 'more coming' arg
        """
        nodes = self.table.findNodes(info_hash, invalid=False)
        nodes += self.table.findNodes(info_hash, invalid=True)

        # get locals
        if searchlocal:
            l = self.retrieve_values(info_hash)
            if len(l) > 0:
                self.add_task(0, callback, [reducePeers(l)])
        else:
            l = []
        # create our search state
        x = lambda a: a
        state = GetAndStore(self, info_hash, port, callback, x, self.add_task,
                            'get_peers', "announce_peer")
        self.add_task(0, state.goWithNodes, nodes, l)

    def krpc_get_peers(self, info_hash, id, _krpc_sender):
        sender = {'id': id}
        sender['host'] = _krpc_sender[0]
        sender['port'] = _krpc_sender[1]
        n = self.Node().initWithDict(sender)
        self.insertNode(n, contacted=0)

        l = self.retrieve_values(info_hash)
        if len(l) > 0:
            return {
                'values': [reducePeers(l)],
                "id": self.node.id,
                "token": self.get_token(sender['host'], sender['port'])
            }
        else:
            nodes = self.table.findNodes(info_hash, invalid=False)
            nodes = [node.senderDict() for node in nodes]
            return {
                'nodes': packNodes(nodes),
                "id": self.node.id,
                "token": self.get_token(sender['host'], sender['port'])
            }