You can recreate your addresses on any computer from memory."
+ " You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. | "
+ " You must remember (or write down) your passphrase if you expect to be able"
+ " to recreate your keys if they are lost."
+ # "You must remember the address version number and the stream number along with your passphrase. "
+ " If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your"
+ " messages and send messages as you.")
label.setWordWrap(True)
self.randomAddress = QtGui.QRadioButton("Use a random number generator to make an address")
@@ -59,14 +78,18 @@ class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage):
self.setLayout(layout)
def nextId(self):
+ """Page 2"""
+
if self.randomAddress.isChecked():
return 2
- else:
- return 3
+ return 3
+
class NewAddressWizardRandomPage(QtGui.QWizardPage):
+ """The user chose a new random address"""
+
def __init__(self, addresses):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardRandomPage, self).__init__()
self.setTitle("Random")
label = QtGui.QLabel("Random address.")
@@ -75,10 +98,11 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
labelLabel = QtGui.QLabel("Label (not shown to anyone except you):")
self.labelLineEdit = QtGui.QLineEdit()
- self.radioButtonMostAvailable = QtGui.QRadioButton("Use the most available stream\n"
+ self.radioButtonMostAvailable = QtGui.QRadioButton(
+ "Use the most available stream\n"
"(best if this is the first of many addresses you will create)")
self.radioButtonExisting = QtGui.QRadioButton("Use the same stream as an existing address\n"
- "(saves you some bandwidth and processing power)")
+ "(saves you some bandwidth and processing power)")
self.radioButtonMostAvailable.setChecked(True)
self.comboBoxExisting = QtGui.QComboBox()
self.comboBoxExisting.setEnabled(False)
@@ -86,10 +110,10 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
for address in addresses:
self.comboBoxExisting.addItem(address)
-
-# self.comboBoxExisting.setObjectName(_fromUtf8("comboBoxExisting"))
- self.checkBoxEighteenByteRipe = QtGui.QCheckBox("Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter")
-
+
+ self.checkBoxEighteenByteRipe = QtGui.QCheckBox(
+ "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter")
+
layout = QtGui.QGridLayout()
layout.addWidget(label, 0, 0)
layout.addWidget(labelLabel, 1, 0)
@@ -100,24 +124,27 @@ class NewAddressWizardRandomPage(QtGui.QWizardPage):
layout.addWidget(self.checkBoxEighteenByteRipe, 6, 0)
self.setLayout(layout)
- QtCore.QObject.connect(self.radioButtonExisting, QtCore.SIGNAL("toggled(bool)"), self.comboBoxExisting.setEnabled)
-
+ QtCore.QObject.connect( # pylint: disable=no-member
+ self.radioButtonExisting,
+ QtCore.SIGNAL("toggled(bool)"),
+ self.comboBoxExisting.setEnabled)
+
self.registerField("label", self.labelLineEdit)
self.registerField("radioButtonMostAvailable", self.radioButtonMostAvailable)
self.registerField("radioButtonExisting", self.radioButtonExisting)
self.registerField("comboBoxExisting", self.comboBoxExisting)
-# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account")
-# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)")
-# self.emailAsWell.setChecked(True)
-
def nextId(self):
+ """Page 6"""
+
return 6
-
+
class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
+ """The user chose a passphrase-based address"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardPassphrasePage, self).__init__()
self.setTitle("Passphrase")
label = QtGui.QLabel("Deterministric address.")
@@ -126,7 +153,8 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
passphraseLabel = QtGui.QLabel("Passphrase")
self.lineEditPassphrase = QtGui.QLineEdit()
self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password)
- self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText)
+ self.lineEditPassphrase.setInputMethodHints(
+ QtCore.Qt.ImhHiddenText | QtCore.Qt.ImhNoAutoUppercase | QtCore.Qt.ImhNoPredictiveText)
retypePassphraseLabel = QtGui.QLabel("Retype passphrase")
self.lineEditPassphraseAgain = QtGui.QLineEdit()
self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password)
@@ -135,11 +163,11 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox()
self.spinBoxNumberOfAddressesToMake.setMinimum(1)
self.spinBoxNumberOfAddressesToMake.setProperty("value", 8)
-# self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake"))
+
label2 = QtGui.QLabel("In addition to your passphrase, you must remember these numbers:")
label3 = QtGui.QLabel("Address version number: 4")
label4 = QtGui.QLabel("Stream number: 1")
-
+
layout = QtGui.QGridLayout()
layout.addWidget(label, 0, 0, 1, 4)
layout.addWidget(passphraseLabel, 1, 0, 1, 4)
@@ -155,34 +183,39 @@ class NewAddressWizardPassphrasePage(QtGui.QWizardPage):
self.setLayout(layout)
def nextId(self):
+ """Page 6"""
+
return 6
-
+
class NewAddressWizardEmailProviderPage(QtGui.QWizardPage):
+ """The user choses the email gateway address type"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardEmailProviderPage, self).__init__()
self.setTitle("Choose email provider")
label = QtGui.QLabel("Currently only Mailchuck email gateway is available "
- "(@mailchuck.com email address). In the future, maybe other gateways will be available. "
- "Press Next.")
+ "(@mailchuck.com email address). In the future, maybe other gateways will be available. "
+ "Press Next.")
label.setWordWrap(True)
-# self.mailchuck = QtGui.QRadioButton("Mailchuck email gateway (@mailchuck.com)")
-# self.mailchuck.setChecked(True)
-
layout = QtGui.QVBoxLayout()
layout.addWidget(label)
-# layout.addWidget(self.mailchuck)
+
self.setLayout(layout)
def nextId(self):
+ """Page 5"""
+
return 5
-
+
class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
+ """The user provides their email gateway detauils"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardEmailAddressPage, self).__init__()
self.setTitle("Email address")
label = QtGui.QLabel("Choosing an email address. Address must end with @mailchuck.com")
@@ -192,8 +225,9 @@ class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
self.specificEmail.setChecked(True)
self.emailLineEdit = QtGui.QLineEdit()
self.randomEmail = QtGui.QRadioButton("Generate a random email address")
-
- QtCore.QObject.connect(self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled)
+
+ QtCore.QObject.connect( # pylint: disable=no-member
+ self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled)
layout = QtGui.QVBoxLayout()
layout.addWidget(label)
@@ -203,33 +237,37 @@ class NewAddressWizardEmailAddressPage(QtGui.QWizardPage):
self.setLayout(layout)
def nextId(self):
+ """Page 6"""
+
return 6
-
+
class NewAddressWizardWaitPage(QtGui.QWizardPage):
+ """Wait for the address to be generated"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardWaitPage, self).__init__()
self.setTitle("Wait")
-
+
self.label = QtGui.QLabel("Wait!")
self.label.setWordWrap(True)
self.progressBar = QtGui.QProgressBar()
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(100)
self.progressBar.setValue(0)
-
-# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account")
-# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)")
-# self.emailAsWell.setChecked(True)
layout = QtGui.QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.progressBar)
-# layout.addWidget(self.emailAsWell)
-# layout.addWidget(self.onlyBM)
+
self.setLayout(layout)
def update(self, i):
+ """
+ Update the progress bar
+
+ .. todo:: remove print statement?
+ """
if i == 101 and self.wizard().currentId() == 6:
self.wizard().button(QtGui.QWizard.NextButton).click()
return
@@ -239,15 +277,17 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
self.progressBar.setValue(i)
if i == 50:
self.emit(QtCore.SIGNAL('completeChanged()'))
-
+
def isComplete(self):
-# print "val = " + str(self.progressBar.value())
+ """Predicate to indicate progress is complete"""
+
if self.progressBar.value() >= 50:
return True
- else:
- return False
-
+ return False
+
def initializePage(self):
+ """Initialize the underlying QWizardPage"""
+
if self.field("emailAsWell").toBool():
val = "yes/"
else:
@@ -258,19 +298,23 @@ class NewAddressWizardWaitPage(QtGui.QWizardPage):
val += "no"
self.label.setText("Wait! " + val)
-# self.wizard().button(QtGui.QWizard.NextButton).setEnabled(False)
+
self.progressBar.setValue(0)
self.thread = NewAddressThread()
self.connect(self.thread, self.thread.signal, self.update)
self.thread.start()
-
+
def nextId(self):
+ """Page 10"""
+
return 10
-
+
class NewAddressWizardConclusionPage(QtGui.QWizardPage):
+ """The user is informed their address has been created"""
+
def __init__(self):
- super(QtGui.QWizardPage, self).__init__()
+ super(NewAddressWizardConclusionPage, self).__init__()
self.setTitle("All done!")
label = QtGui.QLabel("You successfully created a new address.")
@@ -278,14 +322,17 @@ class NewAddressWizardConclusionPage(QtGui.QWizardPage):
layout = QtGui.QVBoxLayout()
layout.addWidget(label)
- self.setLayout(layout)
+ self.setLayout(layout)
+
class Ui_NewAddressWizard(QtGui.QWizard):
+ """The wizard is a collection of pages"""
+
def __init__(self, addresses):
- super(QtGui.QWizard, self).__init__()
+ super(Ui_NewAddressWizard, self).__init__()
self.pages = {}
-
+
page = NewAddressWizardIntroPage()
self.setPage(0, page)
self.setStartId(0)
@@ -308,45 +355,45 @@ class Ui_NewAddressWizard(QtGui.QWizard):
self.adjustSize()
self.show()
+
class NewAddressThread(QtCore.QThread):
+ # pylint: disable=missing-docstring
+
def __init__(self):
QtCore.QThread.__init__(self)
self.signal = QtCore.SIGNAL("signal")
def __del__(self):
self.wait()
-
+
def createDeterministic(self):
pass
-
+
def createPassphrase(self):
pass
-
+
def broadcastAddress(self):
pass
-
+
def registerMailchuck(self):
pass
-
+
def waitRegistration(self):
pass
def run(self):
- import time
for i in range(1, 101):
- time.sleep(0.1) # artificial time delay
+ time.sleep(0.1) # artificial time delay
self.emit(self.signal, i)
self.emit(self.signal, 101)
-# self.terminate()
+
if __name__ == '__main__':
- import sys
-
app = QtGui.QApplication(sys.argv)
wizard = Ui_NewAddressWizard(["a", "b", "c", "d"])
- if (wizard.exec_()):
+ if wizard.exec_():
print "Email: " + ("yes" if wizard.field("emailAsWell").toBool() else "no")
print "BM: " + ("yes" if wizard.field("onlyBM").toBool() else "no")
else:
diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py
index e50be61b..233a49b1 100644
--- a/src/network/asyncore_pollchoose.py
+++ b/src/network/asyncore_pollchoose.py
@@ -1,7 +1,9 @@
# -*- Mode: Python -*-
# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
# Author: Sam Rushing
-
+# pylint: disable=too-many-statements,too-many-branches,no-self-use,too-many-lines,attribute-defined-outside-init
+# pylint: disable=global-statement
+"""
# ======================================================================
# Copyright 1996 by Sam Rushing
#
@@ -25,7 +27,7 @@
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# ======================================================================
-"""Basic infrastructure for asynchronous socket service clients and servers.
+Basic infrastructure for asynchronous socket service clients and servers.
There are only two ways to have a program on a single processor do "more
than one thing at a time". Multi-threaded programming is the simplest and
@@ -46,22 +48,18 @@ many of the difficult problems for you, making the task of building
sophisticated high-performance network servers and clients a snap.
"""
-# randomise object order for bandwidth balancing
-import random
+import os
import select
import socket
import sys
import time
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, \
- EADDRINUSE, \
- errorcode
+ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \
+ ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \
+ EADDRINUSE, \
+ errorcode
try:
from errno import WSAEWOULDBLOCK
except (ImportError, AttributeError):
@@ -75,13 +73,16 @@ try:
except (ImportError, AttributeError):
WSAECONNRESET = ECONNRESET
try:
- from errno import WSAEADDRINUSE
+ # side-effects on Windows or cruft?
+ from errno import WSAEADDRINUSE # pylint: disable=unused-import
except (ImportError, AttributeError):
WSAEADDRINUSE = EADDRINUSE
+import helper_random
-_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE,
- EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT,
- WSAECONNRESET))
+
+_DISCONNECTED = frozenset((
+ ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF, ECONNREFUSED,
+ EHOSTUNREACH, ENETUNREACH, ETIMEDOUT, WSAECONNRESET))
OP_READ = 1
OP_WRITE = 2
@@ -91,17 +92,21 @@ try:
except NameError:
socket_map = {}
+
def _strerror(err):
try:
return os.strerror(err)
except (ValueError, OverflowError, NameError):
if err in errorcode:
return errorcode[err]
- return "Unknown error %s" %err
+ return "Unknown error %s" % err
+
class ExitNow(Exception):
+ """We don't use directly but may be necessary as we replace asyncore due to some library raising or expecting it"""
pass
+
_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit)
maxDownloadRate = 0
@@ -113,7 +118,10 @@ uploadTimestamp = 0
uploadBucket = 0
sentBytes = 0
+
def read(obj):
+ """Read an event from the object"""
+
if not can_receive():
return
try:
@@ -123,7 +131,10 @@ def read(obj):
except:
obj.handle_error()
+
def write(obj):
+ """Write an event to the object"""
+
if not can_send():
return
try:
@@ -133,8 +144,12 @@ def write(obj):
except:
obj.handle_error()
+
def set_rates(download, upload):
+ """Set throttling rates"""
+
global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp
+
maxDownloadRate = float(download) * 1024
maxUploadRate = float(upload) * 1024
downloadBucket = maxDownloadRate
@@ -142,14 +157,24 @@ def set_rates(download, upload):
downloadTimestamp = time.time()
uploadTimestamp = time.time()
+
def can_receive():
+ """Predicate indicating whether the download throttle is in effect"""
+
return maxDownloadRate == 0 or downloadBucket > 0
+
def can_send():
+ """Predicate indicating whether the upload throttle is in effect"""
+
return maxUploadRate == 0 or uploadBucket > 0
+
def update_received(download=0):
+ """Update the receiving throttle"""
+
global receivedBytes, downloadBucket, downloadTimestamp
+
currentTimestamp = time.time()
receivedBytes += download
if maxDownloadRate > 0:
@@ -160,8 +185,12 @@ def update_received(download=0):
downloadBucket -= download
downloadTimestamp = currentTimestamp
+
def update_sent(upload=0):
+ """Update the sending throttle"""
+
global sentBytes, uploadBucket, uploadTimestamp
+
currentTimestamp = time.time()
sentBytes += upload
if maxUploadRate > 0:
@@ -172,7 +201,10 @@ def update_sent(upload=0):
uploadBucket -= upload
uploadTimestamp = currentTimestamp
+
def _exception(obj):
+ """Handle exceptions as appropriate"""
+
try:
obj.handle_expt_event()
except _reraised_exceptions:
@@ -180,7 +212,10 @@ def _exception(obj):
except:
obj.handle_error()
+
def readwrite(obj, flags):
+ """Read and write any pending data to/from the object"""
+
try:
if flags & select.POLLIN and can_receive():
obj.handle_read_event()
@@ -200,12 +235,17 @@ def readwrite(obj, flags):
except:
obj.handle_error()
+
def select_poller(timeout=0.0, map=None):
"""A poller which uses select(), available on most platforms."""
+ # pylint: disable=redefined-builtin
+
if map is None:
map = socket_map
if map:
- r = []; w = []; e = []
+ r = []
+ w = []
+ e = []
for fd, obj in list(map.items()):
is_r = obj.readable()
is_w = obj.writable()
@@ -251,13 +291,16 @@ def select_poller(timeout=0.0, map=None):
else:
current_thread().stop.wait(timeout)
+
def poll_poller(timeout=0.0, map=None):
"""A poller which uses poll(), available on most UNIXen."""
+ # pylint: disable=redefined-builtin
+
if map is None:
map = socket_map
if timeout is not None:
# timeout is in milliseconds
- timeout = int(timeout*1000)
+ timeout = int(timeout * 1000)
try:
poll_poller.pollster
except AttributeError:
@@ -301,12 +344,16 @@ def poll_poller(timeout=0.0, map=None):
else:
current_thread().stop.wait(timeout)
+
# Aliases for backward compatibility
poll = select_poller
poll2 = poll3 = poll_poller
+
def epoll_poller(timeout=0.0, map=None):
"""A poller which uses epoll(), supported on Linux 2.5.44 and newer."""
+ # pylint: disable=redefined-builtin
+
if map is None:
map = socket_map
try:
@@ -346,7 +393,7 @@ def epoll_poller(timeout=0.0, map=None):
if e.errno != EINTR:
raise
r = []
- except select.error, err:
+ except select.error as err:
if err.args[0] != EINTR:
raise
r = []
@@ -354,12 +401,15 @@ def epoll_poller(timeout=0.0, map=None):
obj = map.get(fd)
if obj is None:
continue
- readwrite(obj, flags)
+ readwrite(obj, flags)
else:
current_thread().stop.wait(timeout)
+
def kqueue_poller(timeout=0.0, map=None):
"""A poller which uses kqueue(), BSD specific."""
+ # pylint: disable=redefined-builtin,no-member
+
if map is None:
map = socket_map
try:
@@ -408,7 +458,7 @@ def kqueue_poller(timeout=0.0, map=None):
for event in events:
fd = event.ident
- obj = map.get(fd)
+ obj = map.get(fd)
if obj is None:
continue
if event.flags & select.KQ_EV_ERROR:
@@ -425,13 +475,15 @@ def kqueue_poller(timeout=0.0, map=None):
current_thread().stop.wait(timeout)
-def loop(timeout=30.0, use_poll=False, map=None, count=None,
- poller=None):
+def loop(timeout=30.0, use_poll=False, map=None, count=None, poller=None):
+ """Poll in a loop, forever if count is None"""
+ # pylint: disable=redefined-builtin
+
if map is None:
map = socket_map
if count is None:
- count = True
- # code which grants backward compatibility with "use_poll"
+ count = True
+ # code which grants backward compatibility with "use_poll"
# argument which should no longer be used in favor of
# "poller"
@@ -460,10 +512,13 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None,
break
# then poll
poller(subtimeout, map)
- if type(count) is int:
+ if isinstance(count, int):
count = count - 1
+
class dispatcher:
+ """Dispatcher for socket objects"""
+ # pylint: disable=too-many-public-methods,too-many-instance-attributes,old-style-class
debug = False
connected = False
@@ -478,6 +533,7 @@ class dispatcher:
minTx = 1500
def __init__(self, sock=None, map=None):
+ # pylint: disable=redefined-builtin
if map is None:
self._map = socket_map
else:
@@ -510,7 +566,7 @@ class dispatcher:
self.socket = None
def __repr__(self):
- status = [self.__class__.__module__+"."+self.__class__.__name__]
+ status = [self.__class__.__module__ + "." + self.__class__.__name__]
if self.accepting and self.addr:
status.append('listening')
elif self.connected:
@@ -525,7 +581,9 @@ class dispatcher:
__str__ = __repr__
def add_channel(self, map=None):
- #self.log_info('adding channel %s' % self)
+ """Add a channel"""
+ # pylint: disable=redefined-builtin
+
if map is None:
map = self._map
map[self._fileno] = self
@@ -533,11 +591,13 @@ class dispatcher:
self.poller_filter = 0
def del_channel(self, map=None):
+ """Delete a channel"""
+ # pylint: disable=redefined-builtin
+
fd = self._fileno
if map is None:
map = self._map
if fd in map:
- #self.log_info('closing channel %d:%s' % (fd, self))
del map[fd]
if self._fileno:
try:
@@ -564,25 +624,29 @@ class dispatcher:
self.poller_registered = False
def create_socket(self, family=socket.AF_INET, socket_type=socket.SOCK_STREAM):
+ """Create a socket"""
self.family_and_type = family, socket_type
sock = socket.socket(family, socket_type)
sock.setblocking(0)
self.set_socket(sock)
def set_socket(self, sock, map=None):
+ """Set socket"""
+ # pylint: disable=redefined-builtin
+
self.socket = sock
-## self.__dict__['socket'] = sock
self._fileno = sock.fileno()
self.add_channel(map)
def set_reuse_addr(self):
- # try to re-use a server port if possible
+ """try to re-use a server port if possible"""
+
try:
self.socket.setsockopt(
socket.SOL_SOCKET, socket.SO_REUSEADDR,
self.socket.getsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR) | 1
- )
+ )
except socket.error:
pass
@@ -593,11 +657,13 @@ class dispatcher:
# ==================================================
def readable(self):
+ """Predicate to indicate download throttle status"""
if maxDownloadRate > 0:
return downloadBucket > dispatcher.minTx
return True
def writable(self):
+ """Predicate to indicate upload throttle status"""
if maxUploadRate > 0:
return uploadBucket > dispatcher.minTx
return True
@@ -607,21 +673,24 @@ class dispatcher:
# ==================================================
def listen(self, num):
+ """Listen on a port"""
self.accepting = True
if os.name == 'nt' and num > 5:
num = 5
return self.socket.listen(num)
def bind(self, addr):
+ """Bind to an address"""
self.addr = addr
return self.socket.bind(addr)
def connect(self, address):
+ """Connect to an address"""
self.connected = False
self.connecting = True
err = self.socket.connect_ex(address)
if err in (EINPROGRESS, EALREADY, EWOULDBLOCK, WSAEWOULDBLOCK) \
- or err == EINVAL and os.name in ('nt', 'ce'):
+ or err == EINVAL and os.name in ('nt', 'ce'):
self.addr = address
return
if err in (0, EISCONN):
@@ -631,7 +700,11 @@ class dispatcher:
raise socket.error(err, errorcode[err])
def accept(self):
- # XXX can return either an address pair or None
+ """
+ Accept incoming connections
+
+ .. todo:: FIXME: can return either an address pair or None
+ """
try:
conn, addr = self.socket.accept()
except TypeError:
@@ -645,6 +718,7 @@ class dispatcher:
return conn, addr
def send(self, data):
+ """Send data"""
try:
result = self.socket.send(data)
return result
@@ -658,6 +732,7 @@ class dispatcher:
raise
def recv(self, buffer_size):
+ """Receive data"""
try:
data = self.socket.recv(buffer_size)
if not data:
@@ -665,8 +740,7 @@ class dispatcher:
# a read condition, and having recv() return 0.
self.handle_close()
return b''
- else:
- return data
+ return data
except socket.error as why:
# winsock sometimes raises ENOTCONN
if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK):
@@ -678,6 +752,7 @@ class dispatcher:
raise
def close(self):
+ """Close connection"""
self.connected = False
self.accepting = False
self.connecting = False
@@ -695,10 +770,10 @@ class dispatcher:
retattr = getattr(self.socket, attr)
except AttributeError:
raise AttributeError("%s instance has no attribute '%s'"
- %(self.__class__.__name__, attr))
+ % (self.__class__.__name__, attr))
else:
msg = "%(me)s.%(attr)s is deprecated; use %(me)s.socket.%(attr)s " \
- "instead" % {'me' : self.__class__.__name__, 'attr' : attr}
+ "instead" % {'me': self.__class__.__name__, 'attr': attr}
warnings.warn(msg, DeprecationWarning, stacklevel=2)
return retattr
@@ -707,13 +782,16 @@ class dispatcher:
# and 'log_info' is for informational, warning and error logging.
def log(self, message):
+ """Log a message to stderr"""
sys.stderr.write('log: %s\n' % str(message))
def log_info(self, message, log_type='info'):
+ """Conditionally print a message"""
if log_type not in self.ignore_log_types:
- print('%s: %s' % (log_type, message))
+ print '%s: %s' % log_type, message
def handle_read_event(self):
+ """Handle a read event"""
if self.accepting:
# accepting sockets are never connected, they "spawn" new
# sockets that are connected
@@ -726,6 +804,7 @@ class dispatcher:
self.handle_read()
def handle_connect_event(self):
+ """Handle a connection event"""
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
if err != 0:
raise socket.error(err, _strerror(err))
@@ -734,6 +813,7 @@ class dispatcher:
self.connecting = False
def handle_write_event(self):
+ """Handle a write event"""
if self.accepting:
# Accepting sockets shouldn't get a write event.
# We will pretend it didn't happen.
@@ -745,6 +825,7 @@ class dispatcher:
self.handle_write()
def handle_expt_event(self):
+ """Handle expected exceptions"""
# handle_expt_event() is called if there might be an error on the
# socket, or if there is OOB data
# check for the error condition first
@@ -763,7 +844,8 @@ class dispatcher:
self.handle_expt()
def handle_error(self):
- nil, t, v, tbinfo = compact_traceback()
+ """Handle unexpected exceptions"""
+ _, t, v, tbinfo = compact_traceback()
# sometimes a user repr method will crash.
try:
@@ -777,89 +859,110 @@ class dispatcher:
t,
v,
tbinfo
- ),
+ ),
'error'
- )
+ )
self.handle_close()
- def handle_expt(self):
- self.log_info('unhandled incoming priority event', 'warning')
-
- def handle_read(self):
- self.log_info('unhandled read event', 'warning')
-
- def handle_write(self):
- self.log_info('unhandled write event', 'warning')
-
- def handle_connect(self):
- self.log_info('unhandled connect event', 'warning')
-
def handle_accept(self):
+ """Handle an accept event"""
pair = self.accept()
if pair is not None:
self.handle_accepted(*pair)
+ def handle_expt(self):
+ """Log that the subclass does not implement handle_expt"""
+ self.log_info('unhandled incoming priority event', 'warning')
+
+ def handle_read(self):
+ """Log that the subclass does not implement handle_read"""
+ self.log_info('unhandled read event', 'warning')
+
+ def handle_write(self):
+ """Log that the subclass does not implement handle_write"""
+ self.log_info('unhandled write event', 'warning')
+
+ def handle_connect(self):
+ """Log that the subclass does not implement handle_connect"""
+ self.log_info('unhandled connect event', 'warning')
+
def handle_accepted(self, sock, addr):
+ """Log that the subclass does not implement handle_accepted"""
sock.close()
self.log_info('unhandled accepted event on %s' % (addr), 'warning')
def handle_close(self):
+ """Log that the subclass does not implement handle_close"""
self.log_info('unhandled close event', 'warning')
self.close()
-# ---------------------------------------------------------------------------
-# adds simple buffered output capability, useful for simple clients.
-# [for more sophisticated usage use asynchat.async_chat]
-# ---------------------------------------------------------------------------
class dispatcher_with_send(dispatcher):
+ """
+ adds simple buffered output capability, useful for simple clients.
+ [for more sophisticated usage use asynchat.async_chat]
+ """
+ # pylint: disable=redefined-builtin
def __init__(self, sock=None, map=None):
+ # pylint: disable=redefined-builtin
+
dispatcher.__init__(self, sock, map)
self.out_buffer = b''
def initiate_send(self):
+ """Initiate a send"""
num_sent = 0
num_sent = dispatcher.send(self, self.out_buffer[:512])
self.out_buffer = self.out_buffer[num_sent:]
def handle_write(self):
+ """Handle a write event"""
self.initiate_send()
def writable(self):
- return (not self.connected) or len(self.out_buffer)
+ """Predicate to indicate if the object is writable"""
+ return not self.connected or len(self.out_buffer)
def send(self, data):
+ """Send data"""
if self.debug:
self.log_info('sending %s' % repr(data))
self.out_buffer = self.out_buffer + data
self.initiate_send()
+
# ---------------------------------------------------------------------------
# used for debugging.
# ---------------------------------------------------------------------------
+
def compact_traceback():
+ """Return a compact traceback"""
t, v, tb = sys.exc_info()
tbinfo = []
- if not tb: # Must have a traceback
+ if not tb: # Must have a traceback
raise AssertionError("traceback does not exist")
while tb:
tbinfo.append((
tb.tb_frame.f_code.co_filename,
tb.tb_frame.f_code.co_name,
str(tb.tb_lineno)
- ))
+ ))
tb = tb.tb_next
# just to be safe
del tb
- file, function, line = tbinfo[-1]
+ filename, function, line = tbinfo[-1]
info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
- return (file, function, line), t, v, info
+ return (filename, function, line), t, v, info
+
def close_all(map=None, ignore_all=False):
+ """Close all connections"""
+ # pylint: disable=redefined-builtin
+
if map is None:
map = socket_map
for x in list(map.values()):
@@ -877,6 +980,7 @@ def close_all(map=None, ignore_all=False):
raise
map.clear()
+
# Asynchronous File I/O:
#
# After a little research (reading man pages on various unixen, and
@@ -890,27 +994,34 @@ def close_all(map=None, ignore_all=False):
#
# Regardless, this is useful for pipes, and stdin/stdout...
+
if os.name == 'posix':
import fcntl
class file_wrapper:
- # Here we override just enough to make a file
- # look like a socket for the purposes of asyncore.
- # The passed fd is automatically os.dup()'d
+ """
+ Here we override just enough to make a file look like a socket for the purposes of asyncore.
+
+ The passed fd is automatically os.dup()'d
+ """
+ # pylint: disable=old-style-class
def __init__(self, fd):
self.fd = os.dup(fd)
def recv(self, *args):
+ """Fake recv()"""
return os.read(self.fd, *args)
def send(self, *args):
+ """Fake send()"""
return os.write(self.fd, *args)
def getsockopt(self, level, optname, buflen=None):
+ """Fake getsockopt()"""
if (level == socket.SOL_SOCKET and
- optname == socket.SO_ERROR and
- not buflen):
+ optname == socket.SO_ERROR and
+ not buflen):
return 0
raise NotImplementedError("Only asyncore specific behaviour "
"implemented.")
@@ -919,14 +1030,19 @@ if os.name == 'posix':
write = send
def close(self):
+ """Fake close()"""
os.close(self.fd)
def fileno(self):
+ """Fake fileno()"""
return self.fd
class file_dispatcher(dispatcher):
+ """A dispatcher for file_wrapper objects"""
def __init__(self, fd, map=None):
+ # pylint: disable=redefined-builtin
+
dispatcher.__init__(self, None, map)
self.connected = True
try:
@@ -940,6 +1056,7 @@ if os.name == 'posix':
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
def set_file(self, fd):
+ """Set file"""
self.socket = file_wrapper(fd)
self._fileno = self.socket.fileno()
self.add_channel()
diff --git a/src/network/bmproto.py b/src/network/bmproto.py
index aff6cd0c..c8927bf5 100644
--- a/src/network/bmproto.py
+++ b/src/network/bmproto.py
@@ -1,6 +1,12 @@
+# pylint: disable=too-many-return-statements,too-many-public-methods,attribute-defined-outside-init,too-many-branches
+# pylint: disable=too-many-instance-attributes,too-many-statements
+"""
+The Bitmessage Protocol
+=======================
+"""
+
import base64
import hashlib
-import random
import socket
import struct
import time
@@ -12,11 +18,11 @@ import knownnodes
from network.advanceddispatcher import AdvancedDispatcher
from network.dandelion import Dandelion
from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, \
- BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError
+ BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError
import network.connectionpool
from network.node import Node
from network.objectracker import ObjectTracker
-from network.proxy import Proxy, ProxyError, GeneralProxyError
+from network.proxy import ProxyError
import addresses
from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue
@@ -25,19 +31,27 @@ import state
import protocol
import helper_random
+
class BMProtoError(ProxyError):
+ """A Bitmessage Protocol Base Error"""
errorCodes = ("Protocol error")
class BMProtoInsufficientDataError(BMProtoError):
+ """A Bitmessage Protocol Insufficient Data Error"""
+
errorCodes = ("Insufficient data")
class BMProtoExcessiveDataError(BMProtoError):
+ """A Bitmessage Protocol Excessive Data Error"""
+
errorCodes = ("Too much data")
class BMProto(AdvancedDispatcher, ObjectTracker):
+ """A parser for the Bitmessage Protocol"""
+
# ~1.6 MB which is the maximum possible size of an inv message.
maxMessageSize = 1600100
# 2**18 = 256kB is the maximum size of an object payload
@@ -52,12 +66,15 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
maxTimeOffset = 3600
def __init__(self, address=None, sock=None):
+ # pylint: disable=super-init-not-called,unused-argument
+
AdvancedDispatcher.__init__(self, sock)
self.isOutbound = False
# packet/connection from a local IP
self.local = False
def bm_proto_reset(self):
+ """TBC"""
self.magic = None
self.command = None
self.payloadLength = 0
@@ -69,7 +86,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
self.object = None
def state_bm_header(self):
- self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(self.read_buf[:protocol.Header.size])
+ """Predicate to indicate the prescence of a header"""
+
+ self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(
+ self.read_buf[:protocol.Header.size])
self.command = self.command.rstrip('\x00')
if self.magic != 0xE9BEB4D9:
# skip 1 byte in order to sync
@@ -84,8 +104,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
self.invalid = True
self.set_state("bm_command", length=protocol.Header.size, expectBytes=self.payloadLength)
return True
-
+
def state_bm_command(self):
+ """TBC"""
self.payload = self.read_buf[:self.payloadLength]
if self.checksum != hashlib.sha512(self.payload).digest()[0:4]:
logger.debug("Bad checksum, ignoring")
@@ -122,7 +143,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
# broken read, ignore
pass
else:
- #print "Skipping command %s due to invalid data" % (self.command)
+ # print "Skipping command %s due to invalid data" % (self.command)
logger.debug("Closing due to invalid command %s", self.command)
self.close_reason = "Invalid command %s" % (self.command)
self.set_state("close")
@@ -134,16 +155,21 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return True
def decode_payload_string(self, length):
- value = self.payload[self.payloadOffset:self.payloadOffset+length]
+ """Read and return `length` bytes from payload"""
+
+ value = self.payload[self.payloadOffset:self.payloadOffset + length]
self.payloadOffset += length
return value
def decode_payload_varint(self):
+ """Decode a varint from the payload"""
+
value, offset = addresses.decodeVarint(self.payload[self.payloadOffset:])
self.payloadOffset += offset
return value
def decode_payload_node(self):
+ """Decode node details from the payload"""
services, host, port = self.decode_payload_content("Q16sH")
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
@@ -153,38 +179,45 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
else:
host = socket.inet_ntop(socket.AF_INET6, str(host))
if host == "":
- # This can happen on Windows systems which are not 64-bit compatible
- # so let us drop the IPv6 address.
+ # This can happen on Windows systems which are not 64-bit compatible
+ # so let us drop the IPv6 address.
host = socket.inet_ntop(socket.AF_INET, str(host[12:16]))
return Node(services, host, port)
- def decode_payload_content(self, pattern = "v"):
- # L = varint indicating the length of the next array
- # l = varint indicating the length of the next item
- # v = varint (or array)
- # H = uint16
- # I = uint32
- # Q = uint64
- # i = net_addr (without time and stream number)
- # s = string
- # 0-9 = length of the next item
- # , = end of array
+ def decode_payload_content(self, pattern="v"):
+ """
+ Decode the payload
+
+ L = varint indicating the length of the next array
+ l = varint indicating the length of the next item
+ v = varint (or array)
+ H = uint16
+ I = uint32
+ Q = uint64
+ i = net_addr (without time and stream number)
+ s = string
+ 0-9 = length of the next item
+ , = end of array
+
+ """
def decode_simple(self, char="v"):
+ """Some expected objects can be decoded very straightforwardly"""
if char == "v":
return self.decode_payload_varint()
if char == "i":
return self.decode_payload_node()
if char == "H":
self.payloadOffset += 2
- return struct.unpack(">H", self.payload[self.payloadOffset-2:self.payloadOffset])[0]
+ return struct.unpack(">H", self.payload[self.payloadOffset - 2:self.payloadOffset])[0]
if char == "I":
self.payloadOffset += 4
- return struct.unpack(">I", self.payload[self.payloadOffset-4:self.payloadOffset])[0]
+ return struct.unpack(">I", self.payload[self.payloadOffset - 4:self.payloadOffset])[0]
if char == "Q":
self.payloadOffset += 8
- return struct.unpack(">Q", self.payload[self.payloadOffset-8:self.payloadOffset])[0]
+ return struct.unpack(">Q", self.payload[self.payloadOffset - 8:self.payloadOffset])[0]
+ return None
size = None
isArray = False
@@ -197,27 +230,19 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
# retval (array)
parserStack = [[1, 1, False, pattern, 0, []]]
- #try:
- # sys._getframe(200)
- # logger.error("Stack depth warning, pattern: %s", pattern)
- # return
- #except ValueError:
- # pass
-
while True:
i = parserStack[-1][3][parserStack[-1][4]]
- if i in "0123456789" and (size is None or parserStack[-1][3][parserStack[-1][4]-1] not in "lL"):
+ if i in "0123456789" and (size is None or parserStack[-1][3][parserStack[-1][4] - 1] not in "lL"):
try:
size = size * 10 + int(i)
except TypeError:
size = int(i)
isArray = False
+
elif i in "Ll" and size is None:
size = self.decode_payload_varint()
- if i == "L":
- isArray = True
- else:
- isArray = False
+ isArray = bool(i == "L")
+
elif size is not None:
if isArray:
parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:], 0, []])
@@ -226,25 +251,26 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
for j in range(parserStack[-1][4], len(parserStack[-1][3])):
if parserStack[-1][3][j] not in "lL0123456789":
break
- parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:j+1], 0, []])
+ # pylint: disable=undefined-loop-variable
+ parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:j + 1], 0, []])
parserStack[-2][4] += len(parserStack[-1][3]) - 1
size = None
continue
+
elif i == "s":
- #if parserStack[-2][2]:
- # parserStack[-1][5].append(self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]])
- #else:
parserStack[-1][5] = self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]]
self.payloadOffset += parserStack[-1][0]
parserStack[-1][1] = 0
parserStack[-1][2] = True
- #del parserStack[-1]
size = None
+
elif i in "viHIQ":
parserStack[-1][5].append(decode_simple(self, parserStack[-1][3][parserStack[-1][4]]))
size = None
+
else:
size = None
+
for depth in range(len(parserStack) - 1, -1, -1):
parserStack[depth][4] += 1
if parserStack[depth][4] >= len(parserStack[depth][3]):
@@ -269,16 +295,19 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
raise BMProtoInsufficientDataError()
def bm_command_error(self):
+ """TBC"""
+ # pylint: disable=unused-variable
fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls")
logger.error("%s:%i error: %i, %s", self.destination.host, self.destination.port, fatalStatus, errorText)
return True
def bm_command_getdata(self):
+ """TBC"""
items = self.decode_payload_content("l32s")
- # skip?
+ # ..todo:: skip?
if time.time() < self.skipUntil:
return True
- #TODO make this more asynchronous
+ # .. todo:: make this more asynchronous
helper_random.randomshuffle(items)
for i in map(str, items):
if Dandelion().hasHash(i) and \
@@ -320,6 +349,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return True
def bm_command_inv(self):
+ """TBC"""
return self._command_inv(False)
def bm_command_dinv(self):
@@ -329,12 +359,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return self._command_inv(True)
def bm_command_object(self):
+ """TBC"""
objectOffset = self.payloadOffset
nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv")
self.object = BMObject(nonce, expiresTime, objectType, version, streamNumber, self.payload, self.payloadOffset)
if len(self.payload) - self.payloadOffset > BMProto.maxObjectPayloadSize:
- logger.info('The payload length of this object is too large (%d bytes). Ignoring it.' % (len(self.payload) - self.payloadOffset))
+ logger.info(
+ 'The payload length of this object is too large (%d bytes). Ignoring it.',
+ len(self.payload) - self.payloadOffset
+ )
raise BMProtoExcessiveDataError()
try:
@@ -347,7 +381,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
try:
self.object.checkStream()
except (BMObjectUnwantedStreamError,) as e:
- BMProto.stopDownloadingObject(self.object.inventoryHash, BMConfigParser().get("inventory", "acceptmismatch"))
+ BMProto.stopDownloadingObject(
+ self.object.inventoryHash, BMConfigParser().get(
+ "inventory", "acceptmismatch"))
if not BMConfigParser().get("inventory", "acceptmismatch"):
raise e
@@ -366,7 +402,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
Dandelion().removeHash(self.object.inventoryHash, "cycle detection")
Inventory()[self.object.inventoryHash] = (
- self.object.objectType, self.object.streamNumber, buffer(self.payload[objectOffset:]), self.object.expiresTime, buffer(self.object.tag))
+ self.object.objectType, self.object.streamNumber,
+ buffer(self.payload[objectOffset:]), self.object.expiresTime,
+ buffer(self.object.tag)
+ )
self.handleReceivedObject(self.object.streamNumber, self.object.inventoryHash)
invQueue.put((self.object.streamNumber, self.object.inventoryHash, self.destination))
return True
@@ -375,9 +414,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return self.decode_payload_content("LQIQ16sH")
def bm_command_addr(self):
- addresses = self._decode_addr()
- for i in addresses:
- seenTime, stream, services, ip, port = i
+ """TBC"""
+ these_addresses = self._decode_addr()
+ for i in these_addresses:
+ seenTime, stream, _, ip, port = i
decodedIP = protocol.checkIPAddress(str(ip))
if stream not in state.streamsInWhichIAmParticipating:
continue
@@ -402,18 +442,23 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return True
def bm_command_portcheck(self):
+ """TBC"""
portCheckerQueue.put(state.Peer(self.destination, self.peerNode.port))
return True
def bm_command_ping(self):
+ """TBC"""
self.append_write_buf(protocol.CreatePacket('pong'))
return True
def bm_command_pong(self):
- # nothing really
+ """noop"""
+ # pylint: disable=no-self-use
return True
def bm_command_verack(self):
+ """TBC"""
+
self.verackReceived = True
if self.verackSent:
if self.isSSL:
@@ -424,6 +469,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return True
def bm_command_version(self):
+ """TBC"""
+
self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \
self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv")
self.nonce = struct.pack('>Q', self.nonce)
@@ -434,17 +481,20 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
logger.debug("my external IP: %s", self.sockNode.host)
logger.debug("remote node incoming address: %s:%i", self.destination.host, self.peerNode.port)
logger.debug("user agent: %s", self.userAgent)
- logger.debug("streams: [%s]", ",".join(map(str,self.streams)))
+ logger.debug("streams: [%s]", ",".join(map(str, self.streams)))
if not self.peerValidityChecks():
- # TODO ABORT
+ # .. todo:: ABORT
return True
- #shared.connectedHostsList[self.destination] = self.streams[0]
self.append_write_buf(protocol.CreatePacket('verack'))
self.verackSent = True
if not self.isOutbound:
- self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
- network.connectionpool.BMConnectionPool().streams, True, nodeid=self.nodeid))
- #print "%s:%i: Sending version" % (self.destination.host, self.destination.port)
+ self.append_write_buf(
+ protocol.assembleVersionMessage(
+ self.destination.host,
+ self.destination.port,
+ network.connectionpool.BMConnectionPool().streams,
+ True,
+ nodeid=self.nodeid))
if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and
protocol.haveSSL(not self.isOutbound)):
self.isSSL = True
@@ -457,41 +507,45 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
return True
def peerValidityChecks(self):
+ """Check the validity of peers"""
if self.remoteProtocolVersion < 3:
- self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="Your is using an old protocol. Closing connection."))
- logger.debug ('Closing connection to old protocol version %s, node: %s',
- str(self.remoteProtocolVersion), str(self.destination))
+ self.append_write_buf(protocol.assembleErrorMessage(
+ fatal=2, errorText="Your is using an old protocol. Closing connection."))
+ logger.debug('Closing connection to old protocol version %s, node: %s',
+ str(self.remoteProtocolVersion), str(self.destination))
return False
if self.timeOffset > BMProto.maxTimeOffset:
- self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="Your time is too far in the future compared to mine. Closing connection."))
+ self.append_write_buf(
+ protocol.assembleErrorMessage(
+ fatal=2,
+ errorText="Your time is too far in the future compared to mine. Closing connection."))
logger.info("%s's time is too far in the future (%s seconds). Closing connection to it.",
- self.destination, self.timeOffset)
+ self.destination, self.timeOffset)
shared.timeOffsetWrongCount += 1
return False
elif self.timeOffset < -BMProto.maxTimeOffset:
- self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="Your time is too far in the past compared to mine. Closing connection."))
+ self.append_write_buf(protocol.assembleErrorMessage(
+ fatal=2, errorText="Your time is too far in the past compared to mine. Closing connection."))
logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it.",
- self.destination, self.timeOffset)
+ self.destination, self.timeOffset)
shared.timeOffsetWrongCount += 1
return False
else:
shared.timeOffsetWrongCount = 0
if not self.streams:
- self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="We don't have shared stream interests. Closing connection."))
- logger.debug ('Closed connection to %s because there is no overlapping interest in streams.',
- str(self.destination))
+ self.append_write_buf(protocol.assembleErrorMessage(
+ fatal=2, errorText="We don't have shared stream interests. Closing connection."))
+ logger.debug('Closed connection to %s because there is no overlapping interest in streams.',
+ str(self.destination))
return False
if self.destination in network.connectionpool.BMConnectionPool().inboundConnections:
try:
if not protocol.checkSocksIP(self.destination.host):
- self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="Too many connections from your IP. Closing connection."))
- logger.debug ('Closed connection to %s because we are already connected to that IP.',
- str(self.destination))
+ self.append_write_buf(
+ protocol.assembleErrorMessage(
+ fatal=2, errorText="Too many connections from your IP. Closing connection."))
+ logger.debug('Closed connection to %s because we are already connected to that IP.',
+ str(self.destination))
return False
except:
pass
@@ -499,27 +553,30 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
# incoming from a peer we're connected to as outbound, or server full
# report the same error to counter deanonymisation
if state.Peer(self.destination.host, self.peerNode.port) in \
- network.connectionpool.BMConnectionPool().inboundConnections or \
- len(network.connectionpool.BMConnectionPool().inboundConnections) + \
- len(network.connectionpool.BMConnectionPool().outboundConnections) > \
- BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \
- BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"):
+ network.connectionpool.BMConnectionPool().inboundConnections or \
+ len(network.connectionpool.BMConnectionPool().inboundConnections) + \
+ len(network.connectionpool.BMConnectionPool().outboundConnections) > \
+ BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \
+ BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"):
self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="Server full, please try again later."))
- logger.debug ("Closed connection to %s due to server full or duplicate inbound/outbound.",
- str(self.destination))
+ errorText="Server full, please try again later."))
+ logger.debug("Closed connection to %s due to server full or duplicate inbound/outbound.",
+ str(self.destination))
return False
if network.connectionpool.BMConnectionPool().isAlreadyConnected(self.nonce):
- self.append_write_buf(protocol.assembleErrorMessage(fatal=2,
- errorText="I'm connected to myself. Closing connection."))
- logger.debug ("Closed connection to %s because I'm connected to myself.",
- str(self.destination))
+ self.append_write_buf(
+ protocol.assembleErrorMessage(
+ fatal=2,
+ errorText="I'm connected to myself. Closing connection."))
+ logger.debug("Closed connection to %s because I'm connected to myself.",
+ str(self.destination))
return False
return True
@staticmethod
def assembleAddr(peerList):
+ """iBuild up a packed address"""
if isinstance(peerList, state.Peer):
peerList = (peerList)
if not peerList:
@@ -541,6 +598,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
@staticmethod
def stopDownloadingObject(hashId, forwardAnyway=False):
+ """Stop downloading an object"""
for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \
network.connectionpool.BMConnectionPool().outboundConnections.values():
try:
@@ -559,6 +617,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
pass
def handle_close(self):
+ """Handle close"""
self.set_state("close")
if not (self.accepting or self.connecting or self.connected):
# already disconnected
diff --git a/src/network/tcp.py b/src/network/tcp.py
index 163cbd85..322acba6 100644
--- a/src/network/tcp.py
+++ b/src/network/tcp.py
@@ -1,41 +1,45 @@
-import base64
-from binascii import hexlify
-import hashlib
+# pylint: disable=too-many-ancestors
+"""
+tcp.py
+======
+"""
+
+from __future__ import absolute_import
+
import math
import time
-from pprint import pprint
import socket
-import struct
import random
-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
-from network.bmproto import BMProtoError, BMProtoInsufficientDataError, BMProtoExcessiveDataError, BMProto
-from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError
+
+from network.bmproto import BMProto
import network.connectionpool
from network.dandelion import Dandelion
-from network.node import Node
import network.asyncore_pollchoose as asyncore
-from network.proxy import Proxy, ProxyError, GeneralProxyError
from network.objectracker import ObjectTracker
-from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error
-from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError
+from network.socks5 import Socks5Connection
+from network.socks4a import Socks4aConnection
from network.tls import TLSDispatcher
-
import addresses
from bmconfigparser import BMConfigParser
-from queues import invQueue, objectProcessorQueue, portCheckerQueue, UISignalQueue, receiveDataQueue
+from queues import invQueue, UISignalQueue, receiveDataQueue
import shared
import state
import protocol
-class TCPConnection(BMProto, TLSDispatcher):
+
+class TCPConnection(BMProto, TLSDispatcher): # pylint: disable=too-many-instance-attributes
+ """
+
+ .. todo:: Look to understand and/or fix the non-parent-init-called
+ """
+
def __init__(self, address=None, sock=None):
BMProto.__init__(self, address=address, sock=sock)
self.verackReceived = False
@@ -67,18 +71,27 @@ class TCPConnection(BMProto, TLSDispatcher):
self.connect(self.destination)
logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port)
encodedAddr = protocol.encodeHost(self.destination.host)
- if protocol.checkIPAddress(encodedAddr, True) and not protocol.checkSocksIP(self.destination.host):
- self.local = True
- else:
- self.local = False
- #shared.connectedHostsList[self.destination] = 0
- ObjectTracker.__init__(self)
+ self.local = all([
+ protocol.checkIPAddress(encodedAddr, True),
+ not protocol.checkSocksIP(self.destination.host)
+ ])
+ ObjectTracker.__init__(self) # pylint: disable=non-parent-init-called
self.bm_proto_reset()
self.set_state("bm_header", expectBytes=protocol.Header.size)
- def antiIntersectionDelay(self, initial = False):
+ def antiIntersectionDelay(self, initial=False):
+ """TBC"""
# estimated time for a small object to propagate across the whole network
- delay = math.ceil(math.log(max(len(knownnodes.knownNodes[x]) for x in knownnodes.knownNodes) + 2, 20)) * (0.2 + invQueue.queueCount/2.0)
+
+ delay = math.ceil(
+ math.log(
+ max(
+ len(knownnodes.knownNodes[x])
+ for x in knownnodes.knownNodes
+ ) + 2,
+ 20
+ )
+ ) * (0.2 + invQueue.queueCount / 2.0)
# take the stream with maximum amount of nodes
# +2 is to avoid problems with log(0) and log(1)
# 20 is avg connected nodes count
@@ -93,12 +106,14 @@ class TCPConnection(BMProto, TLSDispatcher):
self.skipUntil = time.time() + delay
def state_connection_fully_established(self):
+ """TBC"""
self.set_connection_fully_established()
self.set_state("bm_header")
self.bm_proto_reset()
return True
def set_connection_fully_established(self):
+ """TBC"""
if not self.isOutbound and not self.local:
shared.clientHasReceivedIncomingConnections = True
UISignalQueue.put(('setStatusIcon', 'green'))
@@ -113,50 +128,50 @@ class TCPConnection(BMProto, TLSDispatcher):
self.sendBigInv()
def sendAddr(self):
+ """TBC"""
# We are going to share a maximum number of 1000 addrs (per overlapping
# stream) with our peer. 500 from overlapping streams, 250 from the
# left child stream, and 250 from the right child stream.
maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500)
# init
- addressCount = 0
- payload = b''
-
templist = []
addrs = {}
for stream in self.streams:
with knownnodes.knownNodesLock:
- if len(knownnodes.knownNodes[stream]) > 0:
+ if knownnodes.knownNodes[stream]:
filtered = {k: v for k, v in knownnodes.knownNodes[stream].items()
- if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
+ if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
elemCount = len(filtered)
if elemCount > maxAddrCount:
elemCount = maxAddrCount
# only if more recent than 3 hours
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()
- if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
+ if knownnodes.knownNodes[stream * 2] and stream not in self.streams:
+ filtered = {k: v for k, v in knownnodes.knownNodes[stream * 2].items()
+ if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
elemCount = len(filtered)
if elemCount > maxAddrCount / 2:
elemCount = int(maxAddrCount / 2)
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)}
+ if knownnodes.knownNodes[(stream * 2) + 1] 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] = helper_random.randomsample(filtered.items(), elemCount)
- for substream in addrs.keys():
+ for substream in addrs:
for peer, params in addrs[substream]:
templist.append((substream, peer, params["lastseen"]))
- if len(templist) > 0:
+ if templist:
self.append_write_buf(BMProto.assembleAddr(templist))
def sendBigInv(self):
+ """TBC"""
def sendChunk():
+ """TBC"""
if objectCount == 0:
return
logger.debug('Sending huge inv message with %i objects to just this one peer', objectCount)
@@ -172,13 +187,12 @@ class TCPConnection(BMProto, TLSDispatcher):
if Dandelion().hasHash(objHash):
continue
bigInvList[objHash] = 0
- #self.objectsNewToThem[objHash] = time.time()
objectCount = 0
payload = b''
# Now let us start appending all of these hashes together. They will be
# sent out in a big inv message to our new peer.
- for hash, storedValue in bigInvList.items():
- payload += hash
+ for obj_hash, _ in bigInvList.items():
+ payload += obj_hash
objectCount += 1
if objectCount >= BMProto.maxObjectCount:
sendChunk()
@@ -189,20 +203,26 @@ class TCPConnection(BMProto, TLSDispatcher):
sendChunk()
def handle_connect(self):
+ """TBC"""
try:
AdvancedDispatcher.handle_connect(self)
except socket.error as e:
- if e.errno in asyncore._DISCONNECTED:
- logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e)))
+ if e.errno in asyncore._DISCONNECTED: # pylint: disable=protected-access
+ logger.debug("%s:%i: Connection failed: %s", self.destination.host, self.destination.port, str(e))
return
self.nodeid = randomBytes(8)
- self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
- network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid))
- #print "%s:%i: Sending version" % (self.destination.host, self.destination.port)
+ self.append_write_buf(
+ protocol.assembleVersionMessage(
+ self.destination.host,
+ self.destination.port,
+ network.connectionpool.BMConnectionPool().streams,
+ False,
+ nodeid=self.nodeid))
self.connectedAt = time.time()
receiveDataQueue.put(self.destination)
def handle_read(self):
+ """TBC"""
TLSDispatcher.handle_read(self)
if self.isOutbound and self.fullyEstablished:
for s in self.streams:
@@ -214,9 +234,11 @@ class TCPConnection(BMProto, TLSDispatcher):
receiveDataQueue.put(self.destination)
def handle_write(self):
+ """TBC"""
TLSDispatcher.handle_write(self)
def handle_close(self):
+ """TBC"""
if self.isOutbound and not self.fullyEstablished:
knownnodes.decreaseRating(self.destination)
if self.fullyEstablished:
@@ -227,37 +249,55 @@ class TCPConnection(BMProto, TLSDispatcher):
class Socks5BMConnection(Socks5Connection, TCPConnection):
+ """TBC"""
+
def __init__(self, address):
Socks5Connection.__init__(self, address=address)
TCPConnection.__init__(self, address=address, sock=self.socket)
self.set_state("init")
def state_proxy_handshake_done(self):
+ """TBC"""
Socks5Connection.state_proxy_handshake_done(self)
self.nodeid = randomBytes(8)
- self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
- network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid))
+ self.append_write_buf(
+ protocol.assembleVersionMessage(
+ self.destination.host,
+ self.destination.port,
+ network.connectionpool.BMConnectionPool().streams,
+ False,
+ nodeid=self.nodeid))
self.set_state("bm_header", expectBytes=protocol.Header.size)
return True
class Socks4aBMConnection(Socks4aConnection, TCPConnection):
+ """TBC"""
+
def __init__(self, address):
Socks4aConnection.__init__(self, address=address)
TCPConnection.__init__(self, address=address, sock=self.socket)
self.set_state("init")
def state_proxy_handshake_done(self):
+ """TBC"""
Socks4aConnection.state_proxy_handshake_done(self)
self.nodeid = randomBytes(8)
- self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
- network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid))
+ self.append_write_buf(
+ protocol.assembleVersionMessage(
+ self.destination.host,
+ self.destination.port,
+ network.connectionpool.BMConnectionPool().streams,
+ False,
+ nodeid=self.nodeid))
self.set_state("bm_header", expectBytes=protocol.Header.size)
return True
class TCPServer(AdvancedDispatcher):
- def __init__(self, host='127.0.0.1', port=8444):
+ """TBC"""
+
+ def __init__(self, host='127.0.0.1', port=8444): # pylint: disable=redefined-outer-name
if not hasattr(self, '_map'):
AdvancedDispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -280,20 +320,22 @@ class TCPServer(AdvancedDispatcher):
self.listen(5)
def is_bound(self):
+ """TBC"""
try:
return self.bound
except AttributeError:
return False
def handle_accept(self):
+ """TBC"""
pair = self.accept()
if pair is not None:
- sock, addr = pair
+ sock, _ = pair
state.ownAddresses[state.Peer(sock.getsockname()[0], sock.getsockname()[1])] = True
if len(network.connectionpool.BMConnectionPool().inboundConnections) + \
- len(network.connectionpool.BMConnectionPool().outboundConnections) > \
- BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \
- BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections") + 10:
+ len(network.connectionpool.BMConnectionPool().outboundConnections) > \
+ BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \
+ BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections") + 10:
# 10 is a sort of buffer, in between it will go through the version handshake
# and return an error to the peer
logger.warning("Server full, dropping connection")
@@ -310,17 +352,7 @@ if __name__ == "__main__":
for host in (("127.0.0.1", 8448),):
direct = TCPConnection(host)
- while len(asyncore.socket_map) > 0:
+ while asyncore.socket_map:
print "loop, state = %s" % (direct.state)
asyncore.loop(timeout=10, count=1)
continue
-
- proxy = Socks5BMConnection(host)
- while len(asyncore.socket_map) > 0:
-# print "loop, state = %s" % (proxy.state)
- asyncore.loop(timeout=10, count=1)
-
- proxy = Socks4aBMConnection(host)
- while len(asyncore.socket_map) > 0:
-# print "loop, state = %s" % (proxy.state)
- asyncore.loop(timeout=10, count=1)
diff --git a/src/proofofwork.py b/src/proofofwork.py
index df6ed295..aeb782c8 100644
--- a/src/proofofwork.py
+++ b/src/proofofwork.py
@@ -1,60 +1,74 @@
-#import shared
-#import time
-#from multiprocessing import Pool, cpu_count
+# pylint: disable=too-many-branches,too-many-statements,protected-access
+"""
+proofofwork.py
+==============
+"""
+
+from __future__ import absolute_import
+
+import ctypes
import hashlib
-from struct import unpack, pack
-from subprocess import call
+import os
import sys
import time
-from bmconfigparser import BMConfigParser
-from debug import logger
+from struct import unpack, pack
+from subprocess import call
+
import paths
import openclpow
import queues
import tr
-import os
-import ctypes
-
import state
+from bmconfigparser import BMConfigParser
+from debug import logger
+
bitmsglib = 'bitmsghash.so'
-
bmpow = None
+
def _set_idle():
if 'linux' in sys.platform:
os.nice(20)
else:
try:
+ # pylint: disable=no-member,import-error
sys.getwindowsversion()
- import win32api,win32process,win32con # @UnresolvedImport
+ import win32api
+ import win32process
+ import win32con # @UnresolvedImport
pid = win32api.GetCurrentProcessId()
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS)
except:
- #Windows 64-bit
+ # Windows 64-bit
pass
+
def _pool_worker(nonce, initialHash, target, pool_size):
_set_idle()
trialValue = float('inf')
while trialValue > target:
nonce += pool_size
- trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
+ trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(
+ pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
return [trialValue, nonce]
+
def _doSafePoW(target, initialHash):
logger.debug("Safe PoW start")
nonce = 0
trialValue = float('inf')
while trialValue > target and state.shutdown == 0:
nonce += 1
- trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
+ trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(
+ pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
if state.shutdown != 0:
- raise StopIteration("Interrupted")
+ raise StopIteration("Interrupted") # pylint: misplaced-bare-raise
logger.debug("Safe PoW done")
return [trialValue, nonce]
+
def _doFastPoW(target, initialHash):
logger.debug("Fast PoW start")
from multiprocessing import Pool, cpu_count
@@ -96,7 +110,8 @@ def _doFastPoW(target, initialHash):
logger.debug("Fast PoW done")
return result[0], result[1]
time.sleep(0.2)
-
+
+
def _doCPoW(target, initialHash):
h = initialHash
m = target
@@ -104,33 +119,52 @@ def _doCPoW(target, initialHash):
out_m = ctypes.c_ulonglong(m)
logger.debug("C PoW start")
nonce = bmpow(out_h, out_m)
- trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
+ trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
if state.shutdown != 0:
raise StopIteration("Interrupted")
logger.debug("C PoW done")
return [trialValue, nonce]
+
def _doGPUPoW(target, initialHash):
logger.debug("GPU PoW start")
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
- trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
- #print "{} - value {} < {}".format(nonce, trialValue, target)
+ trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
if trialValue > target:
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
- queues.UISignalQueue.put(('updateStatusBar', (tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'), 1)))
- logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames)
+ queues.UISignalQueue.put(
+ (
+ 'updateStatusBar',
+ (
+ tr._translate(
+ "MainWindow",
+ 'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'
+ ),
+ 1
+ )
+ )
+ )
+ logger.error(
+ "Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.",
+ deviceNames)
openclpow.enabledGpus = []
raise Exception("GPU did not calculate correctly.")
if state.shutdown != 0:
raise StopIteration("Interrupted")
logger.debug("GPU PoW done")
return [trialValue, nonce]
-
-def estimate(difficulty, format = False):
+
+
+def estimate(difficulty, format=False): # pylint: disable=redefined-builtin
+ """
+ .. todo: fix unused variable
+ """
ret = difficulty / 10
if ret < 1:
ret = 1
+
if format:
+ # pylint: disable=unused-variable
out = str(int(ret)) + " seconds"
if ret > 60:
ret /= 60
@@ -148,25 +182,46 @@ def estimate(difficulty, format = False):
if ret > 366:
ret /= 366
out = str(int(ret)) + " years"
- else:
- return ret
+ ret = None # Ensure legacy behaviour
+
+ return ret
+
def getPowType():
+ """Get the proof of work implementation"""
+
if openclpow.openclEnabled():
return "OpenCL"
if bmpow:
return "C"
return "python"
+
def notifyBuild(tried=False):
+ """TBC"""
+
if bmpow:
- queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1)))
+ queues.UISignalQueue.put(('updateStatusBar', (tr._translate(
+ "proofofwork", "C PoW module built successfully."), 1)))
elif tried:
- queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1)))
+ queues.UISignalQueue.put(
+ (
+ 'updateStatusBar', (
+ tr._translate(
+ "proofofwork",
+ "Failed to build C PoW module. Please build it manually."
+ ),
+ 1
+ )
+ )
+ )
else:
- queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1)))
+ queues.UISignalQueue.put(('updateStatusBar', (tr._translate(
+ "proofofwork", "C PoW module unavailable. Please build it."), 1)))
+
def buildCPoW():
+ """TBC"""
if bmpow is not None:
return
if paths.frozen is not None:
@@ -190,29 +245,27 @@ def buildCPoW():
except:
notifyBuild(True)
+
def run(target, initialHash):
+ """Run the proof of work thread"""
+
if state.shutdown != 0:
raise
target = int(target)
if openclpow.openclEnabled():
-# trialvalue1, nonce1 = _doGPUPoW(target, initialHash)
-# trialvalue, nonce = _doFastPoW(target, initialHash)
-# print "GPU: %s, %s" % (trialvalue1, nonce1)
-# print "Fast: %s, %s" % (trialvalue, nonce)
-# return [trialvalue, nonce]
try:
return _doGPUPoW(target, initialHash)
except StopIteration:
raise
except:
- pass # fallback
+ pass # fallback
if bmpow:
try:
return _doCPoW(target, initialHash)
except StopIteration:
raise
except:
- pass # fallback
+ pass # fallback
if paths.frozen == "macosx_app" or not paths.frozen:
# on my (Peter Surda) Windows 10, Windows Defender
# does not like this and fights with PyBitmessage
@@ -225,24 +278,30 @@ def run(target, initialHash):
raise
except:
logger.error("Fast PoW got exception:", exc_info=True)
- pass #fallback
try:
return _doSafePoW(target, initialHash)
except StopIteration:
raise
except:
- pass #fallback
+ pass # fallback
+
def resetPoW():
+ """TBC"""
openclpow.initCL()
+
# init
+
+
def init():
- global bitmsglib, bso, bmpow
+ """TBC"""
+ # pylint: disable=global-statement
+ global bitmsglib, bmpow
openclpow.initCL()
- if "win32" == sys.platform:
+ if sys.platform == "win32":
if ctypes.sizeof(ctypes.c_voidp) == 4:
bitmsglib = 'bitmsghash32.dll'
else:
diff --git a/src/socks/__init__.py b/src/socks/__init__.py
index 0bfa18f5..aa83f60e 100644
--- a/src/socks/__init__.py
+++ b/src/socks/__init__.py
@@ -1,4 +1,6 @@
-"""SocksiPy - Python SOCKS module.
+# pylint: disable=too-many-arguments,global-statement,too-many-branches
+"""
+SocksiPy - Python SOCKS module.
Version 1.00
Copyright 2006 Dan-Haim. All rights reserved.
@@ -28,10 +30,6 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
This module provides a standard socket-like interface for Python
for tunneling connections through SOCKS proxies.
-"""
-
-"""
-
Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
for use in PyLoris (http://pyloris.sourceforge.net/)
@@ -42,7 +40,7 @@ mainly to merge bug fixes found in Sourceforge
import socket
import struct
-import sys
+
PROXY_TYPE_SOCKS4 = 1
PROXY_TYPE_SOCKS5 = 2
@@ -51,46 +49,71 @@ PROXY_TYPE_HTTP = 3
_defaultproxy = None
_orgsocket = socket.socket
-class ProxyError(Exception): pass
-class GeneralProxyError(ProxyError): pass
-class Socks5AuthError(ProxyError): pass
-class Socks5Error(ProxyError): pass
-class Socks4Error(ProxyError): pass
-class HTTPError(ProxyError): pass
+
+class ProxyError(Exception):
+ """Base class for other ProxyErrors"""
+ pass
+
+
+class GeneralProxyError(ProxyError):
+ """Handle a general proxy error"""
+ pass
+
+
+class Socks5AuthError(ProxyError):
+ """Handle a SOCKS5 auth error"""
+ pass
+
+
+class Socks5Error(ProxyError):
+ """Handle a SOCKS5 non-auth error"""
+ pass
+
+
+class Socks4Error(ProxyError):
+ """Handle a SOCKS4 error"""
+ pass
+
+
+class HTTPError(ProxyError):
+ """Handle a HTTP error"""
+ pass
+
_generalerrors = ("success",
- "invalid data",
- "not connected",
- "not available",
- "bad proxy type",
- "bad input",
- "timed out",
- "network unreachable",
- "connection refused",
- "host unreachable")
+ "invalid data",
+ "not connected",
+ "not available",
+ "bad proxy type",
+ "bad input",
+ "timed out",
+ "network unreachable",
+ "connection refused",
+ "host unreachable")
_socks5errors = ("succeeded",
- "general SOCKS server failure",
- "connection not allowed by ruleset",
- "Network unreachable",
- "Host unreachable",
- "Connection refused",
- "TTL expired",
- "Command not supported",
- "Address type not supported",
- "Unknown error")
+ "general SOCKS server failure",
+ "connection not allowed by ruleset",
+ "Network unreachable",
+ "Host unreachable",
+ "Connection refused",
+ "TTL expired",
+ "Command not supported",
+ "Address type not supported",
+ "Unknown error")
_socks5autherrors = ("succeeded",
- "authentication is required",
- "all offered authentication methods were rejected",
- "unknown username or invalid password",
- "unknown error")
+ "authentication is required",
+ "all offered authentication methods were rejected",
+ "unknown username or invalid password",
+ "unknown error")
_socks4errors = ("request granted",
- "request rejected or failed",
- "request rejected because SOCKS server cannot connect to identd on the client",
- "request rejected because the client program and identd report different user-ids",
- "unknown error")
+ "request rejected or failed",
+ "request rejected because SOCKS server cannot connect to identd on the client",
+ "request rejected because the client program and identd report different user-ids",
+ "unknown error")
+
def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
"""setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
@@ -100,6 +123,7 @@ def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=No
global _defaultproxy
_defaultproxy = (proxytype, addr, port, rdns, username, password)
+
def wrapmodule(module):
"""wrapmodule(module)
Attempts to replace a module's socket library with a SOCKS socket. Must set
@@ -107,11 +131,12 @@ def wrapmodule(module):
This will only work on modules that import socket directly into the namespace;
most of the Python Standard Library falls into this category.
"""
- if _defaultproxy != None:
+ if _defaultproxy is not None:
module.socket.socket = socksocket
else:
raise GeneralProxyError((4, "no proxy specified"))
+
class socksocket(socket.socket):
"""socksocket([family[, type[, proto]]]) -> socket object
Open a SOCKS enabled socket. The parameters are the same as
@@ -120,8 +145,9 @@ class socksocket(socket.socket):
"""
def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
+ # pylint: disable=redefined-builtin
_orgsocket.__init__(self, family, type, proto, _sock)
- if _defaultproxy != None:
+ if _defaultproxy is not None:
self.__proxy = _defaultproxy
else:
self.__proxy = (None, None, None, None, None, None)
@@ -138,8 +164,9 @@ class socksocket(socket.socket):
except socket.timeout:
raise GeneralProxyError((6, "timed out"))
while len(data) < count:
- d = self.recv(count-len(data))
- if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
+ d = self.recv(count - len(data))
+ if not d:
+ raise GeneralProxyError((0, "connection closed unexpectedly"))
data = data + d
return data
@@ -167,7 +194,7 @@ class socksocket(socket.socket):
Negotiates a connection through a SOCKS5 server.
"""
# First we'll send the authentication packages we support.
- if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
+ if (self.__proxy[4] is not None) and (self.__proxy[5] is not None):
# The username/password details were supplied to the
# setproxy method so we support the USERNAME/PASSWORD
# authentication (in addition to the standard none).
@@ -189,7 +216,11 @@ class socksocket(socket.socket):
elif chosenauth[1:2] == chr(0x02).encode():
# Okay, we need to perform a basic username/password
# authentication.
- self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
+ self.sendall(chr(0x01).encode() +
+ chr(len(self.__proxy[4])) +
+ self.__proxy[4] +
+ chr(len(self.__proxy[5])) +
+ self.__proxy[5])
authstat = self.__recvall(2)
if authstat[0:1] != chr(0x01).encode():
# Bad response
@@ -207,7 +238,7 @@ class socksocket(socket.socket):
raise Socks5AuthError((2, _socks5autherrors[2]))
else:
raise GeneralProxyError((1, _generalerrors[1]))
-
+
def __connectsocks5(self, destaddr, destport):
# Now we can request the actual connection
req = struct.pack('BBB', 0x05, 0x01, 0x00)
@@ -236,7 +267,7 @@ class socksocket(socket.socket):
elif resp[1:2] != chr(0x00).encode():
# Connection failed
self.close()
- if ord(resp[1:2])<=8:
+ if ord(resp[1:2]) <= 8:
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
else:
raise Socks5Error((9, _socks5errors[9]))
@@ -248,10 +279,10 @@ class socksocket(socket.socket):
boundaddr = self.__recvall(ord(resp[4:5]))
else:
self.close()
- raise GeneralProxyError((1,_generalerrors[1]))
+ raise GeneralProxyError((1, _generalerrors[1]))
boundport = struct.unpack(">H", self.__recvall(2))[0]
self.__proxysockname = (boundaddr, boundport)
- if ipaddr != None:
+ if ipaddr is not None:
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
else:
self.__proxypeername = (destaddr, destport)
@@ -271,7 +302,7 @@ class socksocket(socket.socket):
elif resp[1:2] != chr(0x00).encode():
# Connection failed
self.close()
- if ord(resp[1:2])<=8:
+ if ord(resp[1:2]) <= 8:
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
else:
raise Socks5Error((9, _socks5errors[9]))
@@ -283,10 +314,10 @@ class socksocket(socket.socket):
ip = self.__recvall(ord(resp[4:5]))
else:
self.close()
- raise GeneralProxyError((1,_generalerrors[1]))
- boundport = struct.unpack(">H", self.__recvall(2))[0]
+ raise GeneralProxyError((1, _generalerrors[1]))
+ _ = struct.unpack(">H", self.__recvall(2))[0]
return ip
-
+
def getproxysockname(self):
"""getsockname() -> address info
Returns the bound IP address and port number at the proxy.
@@ -307,9 +338,10 @@ class socksocket(socket.socket):
return self.__proxypeername
def getproxytype(self):
+ """Get the proxy type"""
return self.__proxy[0]
- def __negotiatesocks4(self,destaddr,destport):
+ def __negotiatesocks4(self, destaddr, destport):
"""__negotiatesocks4(self,destaddr,destport)
Negotiates a connection through a SOCKS4 server.
"""
@@ -327,7 +359,7 @@ class socksocket(socket.socket):
# Construct the request packet
req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
# The username parameter is considered userid for SOCKS4
- if self.__proxy[4] != None:
+ if self.__proxy[4] is not None:
req = req + self.__proxy[4]
req = req + chr(0x00).encode()
# DNS name if remote resolving is required
@@ -341,7 +373,7 @@ class socksocket(socket.socket):
if resp[0:1] != chr(0x00).encode():
# Bad data
self.close()
- raise GeneralProxyError((1,_generalerrors[1]))
+ raise GeneralProxyError((1, _generalerrors[1]))
if resp[1:2] != chr(0x5A).encode():
# Server returned an error
self.close()
@@ -352,7 +384,7 @@ class socksocket(socket.socket):
raise Socks4Error((94, _socks4errors[4]))
# Get the bound address/port
self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
- if rmtrslv != None:
+ if rmtrslv is not None:
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
else:
self.__proxypeername = (destaddr, destport)
@@ -366,7 +398,16 @@ class socksocket(socket.socket):
addr = socket.gethostbyname(destaddr)
else:
addr = destaddr
- self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode())
+ self.sendall(''.join([
+ "CONNECT ",
+ addr,
+ ":",
+ str(destport),
+ " HTTP/1.1\r\n",
+ "Host: ",
+ destaddr,
+ "\r\n\r\n",
+ ]).encode())
# We read the response until we get the string "\r\n\r\n"
resp = self.recv(1)
while resp.find("\r\n\r\n".encode()) == -1:
@@ -396,10 +437,15 @@ class socksocket(socket.socket):
To select the proxy server use setproxy().
"""
# Do a minimal input check first
- if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (type(destpair[0]) != type('')) or (type(destpair[1]) != int):
+ if any([
+ not isinstance(destpair, (list, tuple)),
+ len(destpair) < 2,
+ not isinstance(destpair[0], type('')),
+ not isinstance(destpair[1], int),
+ ]):
raise GeneralProxyError((5, _generalerrors[5]))
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
- if self.__proxy[2] != None:
+ if self.__proxy[2] is not None:
portnum = self.__proxy[2]
else:
portnum = 1080
@@ -419,19 +465,19 @@ class socksocket(socket.socket):
self.__negotiatesocks5()
self.__connectsocks5(destpair[0], destpair[1])
elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
- if self.__proxy[2] != None:
+ if self.__proxy[2] is not None:
portnum = self.__proxy[2]
else:
portnum = 1080
- _orgsocket.connect(self,(self.__proxy[1], portnum))
+ _orgsocket.connect(self, (self.__proxy[1], portnum))
self.__negotiatesocks4(destpair[0], destpair[1])
elif self.__proxy[0] == PROXY_TYPE_HTTP:
- if self.__proxy[2] != None:
+ if self.__proxy[2] is not None:
portnum = self.__proxy[2]
else:
portnum = 8080
try:
- _orgsocket.connect(self,(self.__proxy[1], portnum))
+ _orgsocket.connect(self, (self.__proxy[1], portnum))
except socket.error as e:
# ENETUNREACH, WSAENETUNREACH
if e[0] in [101, 10051]:
@@ -444,14 +490,15 @@ class socksocket(socket.socket):
raise GeneralProxyError((9, _generalerrors[9]))
raise
self.__negotiatehttp(destpair[0], destpair[1])
- elif self.__proxy[0] == None:
+ elif self.__proxy[0] is None:
_orgsocket.connect(self, (destpair[0], destpair[1]))
else:
raise GeneralProxyError((4, _generalerrors[4]))
def resolve(self, host):
+ """TBC"""
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
- if self.__proxy[2] != None:
+ if self.__proxy[2] is not None:
portnum = self.__proxy[2]
else:
portnum = 1080
diff --git a/src/upnp.py b/src/upnp.py
index 46d55956..7ea6a9a6 100644
--- a/src/upnp.py
+++ b/src/upnp.py
@@ -1,21 +1,33 @@
-# A simple upnp module to forward port for BitMessage
-# Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port
+# pylint: disable=too-many-statements,too-many-branches,protected-access,no-self-use
+"""
+A simple upnp module to forward port for BitMessage
+Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port
+"""
+
+from __future__ import absolute_import
+
import httplib
from random import randint
import socket
-from struct import unpack, pack
+from struct import unpack
import threading
import time
+import urllib2
+from urlparse import urlparse
+from xml.dom.minidom import Document, parseString
+
from bmconfigparser import BMConfigParser
+from debug import logger
from network.connectionpool import BMConnectionPool
-from helper_threading import *
+from helper_threading import StoppableThread
import queues
import shared
import state
import tr
+
def createRequestXML(service, action, arguments=None):
- from xml.dom.minidom import Document
+ """Router UPnP requests are XML formatted"""
doc = Document()
@@ -63,22 +75,24 @@ def createRequestXML(service, action, arguments=None):
# our tree is ready, conver it to a string
return doc.toxml()
-class UPnPError(Exception):
- def __init__(self, message):
- self.message
-class Router:
+class UPnPError(Exception):
+ """Handle a UPnP error"""
+
+ def __init__(self, message):
+ super(UPnPError, self).__init__()
+ logger.error(message)
+
+
+class Router: # pylint: disable=old-style-class
+ """TBC"""
name = ""
path = ""
address = None
routerPath = None
extPort = None
-
+
def __init__(self, ssdpResponse, address):
- import urllib2
- from xml.dom.minidom import parseString
- from urlparse import urlparse
- from debug import logger
self.address = address
@@ -92,9 +106,9 @@ class Router:
try:
self.routerPath = urlparse(header['location'])
if not self.routerPath or not hasattr(self.routerPath, "hostname"):
- logger.error ("UPnP: no hostname: %s", header['location'])
+ logger.error("UPnP: no hostname: %s", header['location'])
except KeyError:
- logger.error ("UPnP: missing location header")
+ logger.error("UPnP: missing location header")
# get the profile xml file and read it into a variable
directory = urllib2.urlopen(header['location']).read()
@@ -108,45 +122,58 @@ class Router:
for service in service_types:
if service.childNodes[0].data.find('WANIPConnection') > 0 or \
- service.childNodes[0].data.find('WANPPPConnection') > 0:
+ service.childNodes[0].data.find('WANPPPConnection') > 0:
self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
self.upnp_schema = service.childNodes[0].data.split(':')[-2]
- def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1):
- from debug import logger
+ def AddPortMapping(
+ self,
+ externalPort,
+ internalPort,
+ internalClient,
+ protocol,
+ description,
+ leaseDuration=0,
+ enabled=1,
+ ): # pylint: disable=too-many-arguments
+ """Add UPnP port mapping"""
+
resp = self.soapRequest(self.upnp_schema + ':1', 'AddPortMapping', [
- ('NewRemoteHost', ''),
- ('NewExternalPort', str(externalPort)),
- ('NewProtocol', protocol),
- ('NewInternalPort', str(internalPort)),
- ('NewInternalClient', internalClient),
- ('NewEnabled', str(enabled)),
- ('NewPortMappingDescription', str(description)),
- ('NewLeaseDuration', str(leaseDuration))
- ])
+ ('NewRemoteHost', ''),
+ ('NewExternalPort', str(externalPort)),
+ ('NewProtocol', protocol),
+ ('NewInternalPort', str(internalPort)),
+ ('NewInternalClient', internalClient),
+ ('NewEnabled', str(enabled)),
+ ('NewPortMappingDescription', str(description)),
+ ('NewLeaseDuration', str(leaseDuration))
+ ])
self.extPort = externalPort
- logger.info("Successfully established UPnP mapping for %s:%i on external port %i", internalClient, internalPort, externalPort)
+ logger.info("Successfully established UPnP mapping for %s:%i on external port %i",
+ internalClient, internalPort, externalPort)
return resp
def DeletePortMapping(self, externalPort, protocol):
- from debug import logger
+ """Delete UPnP port mapping"""
+
resp = self.soapRequest(self.upnp_schema + ':1', 'DeletePortMapping', [
- ('NewRemoteHost', ''),
- ('NewExternalPort', str(externalPort)),
- ('NewProtocol', protocol),
- ])
+ ('NewRemoteHost', ''),
+ ('NewExternalPort', str(externalPort)),
+ ('NewProtocol', protocol),
+ ])
logger.info("Removed UPnP mapping on external port %i", externalPort)
return resp
def GetExternalIPAddress(self):
- from xml.dom.minidom import parseString
+ """Get the external address"""
+
resp = self.soapRequest(self.upnp_schema + ':1', 'GetExternalIPAddress')
dom = parseString(resp)
return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data
-
+
def soapRequest(self, service, action, arguments=None):
- from xml.dom.minidom import parseString
- from debug import logger
+ """Make a request to a router"""
+
conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port)
conn.request(
'POST',
@@ -155,8 +182,8 @@ class Router:
{
'SOAPAction': '"urn:schemas-upnp-org:service:%s#%s"' % (service, action),
'Content-Type': 'text/xml'
- }
- )
+ }
+ )
resp = conn.getresponse()
conn.close()
if resp.status == 500:
@@ -164,21 +191,24 @@ class Router:
try:
dom = parseString(respData)
errinfo = dom.getElementsByTagName('errorDescription')
- if len(errinfo) > 0:
+ if errinfo:
logger.error("UPnP error: %s", respData)
raise UPnPError(errinfo[0].childNodes[0].data)
except:
- raise UPnPError("Unable to parse SOAP error: %s" %(respData))
+ raise UPnPError("Unable to parse SOAP error: %s" % (respData))
return resp
+
class uPnPThread(threading.Thread, StoppableThread):
+ """Start a thread to handle UPnP activity"""
+
SSDP_ADDR = "239.255.255.250"
GOOGLE_DNS = "8.8.8.8"
SSDP_PORT = 1900
SSDP_MX = 2
SSDP_ST = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
- def __init__ (self):
+ def __init__(self):
threading.Thread.__init__(self, name="uPnPThread")
try:
self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport')
@@ -194,8 +224,8 @@ class uPnPThread(threading.Thread, StoppableThread):
self.initStop()
def run(self):
- from debug import logger
-
+ """Start the thread to manage UPnP activity"""
+
logger.debug("Starting UPnP thread")
logger.debug("Local IP: %s", self.localIP)
lastSent = 0
@@ -209,9 +239,11 @@ class uPnPThread(threading.Thread, StoppableThread):
if not bound:
time.sleep(1)
+ # pylint: disable=attribute-defined-outside-init
self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
+
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
- if time.time() - lastSent > self.sendSleep and len(self.routers) == 0:
+ if time.time() - lastSent > self.sendSleep and not self.routers:
try:
self.sendSearchRouter()
except:
@@ -219,7 +251,7 @@ class uPnPThread(threading.Thread, StoppableThread):
lastSent = time.time()
try:
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
- resp,(ip,port) = self.sock.recvfrom(1000)
+ resp, (ip, _) = self.sock.recvfrom(1000)
if resp is None:
continue
newRouter = Router(resp, ip)
@@ -230,14 +262,16 @@ class uPnPThread(threading.Thread, StoppableThread):
logger.debug("Found UPnP router at %s", ip)
self.routers.append(newRouter)
self.createPortMapping(newRouter)
- queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping established on port %1').arg(str(self.extPort))))
+ queues.UISignalQueue.put(('updateStatusBar', tr._translate(
+ "MainWindow", 'UPnP port mapping established on port %1'
+ ).arg(str(self.extPort))))
# retry connections so that the submitted port is refreshed
with shared.alreadyAttemptedConnectionsListLock:
shared.alreadyAttemptedConnectionsList.clear()
shared.alreadyAttemptedConnectionsListResetTime = int(
time.time())
break
- except socket.timeout as e:
+ except socket.timeout:
pass
except:
logger.error("Failure running UPnP router search.", exc_info=True)
@@ -259,22 +293,25 @@ class uPnPThread(threading.Thread, StoppableThread):
self.deletePortMapping(router)
shared.extPort = None
if deleted:
- queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping removed')))
+ queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow", 'UPnP port mapping removed')))
logger.debug("UPnP thread done")
def getLocalIP(self):
+ """Get the local IP of the node"""
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.connect((uPnPThread.GOOGLE_DNS, 1))
return s.getsockname()[0]
def sendSearchRouter(self):
- from debug import logger
+ """Querying for UPnP services"""
+
ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
- "HOST: %s:%d\r\n" % (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT) + \
- "MAN: \"ssdp:discover\"\r\n" + \
- "MX: %d\r\n" % (uPnPThread.SSDP_MX, ) + \
- "ST: %s\r\n" % (uPnPThread.SSDP_ST, ) + "\r\n"
+ "HOST: %s:%d\r\n" % (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT) + \
+ "MAN: \"ssdp:discover\"\r\n" + \
+ "MX: %d\r\n" % (uPnPThread.SSDP_MX, ) + \
+ "ST: %s\r\n" % (uPnPThread.SSDP_ST, ) + "\r\n"
try:
logger.debug("Sending UPnP query")
@@ -283,19 +320,24 @@ class uPnPThread(threading.Thread, StoppableThread):
logger.exception("UPnP send query failed")
def createPortMapping(self, router):
- from debug import logger
+ """Add a port mapping"""
for i in range(50):
try:
- routerIP, = unpack('>I', socket.inet_aton(router.address))
+ _, = unpack('>I', socket.inet_aton(router.address))
localIP = self.localIP
if i == 0:
- extPort = self.localPort # try same port first
+ extPort = self.localPort # try same port first
elif i == 1 and self.extPort:
- extPort = self.extPort # try external port from last time next
+ extPort = self.extPort # try external port from last time next
else:
extPort = randint(32767, 65535)
- logger.debug("Attempt %i, requesting UPnP mapping for %s:%i on external port %i", i, localIP, self.localPort, extPort)
+ logger.debug(
+ "Attempt %i, requesting UPnP mapping for %s:%i on external port %i",
+ i,
+ localIP,
+ self.localPort,
+ extPort)
router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage')
shared.extPort = extPort
self.extPort = extPort
@@ -306,7 +348,5 @@ class uPnPThread(threading.Thread, StoppableThread):
logger.debug("UPnP error: ", exc_info=True)
def deletePortMapping(self, router):
+ """Delete a port mapping"""
router.DeletePortMapping(router.extPort, 'TCP')
-
-
-
--
2.45.1
|