Onionr/onionr/onionrdaemontools.py

167 lines
6.0 KiB
Python
Raw Normal View History

'''
Onionr - P2P Anonymous Storage Network
Contains the CommunicatorUtils class which contains useful functions for the communicator daemon
'''
'''
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
2018-11-17 07:23:10 +00:00
import onionrexceptions, onionrpeers, onionrproofs, logger, onionrusers
import base64, sqlite3, os
2018-09-01 00:51:14 +00:00
from dependencies import secrets
class DaemonTools:
def __init__(self, daemon):
self.daemon = daemon
self.announceCache = {}
def announceNode(self):
'''Announce our node to our peers'''
retData = False
# Announce to random online peers
for i in self.daemon.onlinePeers:
if not i in self.announceCache:
peer = i
break
else:
peer = self.daemon.pickOnlinePeer()
ourID = self.daemon._core.hsAddress.strip()
url = 'http://' + peer + '/public/announce/'
data = {'node': ourID}
combinedNodes = ourID + peer
if peer in self.announceCache:
data['random'] = self.announceCache[peer]
else:
proof = onionrproofs.DataPOW(combinedNodes, forceDifficulty=4)
data['random'] = base64.b64encode(proof.waitForResult()[1])
self.announceCache[peer] = data['random']
logger.info('Announcing node to ' + url)
if self.daemon._core._utils.doPostRequest(url, data) == 'Success':
logger.info('Successfully introduced node to ' + peer)
retData = True
self.daemon.decrementThreadCount('announceNode')
2018-08-21 20:01:50 +00:00
return retData
def netCheck(self):
'''Check if we are connected to the internet or not when we can't connect to any peers'''
2018-11-09 05:22:43 +00:00
if len(self.daemon.onlinePeers) == 0:
2018-08-23 19:46:23 +00:00
if not self.daemon._core._utils.checkNetwork(torPort=self.daemon.proxyPort):
2018-08-21 20:01:50 +00:00
logger.warn('Network check failed, are you connected to the internet?')
self.daemon.isOnline = False
self.daemon.decrementThreadCount('netCheck')
2018-09-24 23:48:00 +00:00
def cleanOldBlocks(self):
2018-09-30 04:42:31 +00:00
'''Delete old blocks if our disk allocation is full/near full, and also expired blocks'''
while self.daemon._core._utils.storageCounter.isFull():
oldest = self.daemon._core.getBlockList()[0]
self.daemon._core._blacklist.addToDB(oldest)
self.daemon._core.removeBlock(oldest)
2018-09-24 23:48:00 +00:00
logger.info('Deleted block: %s' % (oldest,))
2018-09-30 04:42:31 +00:00
# Delete expired blocks
for bHash in self.daemon._core.getExpiredBlocks():
self.daemon._core._blacklist.addToDB(bHash)
self.daemon._core.removeBlock(bHash)
2018-08-31 22:53:48 +00:00
self.daemon.decrementThreadCount('cleanOldBlocks')
2018-11-09 19:07:26 +00:00
def cleanKeys(self):
'''Delete expired forward secrecy keys'''
conn = sqlite3.connect(self.daemon._core.peerDB, timeout=10)
c = conn.cursor()
time = self.daemon._core._utils.getEpoch()
deleteKeys = []
2018-11-17 07:23:10 +00:00
for entry in c.execute("SELECT * FROM forwardKeys WHERE expire <= ?", (time,)):
2018-11-09 19:07:26 +00:00
logger.info(entry[1])
deleteKeys.append(entry[1])
2018-11-09 19:07:26 +00:00
for key in deleteKeys:
logger.info('Deleting forward key '+ key)
c.execute("DELETE from forwardKeys where forwardKey = ?", (key,))
conn.commit()
conn.close()
onionrusers.deleteExpiredKeys(self.daemon._core)
self.daemon.decrementThreadCount('cleanKeys')
2018-08-31 22:53:48 +00:00
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
2018-09-24 23:48:00 +00:00
if onlinePeerAmount >= self.daemon._core.config.get('peers.max_connect', 10):
2018-08-31 22:53:48 +00:00
finding = True
2018-11-17 07:23:10 +00:00
2018-08-31 22:53:48 +00:00
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()
2018-11-17 07:23:10 +00:00
2018-09-24 23:48:00 +00:00
self.daemon.decrementThreadCount('cooldownPeer')
def runCheck(self):
if os.path.isfile('data/.runcheck'):
os.remove('data/.runcheck')
return True
return False
def humanReadableTime(self, seconds):
build = ''
units = {
'year' : 31557600,
'month' : (31557600 / 12),
'day' : 86400,
'hour' : 3600,
'minute' : 60,
'second' : 1
}
for unit in units:
amnt_unit = int(seconds / units[unit])
if amnt_unit >= 1:
seconds -= amnt_unit * units[unit]
build += '%s %s' % (amnt_unit, unit) + ('s' if amnt_unit != 1 else '') + ' '
return build.strip()