Docstrings in network from #1401
This commit is contained in:
parent
19ab56a979
commit
2998599442
|
@ -23,6 +23,7 @@ Stem = namedtuple('Stem', ['child', 'stream', 'timeout'])
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class Dandelion():
|
class Dandelion():
|
||||||
|
"""Dandelion class for tracking stem/fluff stages."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# currently assignable child stems
|
# currently assignable child stems
|
||||||
self.stem = []
|
self.stem = []
|
||||||
|
@ -35,6 +36,7 @@ class Dandelion():
|
||||||
self.lock = RLock()
|
self.lock = RLock()
|
||||||
|
|
||||||
def poissonTimeout(self, start=None, average=0):
|
def poissonTimeout(self, start=None, average=0):
|
||||||
|
"""Generate deadline using Poisson distribution"""
|
||||||
if start is None:
|
if start is None:
|
||||||
start = time()
|
start = time()
|
||||||
if average == 0:
|
if average == 0:
|
||||||
|
@ -42,6 +44,7 @@ class Dandelion():
|
||||||
return start + expovariate(1.0 / average) + FLUFF_TRIGGER_FIXED_DELAY
|
return start + expovariate(1.0 / average) + FLUFF_TRIGGER_FIXED_DELAY
|
||||||
|
|
||||||
def addHash(self, hashId, source=None, stream=1):
|
def addHash(self, hashId, source=None, stream=1):
|
||||||
|
"""Add inventory vector to dandelion stem"""
|
||||||
if not state.dandelion:
|
if not state.dandelion:
|
||||||
return
|
return
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
@ -51,6 +54,10 @@ class Dandelion():
|
||||||
self.poissonTimeout())
|
self.poissonTimeout())
|
||||||
|
|
||||||
def setHashStream(self, hashId, stream=1):
|
def setHashStream(self, hashId, stream=1):
|
||||||
|
"""
|
||||||
|
Update stream for inventory vector (as inv/dinv commands don't
|
||||||
|
include streams, we only learn this after receiving the object)
|
||||||
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if hashId in self.hashMap:
|
if hashId in self.hashMap:
|
||||||
self.hashMap[hashId] = Stem(
|
self.hashMap[hashId] = Stem(
|
||||||
|
@ -59,6 +66,7 @@ class Dandelion():
|
||||||
self.poissonTimeout())
|
self.poissonTimeout())
|
||||||
|
|
||||||
def removeHash(self, hashId, reason="no reason specified"):
|
def removeHash(self, hashId, reason="no reason specified"):
|
||||||
|
"""Switch inventory vector from stem to fluff mode"""
|
||||||
logging.debug(
|
logging.debug(
|
||||||
"%s entering fluff mode due to %s.",
|
"%s entering fluff mode due to %s.",
|
||||||
''.join('%02x' % ord(i) for i in hashId), reason)
|
''.join('%02x' % ord(i) for i in hashId), reason)
|
||||||
|
@ -69,12 +77,19 @@ class Dandelion():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def hasHash(self, hashId):
|
def hasHash(self, hashId):
|
||||||
|
"""Is inventory vector in stem mode?"""
|
||||||
return hashId in self.hashMap
|
return hashId in self.hashMap
|
||||||
|
|
||||||
def objectChildStem(self, hashId):
|
def objectChildStem(self, hashId):
|
||||||
|
"""Child (i.e. next) node for an inventory vector during stem mode"""
|
||||||
return self.hashMap[hashId].child
|
return self.hashMap[hashId].child
|
||||||
|
|
||||||
def maybeAddStem(self, connection):
|
def maybeAddStem(self, connection):
|
||||||
|
"""
|
||||||
|
If we had too few outbound connections, add the current one to the
|
||||||
|
current stem list. Dandelion as designed by the authors should
|
||||||
|
always have two active stem child connections.
|
||||||
|
"""
|
||||||
# fewer than MAX_STEMS outbound connections at last reshuffle?
|
# fewer than MAX_STEMS outbound connections at last reshuffle?
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if len(self.stem) < MAX_STEMS:
|
if len(self.stem) < MAX_STEMS:
|
||||||
|
@ -90,6 +105,10 @@ class Dandelion():
|
||||||
invQueue.put((v.stream, k, v.child))
|
invQueue.put((v.stream, k, v.child))
|
||||||
|
|
||||||
def maybeRemoveStem(self, connection):
|
def maybeRemoveStem(self, connection):
|
||||||
|
"""
|
||||||
|
Remove current connection from the stem list (called e.g. when
|
||||||
|
a connection is closed).
|
||||||
|
"""
|
||||||
# is the stem active?
|
# is the stem active?
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if connection in self.stem:
|
if connection in self.stem:
|
||||||
|
@ -107,6 +126,10 @@ class Dandelion():
|
||||||
None, v.stream, self.poissonTimeout())
|
None, v.stream, self.poissonTimeout())
|
||||||
|
|
||||||
def pickStem(self, parent=None):
|
def pickStem(self, parent=None):
|
||||||
|
"""
|
||||||
|
Pick a random active stem, but not the parent one
|
||||||
|
(the one where an object came from)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# pick a random from available stems
|
# pick a random from available stems
|
||||||
stem = choice(range(len(self.stem)))
|
stem = choice(range(len(self.stem)))
|
||||||
|
@ -123,6 +146,10 @@ class Dandelion():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getNodeStem(self, node=None):
|
def getNodeStem(self, node=None):
|
||||||
|
"""
|
||||||
|
Return child stem node for a given parent stem node
|
||||||
|
(the mapping is static for about 10 minutes, then it reshuffles)
|
||||||
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
try:
|
try:
|
||||||
return self.nodeMap[node]
|
return self.nodeMap[node]
|
||||||
|
@ -131,6 +158,7 @@ class Dandelion():
|
||||||
return self.nodeMap[node]
|
return self.nodeMap[node]
|
||||||
|
|
||||||
def expire(self):
|
def expire(self):
|
||||||
|
"""Switch expired objects from stem to fluff mode"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
deadline = time()
|
deadline = time()
|
||||||
toDelete = [
|
toDelete = [
|
||||||
|
@ -144,6 +172,7 @@ class Dandelion():
|
||||||
return toDelete
|
return toDelete
|
||||||
|
|
||||||
def reRandomiseStems(self):
|
def reRandomiseStems(self):
|
||||||
|
"""Re-shuffle stem mapping (parent <-> child pairs)"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
try:
|
try:
|
||||||
# random two connections
|
# random two connections
|
||||||
|
|
|
@ -5,6 +5,7 @@ from proxy import Proxy, ProxyError, GeneralProxyError
|
||||||
|
|
||||||
|
|
||||||
class Socks4aError(ProxyError):
|
class Socks4aError(ProxyError):
|
||||||
|
"""SOCKS4a error base class"""
|
||||||
errorCodes = (
|
errorCodes = (
|
||||||
"Request granted",
|
"Request granted",
|
||||||
"Request rejected or failed",
|
"Request rejected or failed",
|
||||||
|
@ -17,16 +18,19 @@ class Socks4aError(ProxyError):
|
||||||
|
|
||||||
|
|
||||||
class Socks4a(Proxy):
|
class Socks4a(Proxy):
|
||||||
|
"""SOCKS4a proxy class"""
|
||||||
def __init__(self, address=None):
|
def __init__(self, address=None):
|
||||||
Proxy.__init__(self, address)
|
Proxy.__init__(self, address)
|
||||||
self.ipaddr = None
|
self.ipaddr = None
|
||||||
self.destport = address[1]
|
self.destport = address[1]
|
||||||
|
|
||||||
def state_init(self):
|
def state_init(self):
|
||||||
|
"""Protocol initialisation (before connection is established)"""
|
||||||
self.set_state("auth_done", 0)
|
self.set_state("auth_done", 0)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
|
"""Handle feedback from SOCKS4a while it is connecting on our behalf"""
|
||||||
# Get the response
|
# Get the response
|
||||||
if self.read_buf[0:1] != chr(0x00).encode():
|
if self.read_buf[0:1] != chr(0x00).encode():
|
||||||
# bad data
|
# bad data
|
||||||
|
@ -53,14 +57,20 @@ class Socks4a(Proxy):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def proxy_sock_name(self):
|
def proxy_sock_name(self):
|
||||||
|
"""
|
||||||
|
Handle return value when using SOCKS4a for DNS resolving
|
||||||
|
instead of connecting.
|
||||||
|
"""
|
||||||
return socket.inet_ntoa(self.__proxysockname[0])
|
return socket.inet_ntoa(self.__proxysockname[0])
|
||||||
|
|
||||||
|
|
||||||
class Socks4aConnection(Socks4a):
|
class Socks4aConnection(Socks4a):
|
||||||
|
"""Child SOCKS4a class used for making outbound connections."""
|
||||||
def __init__(self, address):
|
def __init__(self, address):
|
||||||
Socks4a.__init__(self, address=address)
|
Socks4a.__init__(self, address=address)
|
||||||
|
|
||||||
def state_auth_done(self):
|
def state_auth_done(self):
|
||||||
|
"""Request connection to be made"""
|
||||||
# Now we can request the actual connection
|
# Now we can request the actual connection
|
||||||
rmtrslv = False
|
rmtrslv = False
|
||||||
self.append_write_buf(
|
self.append_write_buf(
|
||||||
|
@ -92,6 +102,7 @@ class Socks4aConnection(Socks4a):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
|
"""Tell SOCKS4a to initiate a connection"""
|
||||||
try:
|
try:
|
||||||
return Socks4a.state_pre_connect(self)
|
return Socks4a.state_pre_connect(self)
|
||||||
except Socks4aError as e:
|
except Socks4aError as e:
|
||||||
|
@ -100,6 +111,7 @@ class Socks4aConnection(Socks4a):
|
||||||
|
|
||||||
|
|
||||||
class Socks4aResolver(Socks4a):
|
class Socks4aResolver(Socks4a):
|
||||||
|
"""DNS resolver class using SOCKS4a"""
|
||||||
def __init__(self, host):
|
def __init__(self, host):
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = 8444
|
self.port = 8444
|
||||||
|
@ -118,4 +130,9 @@ class Socks4aResolver(Socks4a):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def resolved(self):
|
def resolved(self):
|
||||||
|
"""
|
||||||
|
Resolving is done, process the return value. To use this within
|
||||||
|
PyBitmessage, a callback needs to be implemented which hasn't
|
||||||
|
been done yet.
|
||||||
|
"""
|
||||||
print "Resolved %s as %s" % (self.host, self.proxy_sock_name())
|
print "Resolved %s as %s" % (self.host, self.proxy_sock_name())
|
||||||
|
|
Reference in New Issue
Block a user