Skip to content
Merged

V0.6 #11

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Bitmessage is a P2P communications protocol used to send encrypted messages to
another person or to many subscribers. It is decentralized and trustless,
meaning that you need-not inherently trust any entities like root certificate
authorities. It uses strong authentication, which means that the sender of a
message cannot be spoofed, and it aims to hide "non-content" data, like the
message cannot be spoofed, and it aims to hide metadata, like the
sender and receiver of messages, from passive eavesdroppers like those running
warrantless wiretapping programs.

Expand Down
60 changes: 60 additions & 0 deletions packages/collectd/pybitmessagestatus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python2.7

import collectd
import json
import xmlrpclib

pybmurl = ""
api = ""

def init_callback():
global api
api = xmlrpclib.ServerProxy(pybmurl)
collectd.info('pybitmessagestatus.py init done')

def config_callback(ObjConfiguration):
global pybmurl
apiUsername = ""
apiPassword = ""
apiInterface = "127.0.0.1"
apiPort = 8445
for node in ObjConfiguration.children:
key = node.key.lower()
if key.lower() == "apiusername" and node.values:
apiUsername = node.values[0]
elif key.lower() == "apipassword" and node.values:
apiPassword = node.values[0]
elif key.lower() == "apiinterface" and node.values:
apiInterface = node.values[0]
elif key.lower() == "apiport" and node.values:
apiPort = node.values[0]
pybmurl = "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface+ ":" + str(int(apiPort)) + "/"
collectd.info('pybitmessagestatus.py config done')

def read_callback():
try:
clientStatus = json.loads(api.clientStatus())
except:
collectd.info("Exception loading or parsing JSON")
return

for i in ["networkConnections", "numberOfPubkeysProcessed", "numberOfMessagesProcessed", "numberOfBroadcastsProcessed"]:
metric = collectd.Values()
metric.plugin = "pybitmessagestatus"
if i[0:6] == "number":
metric.type = 'counter'
else:
metric.type = 'gauge'
metric.type_instance = i.lower()
try:
metric.values = [clientStatus[i]]
except:
collectd.info("Value for %s missing" % (i))
metric.dispatch()

if __name__ == "__main__":
main()
else:
collectd.register_init(init_callback)
collectd.register_config(config_callback)
collectd.register_read(read_callback)
18 changes: 18 additions & 0 deletions packages/systemd/bitmessage.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[Unit]
Description=Bitmessage Daemon
After=network.target auditd.service

[Service]
ExecStart=/usr/bin/python2 /usr/src/PyBitmessage/src/bitmessagemain.py
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
Type=forking
PIDFile=/var/lib/bitmessage/.config/PyBitmessage/singleton.lock
User=bitmessage
Group=nogroup
WorkingDirectory=/var/lib/bitmessage
Environment="HOME=/var/lib/bitmessage"

[Install]
WantedBy=multi-user.target
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def run(self):
'qrcode': ['qrcode'],
'pyopencl': ['pyopencl'],
'notify2': ['notify2'],
'sound:platform_system=="Windows"': ['winsound']
'sound;platform_system=="Windows"': ['winsound']
},
classifiers=[
"License :: OSI Approved :: MIT License"
Expand Down
17 changes: 17 additions & 0 deletions src/bitmessagemain.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,21 @@ def start(self):
sleep(1)

def daemonize(self):
grandfatherPid = os.getpid()
parentPid = None
try:
if os.fork():
# unlock
shared.thisapp.cleanup()
# wait until grandchild ready
while True:
sleep(1)
os._exit(0)
except AttributeError:
# fork not implemented
pass
else:
parentPid = os.getpid()
shared.thisapp.lock() # relock
os.umask(0)
try:
Expand All @@ -358,6 +366,11 @@ def daemonize(self):
pass
try:
if os.fork():
# unlock
shared.thisapp.cleanup()
# wait until child ready
while True:
sleep(1)
os._exit(0)
except AttributeError:
# fork not implemented
Expand All @@ -374,6 +387,10 @@ def daemonize(self):
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
if parentPid:
# signal ready
os.kill(parentPid, signal.SIGTERM)
os.kill(grandfatherPid, signal.SIGTERM)

def setSignalHandler(self):
signal.signal(signal.SIGINT, helper_generic.signal_handler)
Expand Down
10 changes: 5 additions & 5 deletions src/bitmessageqt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
import shutdown
import state
from statusbar import BMStatusBar
import throttle
from network.asyncore_pollchoose import set_rates
from version import softwareVersion
import sound

Expand Down Expand Up @@ -2288,16 +2288,16 @@ def click_actionSettings(self):
int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text()))))
BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text()))))
except:
except ValueError:
QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate(
"MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed."))
else:
set_rates(BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"),
BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate"))

BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', str(
int(float(self.settingsDialogInstance.ui.lineEditMaxOutboundConnections.text()))))

throttle.SendThrottle().resetLimit()
throttle.ReceiveThrottle().resetLimit()

BMConfigParser().set('bitmessagesettings', 'namecoinrpctype',
self.settingsDialogInstance.getNamecoinType())
BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str(
Expand Down
2 changes: 1 addition & 1 deletion src/helper_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def signal_handler(signal, frame):
raise SystemExit
if "PoolWorker" in current_process().name:
raise SystemExit
if current_thread().name != "PyBitmessage":
if current_thread().name not in ("PyBitmessage", "MainThread"):
return
logger.error("Got signal %i", signal)
if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'):
Expand Down
4 changes: 2 additions & 2 deletions src/network/advanceddispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ def set_state(self, state, length=0, expectBytes=0):
def writable(self):
self.uploadChunk = AdvancedDispatcher._buf_len
if asyncore.maxUploadRate > 0:
self.uploadChunk = asyncore.uploadBucket
self.uploadChunk = int(asyncore.uploadBucket)
self.uploadChunk = min(self.uploadChunk, len(self.write_buf))
return asyncore.dispatcher.writable(self) and \
(self.connecting or (self.connected and self.uploadChunk > 0))

def readable(self):
self.downloadChunk = AdvancedDispatcher._buf_len
if asyncore.maxDownloadRate > 0:
self.downloadChunk = asyncore.downloadBucket
self.downloadChunk = int(asyncore.downloadBucket)
try:
if self.expectBytes > 0 and not self.fullyEstablished:
self.downloadChunk = min(self.downloadChunk, self.expectBytes - len(self.read_buf))
Expand Down
22 changes: 16 additions & 6 deletions src/network/asyncore_pollchoose.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class ExitNow(Exception):
sentBytes = 0

def read(obj):
if not can_receive():
return
try:
obj.handle_read_event()
except _reraised_exceptions:
Expand All @@ -120,6 +122,8 @@ def read(obj):
obj.handle_error()

def write(obj):
if not can_send():
return
try:
obj.handle_write_event()
except _reraised_exceptions:
Expand All @@ -129,19 +133,25 @@ def write(obj):

def set_rates(download, upload):
global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp
maxDownloadRate = float(download)
maxUploadRate = float(upload)
maxDownloadRate = float(download) * 1024
maxUploadRate = float(upload) * 1024
downloadBucket = maxDownloadRate
uploadBucket = maxUploadRate
downloadTimestamp = time.time()
uploadTimestamp = time.time()

def can_receive():
return maxDownloadRate == 0 or downloadBucket > 0

def can_send():
return maxUploadRate == 0 or uploadBucket > 0

def update_received(download=0):
global receivedBytes, downloadBucket, downloadTimestamp
currentTimestamp = time.time()
receivedBytes += download
if maxDownloadRate > 0:
bucketIncrease = int(maxDownloadRate * (currentTimestamp - downloadTimestamp))
bucketIncrease = maxDownloadRate * (currentTimestamp - downloadTimestamp)
downloadBucket += bucketIncrease
if downloadBucket > maxDownloadRate:
downloadBucket = int(maxDownloadRate)
Expand All @@ -153,7 +163,7 @@ def update_sent(upload=0):
currentTimestamp = time.time()
sentBytes += upload
if maxUploadRate > 0:
bucketIncrease = int(maxUploadRate * (currentTimestamp - uploadTimestamp))
bucketIncrease = maxUploadRate * (currentTimestamp - uploadTimestamp)
uploadBucket += bucketIncrease
if uploadBucket > maxUploadRate:
uploadBucket = int(maxUploadRate)
Expand All @@ -170,9 +180,9 @@ def _exception(obj):

def readwrite(obj, flags):
try:
if flags & select.POLLIN:
if flags & select.POLLIN and can_receive():
obj.handle_read_event()
if flags & select.POLLOUT:
if flags & select.POLLOUT and can_send():
obj.handle_write_event()
if flags & select.POLLPRI:
obj.handle_expt_event()
Expand Down
17 changes: 11 additions & 6 deletions src/network/bmobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,28 @@
import protocol
import state

class BMObjectInsufficientPOWError(Exception): pass
class BMObjectInsufficientPOWError(Exception):
errorCodes = ("Insufficient proof of work")


class BMObjectInvalidDataError(Exception): pass
class BMObjectInvalidDataError(Exception):
errorCodes = ("Data invalid")


class BMObjectExpiredError(Exception): pass
class BMObjectExpiredError(Exception):
errorCodes = ("Object expired")


class BMObjectUnwantedStreamError(Exception): pass
class BMObjectUnwantedStreamError(Exception):
errorCodes = ("Object in unwanted stream")


class BMObjectInvalidError(Exception): pass
class BMObjectInvalidError(Exception):
errorCodes = ("Invalid object")


class BMObjectAlreadyHaveError(Exception):
pass
errorCodes = ("Already have this object")


class BMObject(object):
Expand Down
23 changes: 20 additions & 3 deletions src/network/bmproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
import state
import protocol

class BMProtoError(ProxyError): pass
class BMProtoError(ProxyError):
errorCodes = ("Protocol error")


class BMProtoInsufficientDataError(BMProtoError): pass
class BMProtoInsufficientDataError(BMProtoError):
errorCodes = ("Insufficient data")


class BMProtoExcessiveDataError(BMProtoError): pass
class BMProtoExcessiveDataError(BMProtoError):
errorCodes = ("Too much data")


class BMProto(AdvancedDispatcher, ObjectTracker):
Expand Down Expand Up @@ -494,6 +497,20 @@ def peerValidityChecks(self):
return False
except:
pass
if not self.isOutbound:
# 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"):
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))
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."))
Expand Down
18 changes: 12 additions & 6 deletions src/network/connectionpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
class BMConnectionPool(object):
def __init__(self):
asyncore.set_rates(
BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate") * 1024,
BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate") * 1024)
BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"),
BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate"))
self.outboundConnections = {}
self.inboundConnections = {}
self.listeningSockets = {}
Expand Down Expand Up @@ -65,12 +65,18 @@ def connectToStream(self, streamNumber):
def getConnectionByAddr(self, addr):
if addr in self.inboundConnections:
return self.inboundConnections[addr]
if addr.host in self.inboundConnections:
return self.inboundConnections[addr.host]
try:
if addr.host in self.inboundConnections:
return self.inboundConnections[addr.host]
except AttributeError:
pass
if addr in self.outboundConnections:
return self.outboundConnections[addr]
if addr.host in self.udpSockets:
return self.udpSockets[addr.host]
try:
if addr.host in self.udpSockets:
return self.udpSockets[addr.host]
except AttributeError:
pass
raise KeyError

def isAlreadyConnected(self, nodeid):
Expand Down
Loading