diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 18606e74..a774a24b 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -15,7 +15,7 @@ import random import state import string import tr#anslate - +import helper_random # This thread exists because SQLITE3 is so un-threadsafe that we must # submit queries to it and it puts results back in a different queue. They # won't let us just use locks. @@ -263,7 +263,7 @@ class sqlThread(threading.Thread): if not BMConfigParser().has_option('bitmessagesettings', 'useidenticons'): BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True') if not BMConfigParser().has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt - BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons + BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(helper_random.randomchoice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12)))# a twelve character pseudo-password to salt the identicons #Add settings to support no longer resending messages after a certain period of time even if we never get an ack if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 7: diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index f8bc95a6..e644c0a4 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -14,6 +14,7 @@ from bmconfigparser import BMConfigParser from debug import logger import messagetypes from tr import _translate +import helper_random BITMESSAGE_ENCODING_IGNORE = 0 BITMESSAGE_ENCODING_TRIVIAL = 1 @@ -141,8 +142,8 @@ class MsgDecode(object): if __name__ == '__main__': import random messageData = { - "subject": ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(40)), - "body": ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10000)) + "subject": ''.join(helper_random.randomchoice(string.ascii_lowercase + string.digits) for _ in range(40)), + "body": ''.join(helper_random.randomchoice(string.ascii_lowercase + string.digits) for _ in range(10000)) } obj1 = MsgEncode(messageData, 1) obj2 = MsgEncode(messageData, 2) diff --git a/src/helper_random.py b/src/helper_random.py index c11ef695..56501871 100644 --- a/src/helper_random.py +++ b/src/helper_random.py @@ -11,14 +11,20 @@ def randomBytes(n): except NotImplementedError: return OpenSSL.rand(n) + def randomshuffle(population): """Method randomShuffle. shuffle the sequence x in place. shuffles the elements in list in place, so they are in a random order. + As Shuffle will alter data in-place, + so its input must be a mutable sequence. + In contrast, sample produces a new list + and its input can be much more varied + (tuple, string, xrange, bytearray, set, etc) """ - return random.shuffle(population) + random.shuffle(population) def randomsample(population, k): @@ -27,7 +33,8 @@ def randomsample(population, k): return a k length list of unique elements chosen from the population sequence. Used for random sampling - without replacement + without replacement, its called + partial shuffle. """ return random.sample(population, k) @@ -44,3 +51,13 @@ def randomrandrange(x, y=None): return random.randrange(x) else: return random.randrange(x, y) + + +def randomchoice(population): + """Method randomchoice. + + Return a random element from the non-empty + sequence seq. If seq is empty, raises + IndexError. + """ + return random.choice(population) diff --git a/src/helper_startup.py b/src/helper_startup.py index 6402ee89..c18c1a88 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -12,6 +12,7 @@ from distutils.version import StrictVersion from namecoin import ensureNamecoinOptions import paths import state +import helper_random storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-select Portable Mode in the settings if they want the config files to stay in the application data folder. @@ -103,7 +104,7 @@ def loadConfig(): BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') BMConfigParser().set('bitmessagesettings', 'userlocale', 'system') BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True') - BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons + BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(helper_random.randomchoice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12)))# a twelve character pseudo-password to salt the identicons BMConfigParser().set('bitmessagesettings', 'replybelow', 'False') BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index cd19063a..e50be61b 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -56,6 +56,7 @@ from threading import current_thread import warnings import os +import helper_random from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \ @@ -230,13 +231,13 @@ def select_poller(timeout=0.0, map=None): if err.args[0] in (WSAENOTSOCK, ): return - for fd in random.sample(r, len(r)): + for fd in helper_random.randomsample(r, len(r)): obj = map.get(fd) if obj is None: continue read(obj) - for fd in random.sample(w, len(w)): + for fd in helper_random.randomsample(w, len(w)): obj = map.get(fd) if obj is None: continue @@ -292,7 +293,7 @@ def poll_poller(timeout=0.0, map=None): except socket.error as err: if err.args[0] in (EBADF, WSAENOTSOCK, EINTR): return - for fd, flags in random.sample(r, len(r)): + for fd, flags in helper_random.randomsample(r, len(r)): obj = map.get(fd) if obj is None: continue @@ -349,7 +350,7 @@ def epoll_poller(timeout=0.0, map=None): if err.args[0] != EINTR: raise r = [] - for fd, flags in random.sample(r, len(r)): + for fd, flags in helper_random.randomsample(r, len(r)): obj = map.get(fd) if obj is None: continue @@ -403,7 +404,7 @@ def kqueue_poller(timeout=0.0, map=None): events = kqueue_poller.pollster.control(updates, selectables, timeout) if len(events) > 1: - events = random.sample(events, len(events)) + events = helper_random.randomsample(events, len(events)) for event in events: fd = event.ident diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 28277f52..a0267cad 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -23,6 +23,7 @@ from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue import shared import state import protocol +import helper_random class BMProtoError(ProxyError): errorCodes = ("Protocol error") @@ -278,7 +279,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): if time.time() < self.skipUntil: return True #TODO make this more asynchronous - random.shuffle(items) + helper_random.randomshuffle(items) for i in map(str, items): if Dandelion().hasHash(i) and \ self != Dandelion().objectChildStem(i): diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 819dfeb1..e29185e9 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -6,10 +6,11 @@ import knownnodes import protocol from queues import portCheckerQueue import state +import helper_random def getDiscoveredPeer(): try: - peer = random.choice(state.discoveredPeers.keys()) + peer = helper_random.randomchoice(state.discoveredPeers.keys()) except (IndexError, KeyError): raise ValueError try: @@ -29,11 +30,11 @@ def chooseConnection(stream): except Queue.Empty: pass # with a probability of 0.5, connect to a discovered peer - if random.choice((False, True)) and not haveOnion: + if helper_random.randomchoice((False, True)) and not haveOnion: # discovered peers are already filtered by allowed streams return getDiscoveredPeer() for _ in range(50): - peer = random.choice(knownnodes.knownNodes[stream].keys()) + peer = helper_random.randomchoice(knownnodes.knownNodes[stream].keys()) try: rating = knownnodes.knownNodes[stream][peer]["rating"] except TypeError: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 408d56e0..7854dec1 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -16,6 +16,7 @@ import network.asyncore_pollchoose as asyncore import protocol from singleton import Singleton import state +import helper_random @Singleton class BMConnectionPool(object): @@ -156,7 +157,7 @@ class BMConnectionPool(object): if established < BMConfigParser().safeGetInt("bitmessagesettings", "maxoutboundconnections"): for i in range(state.maximumNumberOfHalfOpenConnections - pending): try: - chosen = chooseConnection(random.choice(self.streams)) + chosen = chooseConnection(helper_random.randomchoice(self.streams)) except ValueError: continue if chosen in self.outboundConnections: diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 7eee2761..cd4b8018 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -10,6 +10,7 @@ from inventory import Inventory from network.connectionpool import BMConnectionPool import protocol from state import missingObjects +import helper_random class DownloadThread(threading.Thread, StoppableThread): minPending = 200 @@ -41,7 +42,7 @@ class DownloadThread(threading.Thread, StoppableThread): requested = 0 # Choose downloading peers randomly connections = [x for x in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() if x.fullyEstablished] - random.shuffle(connections) + helper_random.randomshuffle(connections) try: requestChunk = max(int(min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) except ZeroDivisionError: diff --git a/src/network/tcp.py b/src/network/tcp.py index 33c4b6ca..f0bfb886 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -12,6 +12,7 @@ import traceback from addresses import calculateInventoryHash from debug import logger from helper_random import randomBytes +import helper_random from inventory import Inventory import knownnodes from network.advanceddispatcher import AdvancedDispatcher @@ -132,7 +133,7 @@ class TCPConnection(BMProto, TLSDispatcher): if elemCount > maxAddrCount: elemCount = maxAddrCount # only if more recent than 3 hours - addrs[stream] = random.sample(filtered.items(), elemCount) + addrs[stream] = helper_random.randomsample(filtered.items(), elemCount) # sent 250 only if the remote isn't interested in it if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streams: filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() @@ -140,14 +141,14 @@ class TCPConnection(BMProto, TLSDispatcher): elemCount = len(filtered) if elemCount > maxAddrCount / 2: elemCount = int(maxAddrCount / 2) - addrs[stream * 2] = random.sample(filtered.items(), elemCount) + addrs[stream * 2] = helper_random.randomsample(filtered.items(), elemCount) if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streams: filtered = {k: v for k, v in knownnodes.knownNodes[stream*2+1].items() if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > maxAddrCount / 2: elemCount = int(maxAddrCount / 2) - addrs[stream * 2 + 1] = random.sample(filtered.items(), elemCount) + addrs[stream * 2 + 1] = helper_random.randomsample(filtered.items(), elemCount) for substream in addrs.keys(): for peer, params in addrs[substream]: templist.append((substream, peer, params["lastseen"])) diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py index 83d35cdf..ef5e6206 100644 --- a/src/randomtrackingdict.py +++ b/src/randomtrackingdict.py @@ -1,6 +1,7 @@ import random from threading import RLock from time import time +import helper_random class RandomTrackingDict(object): maxPending = 10 @@ -82,7 +83,7 @@ class RandomTrackingDict(object): available = self.len - self.pendingLen if count > available: count = available - randomIndex = random.sample(range(self.len - self.pendingLen), count) + randomIndex = helper_random.randomsample(range(self.len - self.pendingLen), count) retval = [self.indexDict[i] for i in randomIndex] for i in sorted(randomIndex, reverse=True):