Added ability to limit network transfer rate

This commit is contained in:
Jonathan Warren 2014-09-10 16:47:51 -04:00
parent c84cdecba4
commit 0865e863ec
10 changed files with 328 additions and 82 deletions

View File

@ -1346,26 +1346,23 @@ class MyForm(QtGui.QMainWindow):
if self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text() == "":
QMessageBox.about(self, _translate("MainWindow", "bad passphrase"), _translate(
"MainWindow", "You must type your passphrase. If you don\'t have one then this is not the form for you."))
else:
streamNumberForAddress = int(
self.regenerateAddressesDialogInstance.ui.lineEditStreamNumber.text())
try:
addressVersionNumber = int(
self.regenerateAddressesDialogInstance.ui.lineEditAddressVersionNumber.text())
except:
QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate(
"MainWindow", "Your address version number must be a number: either 3 or 4."))
if addressVersionNumber < 3 or addressVersionNumber > 4:
QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate(
"MainWindow", "Your address version number must be either 3 or 4."))
# self.addressGenerator = addressGenerator()
# self.addressGenerator.setup(addressVersionNumber,streamNumberForAddress,"unused address",self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value(),self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(),self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())
# QtCore.QObject.connect(self.addressGenerator, SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable)
# QtCore.QObject.connect(self.addressGenerator, QtCore.SIGNAL("updateStatusBar(PyQt_PyObject)"), self.updateStatusBar)
# self.addressGenerator.start()
shared.addressGeneratorQueue.put(('createDeterministicAddresses', addressVersionNumber, streamNumberForAddress, "regenerated deterministic address", self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value(
), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked()))
self.ui.tabWidget.setCurrentIndex(3)
return
streamNumberForAddress = int(
self.regenerateAddressesDialogInstance.ui.lineEditStreamNumber.text())
try:
addressVersionNumber = int(
self.regenerateAddressesDialogInstance.ui.lineEditAddressVersionNumber.text())
except:
QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate(
"MainWindow", "Your address version number must be a number: either 3 or 4."))
return
if addressVersionNumber < 3 or addressVersionNumber > 4:
QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate(
"MainWindow", "Your address version number must be either 3 or 4."))
return
shared.addressGeneratorQueue.put(('createDeterministicAddresses', addressVersionNumber, streamNumberForAddress, "regenerated deterministic address", self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value(
), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked()))
self.ui.tabWidget.setCurrentIndex(3)
def click_actionJoinChan(self):
self.newChanDialogInstance = newChanDialog(self)
@ -2322,6 +2319,15 @@ class MyForm(QtGui.QMainWindow):
self.settingsDialogInstance.ui.lineEditSocksPassword.text()))
shared.config.set('bitmessagesettings', 'sockslisten', str(
self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked()))
try:
# Rounding to integers just for aesthetics
shared.config.set('bitmessagesettings', 'maxdownloadrate', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text()))))
shared.config.set('bitmessagesettings', 'maxuploadrate', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text()))))
except:
QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate(
"MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed."))
shared.config.set('bitmessagesettings', 'namecoinrpctype',
self.settingsDialogInstance.getNamecoinType())
@ -2333,7 +2339,8 @@ class MyForm(QtGui.QMainWindow):
self.settingsDialogInstance.ui.lineEditNamecoinUser.text()))
shared.config.set('bitmessagesettings', 'namecoinrpcpassword', str(
self.settingsDialogInstance.ui.lineEditNamecoinPassword.text()))
# Demanded difficulty tab
if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1:
shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float(
self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)))
@ -3443,7 +3450,12 @@ class settingsDialog(QtGui.QDialog):
shared.config.get('bitmessagesettings', 'sockspassword')))
QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL(
"currentIndexChanged(int)"), self.comboBoxProxyTypeChanged)
self.ui.lineEditMaxDownloadRate.setText(str(
shared.config.get('bitmessagesettings', 'maxdownloadrate')))
self.ui.lineEditMaxUploadRate.setText(str(
shared.config.get('bitmessagesettings', 'maxuploadrate')))
# Demanded difficulty tab
self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint(
'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)))
self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint(

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'settings.ui'
#
# Created: Mon May 19 15:54:27 2014
# Created: Tue Sep 09 15:13:28 2014
# by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost!
@ -128,6 +128,37 @@ class Ui_settingsDialog(object):
self.lineEditTCPPort.setObjectName(_fromUtf8("lineEditTCPPort"))
self.gridLayout_3.addWidget(self.lineEditTCPPort, 0, 2, 1, 1)
self.gridLayout_4.addWidget(self.groupBox1, 0, 0, 1, 1)
self.groupBox_3 = QtGui.QGroupBox(self.tabNetworkSettings)
self.groupBox_3.setObjectName(_fromUtf8("groupBox_3"))
self.gridLayout_9 = QtGui.QGridLayout(self.groupBox_3)
self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9"))
spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_9.addItem(spacerItem1, 0, 0, 2, 1)
self.label_24 = QtGui.QLabel(self.groupBox_3)
self.label_24.setObjectName(_fromUtf8("label_24"))
self.gridLayout_9.addWidget(self.label_24, 0, 1, 1, 1)
self.lineEditMaxDownloadRate = QtGui.QLineEdit(self.groupBox_3)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lineEditMaxDownloadRate.sizePolicy().hasHeightForWidth())
self.lineEditMaxDownloadRate.setSizePolicy(sizePolicy)
self.lineEditMaxDownloadRate.setMaximumSize(QtCore.QSize(60, 16777215))
self.lineEditMaxDownloadRate.setObjectName(_fromUtf8("lineEditMaxDownloadRate"))
self.gridLayout_9.addWidget(self.lineEditMaxDownloadRate, 0, 2, 1, 1)
self.label_25 = QtGui.QLabel(self.groupBox_3)
self.label_25.setObjectName(_fromUtf8("label_25"))
self.gridLayout_9.addWidget(self.label_25, 1, 1, 1, 1)
self.lineEditMaxUploadRate = QtGui.QLineEdit(self.groupBox_3)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lineEditMaxUploadRate.sizePolicy().hasHeightForWidth())
self.lineEditMaxUploadRate.setSizePolicy(sizePolicy)
self.lineEditMaxUploadRate.setMaximumSize(QtCore.QSize(60, 16777215))
self.lineEditMaxUploadRate.setObjectName(_fromUtf8("lineEditMaxUploadRate"))
self.gridLayout_9.addWidget(self.lineEditMaxUploadRate, 1, 2, 1, 1)
self.gridLayout_4.addWidget(self.groupBox_3, 2, 0, 1, 1)
self.groupBox_2 = QtGui.QGroupBox(self.tabNetworkSettings)
self.groupBox_2.setObjectName(_fromUtf8("groupBox_2"))
self.gridLayout_2 = QtGui.QGridLayout(self.groupBox_2)
@ -176,8 +207,8 @@ class Ui_settingsDialog(object):
self.comboBoxProxyType.addItem(_fromUtf8(""))
self.gridLayout_2.addWidget(self.comboBoxProxyType, 0, 1, 1, 1)
self.gridLayout_4.addWidget(self.groupBox_2, 1, 0, 1, 1)
spacerItem1 = QtGui.QSpacerItem(20, 70, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_4.addItem(spacerItem1, 2, 0, 1, 1)
spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_4.addItem(spacerItem2, 3, 0, 1, 1)
self.tabWidgetSettings.addTab(self.tabNetworkSettings, _fromUtf8(""))
self.tabDemandedDifficulty = QtGui.QWidget()
self.tabDemandedDifficulty.setObjectName(_fromUtf8("tabDemandedDifficulty"))
@ -199,8 +230,8 @@ class Ui_settingsDialog(object):
self.label_8.setWordWrap(True)
self.label_8.setObjectName(_fromUtf8("label_8"))
self.gridLayout_6.addWidget(self.label_8, 0, 0, 1, 3)
spacerItem2 = QtGui.QSpacerItem(203, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_6.addItem(spacerItem2, 1, 0, 1, 1)
spacerItem3 = QtGui.QSpacerItem(203, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_6.addItem(spacerItem3, 1, 0, 1, 1)
self.label_12 = QtGui.QLabel(self.tabDemandedDifficulty)
self.label_12.setWordWrap(True)
self.label_12.setObjectName(_fromUtf8("label_12"))
@ -223,10 +254,10 @@ class Ui_settingsDialog(object):
self.lineEditTotalDifficulty.setMaximumSize(QtCore.QSize(70, 16777215))
self.lineEditTotalDifficulty.setObjectName(_fromUtf8("lineEditTotalDifficulty"))
self.gridLayout_6.addWidget(self.lineEditTotalDifficulty, 1, 2, 1, 1)
spacerItem3 = QtGui.QSpacerItem(203, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_6.addItem(spacerItem3, 3, 0, 1, 1)
spacerItem4 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_6.addItem(spacerItem4, 5, 0, 1, 1)
spacerItem4 = QtGui.QSpacerItem(203, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_6.addItem(spacerItem4, 3, 0, 1, 1)
spacerItem5 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_6.addItem(spacerItem5, 5, 0, 1, 1)
self.tabWidgetSettings.addTab(self.tabDemandedDifficulty, _fromUtf8(""))
self.tabMaxAcceptableDifficulty = QtGui.QWidget()
self.tabMaxAcceptableDifficulty.setObjectName(_fromUtf8("tabMaxAcceptableDifficulty"))
@ -236,8 +267,8 @@ class Ui_settingsDialog(object):
self.label_15.setWordWrap(True)
self.label_15.setObjectName(_fromUtf8("label_15"))
self.gridLayout_7.addWidget(self.label_15, 0, 0, 1, 3)
spacerItem5 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_7.addItem(spacerItem5, 1, 0, 1, 1)
spacerItem6 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_7.addItem(spacerItem6, 1, 0, 1, 1)
self.label_13 = QtGui.QLabel(self.tabMaxAcceptableDifficulty)
self.label_13.setLayoutDirection(QtCore.Qt.LeftToRight)
self.label_13.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
@ -252,8 +283,8 @@ class Ui_settingsDialog(object):
self.lineEditMaxAcceptableTotalDifficulty.setMaximumSize(QtCore.QSize(70, 16777215))
self.lineEditMaxAcceptableTotalDifficulty.setObjectName(_fromUtf8("lineEditMaxAcceptableTotalDifficulty"))
self.gridLayout_7.addWidget(self.lineEditMaxAcceptableTotalDifficulty, 1, 2, 1, 1)
spacerItem6 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_7.addItem(spacerItem6, 2, 0, 1, 1)
spacerItem7 = QtGui.QSpacerItem(102, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_7.addItem(spacerItem7, 2, 0, 1, 1)
self.label_14 = QtGui.QLabel(self.tabMaxAcceptableDifficulty)
self.label_14.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_14.setObjectName(_fromUtf8("label_14"))
@ -267,15 +298,15 @@ class Ui_settingsDialog(object):
self.lineEditMaxAcceptableSmallMessageDifficulty.setMaximumSize(QtCore.QSize(70, 16777215))
self.lineEditMaxAcceptableSmallMessageDifficulty.setObjectName(_fromUtf8("lineEditMaxAcceptableSmallMessageDifficulty"))
self.gridLayout_7.addWidget(self.lineEditMaxAcceptableSmallMessageDifficulty, 2, 2, 1, 1)
spacerItem7 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_7.addItem(spacerItem7, 3, 1, 1, 1)
spacerItem8 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_7.addItem(spacerItem8, 3, 1, 1, 1)
self.tabWidgetSettings.addTab(self.tabMaxAcceptableDifficulty, _fromUtf8(""))
self.tabNamecoin = QtGui.QWidget()
self.tabNamecoin.setObjectName(_fromUtf8("tabNamecoin"))
self.gridLayout_8 = QtGui.QGridLayout(self.tabNamecoin)
self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8"))
spacerItem8 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem8, 2, 0, 1, 1)
spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem9, 2, 0, 1, 1)
self.label_16 = QtGui.QLabel(self.tabNamecoin)
self.label_16.setWordWrap(True)
self.label_16.setObjectName(_fromUtf8("label_16"))
@ -287,10 +318,10 @@ class Ui_settingsDialog(object):
self.lineEditNamecoinHost = QtGui.QLineEdit(self.tabNamecoin)
self.lineEditNamecoinHost.setObjectName(_fromUtf8("lineEditNamecoinHost"))
self.gridLayout_8.addWidget(self.lineEditNamecoinHost, 2, 2, 1, 1)
spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem9, 3, 0, 1, 1)
spacerItem10 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem10, 4, 0, 1, 1)
self.gridLayout_8.addItem(spacerItem10, 3, 0, 1, 1)
spacerItem11 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem11, 4, 0, 1, 1)
self.label_18 = QtGui.QLabel(self.tabNamecoin)
self.label_18.setEnabled(True)
self.label_18.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
@ -299,8 +330,8 @@ class Ui_settingsDialog(object):
self.lineEditNamecoinPort = QtGui.QLineEdit(self.tabNamecoin)
self.lineEditNamecoinPort.setObjectName(_fromUtf8("lineEditNamecoinPort"))
self.gridLayout_8.addWidget(self.lineEditNamecoinPort, 3, 2, 1, 1)
spacerItem11 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_8.addItem(spacerItem11, 8, 1, 1, 1)
spacerItem12 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_8.addItem(spacerItem12, 8, 1, 1, 1)
self.labelNamecoinUser = QtGui.QLabel(self.tabNamecoin)
self.labelNamecoinUser.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.labelNamecoinUser.setObjectName(_fromUtf8("labelNamecoinUser"))
@ -308,8 +339,8 @@ class Ui_settingsDialog(object):
self.lineEditNamecoinUser = QtGui.QLineEdit(self.tabNamecoin)
self.lineEditNamecoinUser.setObjectName(_fromUtf8("lineEditNamecoinUser"))
self.gridLayout_8.addWidget(self.lineEditNamecoinUser, 4, 2, 1, 1)
spacerItem12 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem12, 5, 0, 1, 1)
spacerItem13 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_8.addItem(spacerItem13, 5, 0, 1, 1)
self.labelNamecoinPassword = QtGui.QLabel(self.tabNamecoin)
self.labelNamecoinPassword.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.labelNamecoinPassword.setObjectName(_fromUtf8("labelNamecoinPassword"))
@ -347,8 +378,8 @@ class Ui_settingsDialog(object):
self.label_7.setWordWrap(True)
self.label_7.setObjectName(_fromUtf8("label_7"))
self.gridLayout_5.addWidget(self.label_7, 0, 0, 1, 3)
spacerItem13 = QtGui.QSpacerItem(212, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_5.addItem(spacerItem13, 1, 0, 1, 1)
spacerItem14 = QtGui.QSpacerItem(212, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_5.addItem(spacerItem14, 1, 0, 1, 1)
self.widget = QtGui.QWidget(self.tabResendsExpire)
self.widget.setMinimumSize(QtCore.QSize(231, 75))
self.widget.setObjectName(_fromUtf8("widget"))
@ -373,8 +404,8 @@ class Ui_settingsDialog(object):
self.label_23.setGeometry(QtCore.QRect(170, 41, 71, 16))
self.label_23.setObjectName(_fromUtf8("label_23"))
self.gridLayout_5.addWidget(self.widget, 1, 2, 1, 1)
spacerItem14 = QtGui.QSpacerItem(20, 129, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_5.addItem(spacerItem14, 2, 1, 1, 1)
spacerItem15 = QtGui.QSpacerItem(20, 129, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_5.addItem(spacerItem15, 2, 1, 1, 1)
self.tabWidgetSettings.addTab(self.tabResendsExpire, _fromUtf8(""))
self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1)
@ -416,6 +447,9 @@ class Ui_settingsDialog(object):
self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabUserInterface), _translate("settingsDialog", "User Interface", None))
self.groupBox1.setTitle(_translate("settingsDialog", "Listening port", None))
self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None))
self.groupBox_3.setTitle(_translate("settingsDialog", "Bandwidth limit", None))
self.label_24.setText(_translate("settingsDialog", "Maximum download rate (kB/s): [0: unlimited]", None))
self.label_25.setText(_translate("settingsDialog", "Maximum upload rate (kB/s): [0: unlimited]", None))
self.groupBox_2.setTitle(_translate("settingsDialog", "Proxy server / Tor", None))
self.label_2.setText(_translate("settingsDialog", "Type:", None))
self.label_3.setText(_translate("settingsDialog", "Server hostname:", None))

View File

@ -247,6 +247,74 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Bandwidth limit</string>
</property>
<layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="0" rowspan="2">
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Maximum download rate (kB/s): [0: unlimited]</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="lineEditMaxDownloadRate">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_25">
<property name="text">
<string>Maximum upload rate (kB/s): [0: unlimited]</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="lineEditMaxUploadRate">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
@ -350,7 +418,7 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -358,7 +426,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>70</height>
<height>40</height>
</size>
</property>
</spacer>

View File

@ -1024,7 +1024,13 @@ class objectProcessor(threading.Thread):
if len(payload) != payloadLength:
logger.info('ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.')
return False
if payloadLength > 2 ** 18: # 256 KiB
if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message.
"""
The largest message should be either an inv or a getdata message at 1.6 MB in size.
That doesn't mean that the object may be that big. The
shared.checkAndShareObjectWithPeers function will verify that it is no larger than
2^18 bytes.
"""
return False
if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message.
logger.info('ackdata checksum wrong. Not sending ackdata.')

View File

@ -64,8 +64,6 @@ class outgoingSynSender(threading.Thread):
shared.alreadyAttemptedConnectionsListLock.acquire()
shared.alreadyAttemptedConnectionsList[peer] = 0
shared.alreadyAttemptedConnectionsListLock.release()
timeNodeLastSeen = shared.knownNodes[
self.streamNumber][peer]
if peer.host.find(':') == -1:
address_family = socket.AF_INET
else:
@ -83,7 +81,10 @@ class outgoingSynSender(threading.Thread):
So let us remove the offending address from our knownNodes file.
"""
shared.knownNodesLock.acquire()
del shared.knownNodes[self.streamNumber][peer]
try:
del shared.knownNodes[self.streamNumber][peer]
except:
pass
shared.knownNodesLock.release()
with shared.printLock:
print 'deleting ', peer, 'from shared.knownNodes because it caused a socks.socksocket exception. We must not be 64-bit compatible.'
@ -169,14 +170,24 @@ class outgoingSynSender(threading.Thread):
with shared.printLock:
print 'Could NOT connect to', peer, 'during outgoing attempt.', err
timeLastSeen = shared.knownNodes[
self.streamNumber][peer]
if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure.
shared.knownNodesLock.acquire()
del shared.knownNodes[self.streamNumber][peer]
shared.knownNodesLock.release()
deletedPeer = None
with shared.knownNodesLock:
"""
It is remotely possible that peer is no longer in shared.knownNodes.
This could happen if two outgoingSynSender threads both try to
connect to the same peer, both fail, and then both try to remove
it from shared.knownNodes. This is unlikely because of the
alreadyAttemptedConnectionsList but because we clear that list once
every half hour, it can happen.
"""
if peer in shared.knownNodes[self.streamNumber]:
timeLastSeen = shared.knownNodes[self.streamNumber][peer]
if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure.
del shared.knownNodes[self.streamNumber][peer]
deletedPeer = peer
if deletedPeer:
with shared.printLock:
print 'deleting ', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.'
print 'deleting', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.'
except socks.Socks5AuthError as err:
shared.UISignalQueue.put((
@ -195,14 +206,24 @@ class outgoingSynSender(threading.Thread):
with shared.printLock:
print 'Could NOT connect to', peer, 'during outgoing attempt.', err
timeLastSeen = shared.knownNodes[
self.streamNumber][peer]
if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownNodes data-structure.
shared.knownNodesLock.acquire()
del shared.knownNodes[self.streamNumber][peer]
shared.knownNodesLock.release()
with shared.printLock:
print 'deleting ', peer, 'from knownNodes because it is more than 48 hours old and we could not connect to it.'
deletedPeer = None
with shared.knownNodesLock:
"""
It is remotely possible that peer is no longer in shared.knownNodes.
This could happen if two outgoingSynSender threads both try to
connect to the same peer, both fail, and then both try to remove
it from shared.knownNodes. This is unlikely because of the
alreadyAttemptedConnectionsList but because we clear that list once
every half hour, it can happen.
"""
if peer in shared.knownNodes[self.streamNumber]:
timeLastSeen = shared.knownNodes[self.streamNumber][peer]
if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure.
del shared.knownNodes[self.streamNumber][peer]
deletedPeer = peer
if deletedPeer:
with shared.printLock:
print 'deleting', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.'
except Exception as err:
sys.stderr.write(

View File

@ -65,11 +65,25 @@ class receiveDataThread(threading.Thread):
print 'receiveDataThread starting. ID', str(id(self)) + '. The size of the shared.connectedHostsList is now', len(shared.connectedHostsList)
while True:
if shared.config.getint('bitmessagesettings', 'maxdownloadrate') == 0:
downloadRateLimitBytes = float("inf")
else:
downloadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxdownloadrate') * 1000
with shared.receiveDataLock:
while shared.numberOfBytesReceivedLastSecond >= downloadRateLimitBytes:
if int(time.time()) == shared.lastTimeWeResetBytesReceived:
# If it's still the same second that it was last time then sleep.
time.sleep(0.3)
else:
# It's a new second. Let us clear the shared.numberOfBytesReceivedLastSecond.
shared.lastTimeWeResetBytesReceived = int(time.time())
shared.numberOfBytesReceivedLastSecond = 0
dataLen = len(self.data)
try:
dataRecv = self.sock.recv(4096)
dataRecv = self.sock.recv(1024)
self.data += dataRecv
shared.numberOfBytesReceived += len(dataRecv)
shared.numberOfBytesReceived += len(dataRecv) # for the 'network status' UI tab. The UI clears this value whenever it updates.
shared.numberOfBytesReceivedLastSecond += len(dataRecv) # for the download rate limit
except socket.timeout:
with shared.printLock:
print 'Timeout occurred waiting for data from', self.peer, '. Closing receiveData thread. (ID:', str(id(self)) + ')'
@ -117,7 +131,7 @@ class receiveDataThread(threading.Thread):
if magic != 0xE9BEB4D9:
self.data = ""
return
if payloadLength > 2 ** 18: # 256 KiB
if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message.
logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength)
self.data = self.data[payloadLength + shared.Header.size:]
del magic,command,payloadLength,checksum # we don't need these anymore and better to clean them now before the recursive call rather than after
@ -148,7 +162,9 @@ class receiveDataThread(threading.Thread):
try:
#TODO: Use a dispatcher here
if not self.connectionIsOrWasFullyEstablished:
if command == 'error':
self.recerror(payload)
elif not self.connectionIsOrWasFullyEstablished:
if command == 'version':
self.recversion(payload)
elif command == 'verack':
@ -321,6 +337,37 @@ class receiveDataThread(threading.Thread):
with shared.printLock:
print 'Timing attack mitigation: Sleeping for', sleepTime, 'seconds.'
time.sleep(sleepTime)
def recerror(self, data):
"""
The remote node has been polite enough to send you an error message.
"""
fatalStatus, readPosition = decodeVarint(data[:10])
banTime, banTimeLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += banTimeLength
inventoryVectorLength, inventoryVectorLengthLength = decodeVarint(data[readPosition:readPosition+10])
if inventoryVectorLength > 100:
return
readPosition += inventoryVectorLengthLength
inventoryVector = data[readPosition:readPosition+inventoryVectorLength]
readPosition += inventoryVectorLength
errorTextLength, errorTextLengthLength = decodeVarint(data[readPosition:readPosition+10])
if errorTextLength > 1000:
return
readPosition += errorTextLengthLength
errorText = data[readPosition:readPosition+errorTextLength]
if fatalStatus == 0:
fatalHumanFriendly = 'Warning'
elif fatalStatus == 1:
fatalHumanFriendly = 'Error'
elif fatalStatus == 2:
fatalHumanFriendly = 'Fatal'
message = '%s message received from %s: %s.' % (fatalHumanFriendly, self.peer, errorText)
if inventoryVector:
message += " This concerns object %s" % inventoryVector.encode('hex')
if banTime > 0:
message += " Remote node says that the ban time is %s" % banTime
logger.error(message)
def recobject(self, data):
@ -672,7 +719,20 @@ class receiveDataThread(threading.Thread):
with shared.printLock:
print 'Closing connection to old protocol version', self.remoteProtocolVersion, 'node: ', self.peer
return
# print 'remoteProtocolVersion', self.remoteProtocolVersion
timestamp, = unpack('>Q', data[12:20])
timeOffset = timestamp - int(time.time())
if timeOffset > 3600:
self.sendDataThreadQueue.put((0, 'sendRawData', shared.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.peer, timeOffset))
time.sleep(2)
self.sendDataThreadQueue.put((0, 'shutdown','no data'))
return
if timeOffset < -3600:
self.sendDataThreadQueue.put((0, 'sendRawData', shared.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.peer, timeOffset))
time.sleep(2)
self.sendDataThreadQueue.put((0, 'shutdown','no data'))
return
self.myExternalIP = socket.inet_ntoa(data[40:44])
# print 'myExternalIP', self.myExternalIP
self.remoteNodeIncomingPort, = unpack('>H', data[70:72])
@ -688,7 +748,7 @@ class receiveDataThread(threading.Thread):
self.streamNumber, lengthOfRemoteStreamNumber = decodeVarint(
data[readPosition:])
with shared.printLock:
print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber
print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber, ' time offset:', timeOffset, 'seconds.'
if self.streamNumber != 1:
self.sendDataThreadQueue.put((0, 'shutdown','no data'))

View File

@ -62,9 +62,32 @@ class sendDataThread(threading.Thread):
self.versionSent = 1
def sendBytes(self, data):
self.sock.sendall(data)
shared.numberOfBytesSent += len(data)
self.lastTimeISentData = int(time.time())
if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0:
uploadRateLimitBytes = 999999999 # float("inf") doesn't work
else:
uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000
with shared.sendDataLock:
while data:
while shared.numberOfBytesSentLastSecond >= uploadRateLimitBytes:
if int(time.time()) == shared.lastTimeWeResetBytesSent:
time.sleep(0.3)
else:
# It's a new second. Let us clear the shared.numberOfBytesSentLastSecond
shared.lastTimeWeResetBytesSent = int(time.time())
shared.numberOfBytesSentLastSecond = 0
# If the user raises or lowers the uploadRateLimit then we should make use of
# the new setting. If we are hitting the limit then we'll check here about
# once per second.
if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0:
uploadRateLimitBytes = 999999999 # float("inf") doesn't work
else:
uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000
numberOfBytesWeMaySend = uploadRateLimitBytes - shared.numberOfBytesSentLastSecond
self.sock.sendall(data[:numberOfBytesWeMaySend])
shared.numberOfBytesSent += len(data[:numberOfBytesWeMaySend]) # used for the 'network status' tab in the UI
shared.numberOfBytesSentLastSecond += len(data[:numberOfBytesWeMaySend])
self.lastTimeISentData = int(time.time())
data = data[numberOfBytesWeMaySend:]
def run(self):

View File

@ -341,6 +341,8 @@ class sqlThread(threading.Thread):
shared.config.set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000)))
except:
continue
shared.config.set('bitmessagesettings', 'maxdownloadrate', '0')
shared.config.set('bitmessagesettings', 'maxuploadrate', '0')
shared.config.set('bitmessagesettings', 'settingsversion', '10')
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)

View File

@ -102,6 +102,8 @@ def loadConfig():
shared.config.set('bitmessagesettings', 'useidenticons', 'True')
shared.config.set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons
shared.config.set('bitmessagesettings', 'replybelow', 'False')
shared.config.set('bitmessagesettings', 'maxdownloadrate', '0')
shared.config.set('bitmessagesettings', 'maxuploadrate', '0')
#start:UI setting to stop trying to send messages after X days/months
shared.config.set(

View File

@ -70,8 +70,14 @@ numberOfMessagesProcessed = 0
numberOfBroadcastsProcessed = 0
numberOfPubkeysProcessed = 0
numberOfInventoryLookupsPerformed = 0
numberOfBytesReceived = 0
numberOfBytesSent = 0
numberOfBytesReceived = 0 # Used for the 'network status' page
numberOfBytesSent = 0 # Used for the 'network status' page
numberOfBytesReceivedLastSecond = 0 # used for the bandwidth rate limit
numberOfBytesSentLastSecond = 0 # used for the bandwidth rate limit
lastTimeWeResetBytesReceived = 0 # used for the bandwidth rate limit
lastTimeWeResetBytesSent = 0 # used for the bandwidth rate limit
sendDataLock = threading.Lock() # used for the bandwidth rate limit
receiveDataLock = threading.Lock() # used for the bandwidth rate limit
daemon = False
inventorySets = {} # key = streamNumer, value = a set which holds the inventory object hashes that we are aware of. This is used whenever we receive an inv message from a peer to check to see what items are new to us. We don't delete things out of it; instead, the singleCleaner thread clears and refills it every couple hours.
needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually.
@ -159,6 +165,15 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber):
return CreatePacket('version', payload)
def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''):
payload = encodeVarint(fatal)
payload += encodeVarint(banTime)
payload += encodeVarint(len(inventoryVector))
payload += inventoryVector
payload += encodeVarint(len(errorText))
payload += errorText
return CreatePacket('error', payload)
def lookupAppdataFolder():
APPNAME = "PyBitmessage"
if "BITMESSAGE_HOME" in environ:
@ -586,11 +601,14 @@ Peer = collections.namedtuple('Peer', ['host', 'port'])
def checkAndShareObjectWithPeers(data):
"""
Function is called after either receiving an object off of the wire
This function is called after either receiving an object off of the wire
or after receiving one as ackdata.
Returns the length of time that we should reserve to process this message
if we are receiving it off of the wire.
"""
if len(data) > 2 ** 18:
logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data))
return
# Let us check to make sure that the proof of work is sufficient.
if not isProofOfWorkSufficient(data):
logger.info('Proof of work is insufficient.')