From 1b16c809fd318e22980915a5a86a921ad69be10e Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Fri, 31 Aug 2018 17:53:48 -0500 Subject: [PATCH] work on user connections --- onionr/communicator2.py | 23 +++++++++++++++++++---- onionr/onionrdaemontools.py | 35 +++++++++++++++++++++++++++++++++-- onionr/onionrpeers.py | 4 +++- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/onionr/communicator2.py b/onionr/communicator2.py index 168499ee..2b8667be 100755 --- a/onionr/communicator2.py +++ b/onionr/communicator2.py @@ -51,6 +51,8 @@ class OnionrCommunicatorDaemon: # lists of connected peers and peers we know we can't reach currently self.onlinePeers = [] self.offlinePeers = [] + self.cooldownPeer = {} + self.connectTimes = {} self.peerProfiles = [] # list of peer's profiles (onionrpeers.PeerProfile instances) # amount of threads running by name, used to prevent too many @@ -84,13 +86,14 @@ class OnionrCommunicatorDaemon: # requiresPeer True means the timer function won't fire if we have no connected peers OnionrCommunicatorTimers(self, self.daemonCommands, 5) OnionrCommunicatorTimers(self, self.detectAPICrash, 5) - peerPoolTimer = OnionrCommunicatorTimers(self, self.getOnlinePeers, 60) + peerPoolTimer = OnionrCommunicatorTimers(self, self.getOnlinePeers, 60, maxThreads=1) OnionrCommunicatorTimers(self, self.lookupBlocks, self._core.config.get('timers.lookupBlocks'), requiresPeer=True, maxThreads=1) OnionrCommunicatorTimers(self, self.getBlocks, self._core.config.get('timers.getBlocks'), requiresPeer=True) OnionrCommunicatorTimers(self, self.clearOfflinePeer, 58) OnionrCommunicatorTimers(self, self.daemonTools.cleanOldBlocks, 65) OnionrCommunicatorTimers(self, self.lookupKeys, 60, requiresPeer=True) OnionrCommunicatorTimers(self, self.lookupAdders, 60, requiresPeer=True) + OnionrCommunicatorTimers(self, self.daemonTools.cooldownPeer, 30, requiresPeer=True) netCheckTimer = OnionrCommunicatorTimers(self, self.daemonTools.netCheck, 600) announceTimer = OnionrCommunicatorTimers(self, self.daemonTools.announceNode, 305, requiresPeer=True, maxThreads=1) cleanupTimer = OnionrCommunicatorTimers(self, self.peerCleanup, 300, requiresPeer=True) @@ -295,7 +298,7 @@ class OnionrCommunicatorDaemon: '''Manages the self.onlinePeers attribute list, connects to more peers if we have none connected''' logger.info('Refreshing peer pool.') - maxPeers = config.get('peers.maxConnect') + maxPeers = int(config.get('peers.maxConnect')) needed = maxPeers - len(self.onlinePeers) for i in range(needed): @@ -338,7 +341,7 @@ class OnionrCommunicatorDaemon: for address in peerList: if not config.get('tor.v3onions') and len(address) == 62: continue - if len(address) == 0 or address in tried or address in self.onlinePeers: + if len(address) == 0 or address in tried or address in self.onlinePeers or address in self.cooldownPeer: continue if self.shutdown: return @@ -347,6 +350,7 @@ class OnionrCommunicatorDaemon: time.sleep(0.1) if address not in self.onlinePeers: self.onlinePeers.append(address) + self.connectTimes[address] = self._core._utils.getEpoch() retData = address # add peer to profile list if they're not in it @@ -361,6 +365,17 @@ class OnionrCommunicatorDaemon: logger.debug('Failed to connect to ' + address) return retData + def removeOnlinePeer(self, peer): + '''Remove an online peer''' + try: + del self.connectTimes[peer] + except KeyError: + pass + try: + self.onlinePeers.remove(peer) + except ValueError: + pass + def peerCleanup(self): '''This just calls onionrpeers.cleanupPeers, which removes dead or bad peers (offline too long, too slow)''' onionrpeers.peerCleanup(self._core) @@ -392,7 +407,7 @@ class OnionrCommunicatorDaemon: if retData == False: try: self.getPeerProfileInstance(peer).addScore(-10) - self.onlinePeers.remove(peer) + self.removeOnlinePeer(peer) self.getOnlinePeers() # Will only add a new peer to pool if needed except ValueError: pass diff --git a/onionr/onionrdaemontools.py b/onionr/onionrdaemontools.py index 7c6fc62e..bc3e7d9e 100644 --- a/onionr/onionrdaemontools.py +++ b/onionr/onionrdaemontools.py @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import onionrexceptions, onionrpeers, onionrproofs, base64, logger +import onionrexceptions, onionrpeers, onionrproofs, base64, logger, secrets class DaemonTools: def __init__(self, daemon): self.daemon = daemon @@ -70,4 +70,35 @@ class DaemonTools: self.daemon._core._blacklist.addToDB(oldest) self.daemon._core.removeBlock(oldest) logger.info('Deleted block: %s' % (oldest,)) - self.daemon.decrementThreadCount('cleanOldBlocks') \ No newline at end of file + self.daemon.decrementThreadCount('cleanOldBlocks') + + def cooldownPeer(self): + '''Randomly add an online peer to cooldown, so we can connect a new one''' + onlinePeerAmount = len(self.daemon.onlinePeers) + minTime = 300 + cooldownTime = 600 + toCool = '' + tempConnectTimes = dict(self.daemon.connectTimes) + + # Remove peers from cooldown that have been there long enough + tempCooldown = dict(self.daemon.cooldownPeer) + for peer in tempCooldown: + if (self.daemon._core._utils.getEpoch() - tempCooldown[peer]) >= cooldownTime: + del self.daemon.cooldownPeer[peer] + + # Cool down a peer, if we have max connections alive for long enough + if onlinePeerAmount >= self.daemon._core.config.get('peers.maxConnect'): + finding = True + while finding: + try: + toCool = min(tempConnectTimes, key=tempConnectTimes.get) + if (self.daemon._core._utils.getEpoch() - tempConnectTimes[toCool]) < minTime: + del tempConnectTimes[toCool] + else: + finding = False + except ValueError: + break + else: + self.daemon.removeOnlinePeer(toCool) + self.daemon.cooldownPeer[toCool] = self.daemon._core._utils.getEpoch() + self.daemon.decrementThreadCount('cooldownPeer') \ No newline at end of file diff --git a/onionr/onionrpeers.py b/onionr/onionrpeers.py index 041a69b9..322db9ba 100644 --- a/onionr/onionrpeers.py +++ b/onionr/onionrpeers.py @@ -90,13 +90,15 @@ def peerCleanup(coreInst): if PeerProfiles(address, coreInst).score < minScore: coreInst.removeAddress(address) try: - if (coreInst._utils.getEpoch() - coreInst.getPeerInfo(address, 'dateSeen')) >= 600: + if (int(coreInst._utils.getEpoch()) - int(coreInst.getPeerInfo(address, 'dateSeen'))) >= 600: expireTime = 600 else: expireTime = 86400 coreInst._blacklist.addToDB(address, dataType=1, expire=expireTime) except sqlite3.IntegrityError: #TODO just make sure its not a unique constraint issue pass + except ValueError: + pass logger.warn('Removed address ' + address + '.') # Unban probably not malicious peers TODO improve