#Right now, PyBitmessage only support connecting to stream 1. It doesn't yet contain logic to expand into further streams.
softwareVersion='0.1.3'
softwareVersion='0.1.4'
verbose=2
maximumAgeOfAnObjectThatIAmWillingToAccept=216000#Equals two days and 12 hours.
lengthOfTimeToLeaveObjectsInInventory=237600#Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice.
@ -44,10 +44,10 @@ import random
importsqlite3
importthreading#used for the locks, not for the threads
importcStringIO
#from email.parser import Parser
fromtimeimportstrftime,localtime
importos
importstring
importsocks
#For each stream to which we connect, one outgoingSynSender thread will exist and will create 8 connections with peers.
classoutgoingSynSender(QThread):
@ -79,10 +79,42 @@ class outgoingSynSender(QThread):
if(int(time.time())-timeLastSeen)>172800:# for nodes older than 48 hours old, delete from the knownNodes data-structure.
iflen(knownNodes[self.streamNumber])>1000:#as long as we have more than 1000 hosts in our list
if(int(time.time())-timeLastSeen)>172800andlen(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.
delknownNodes[self.streamNumber][HOST]
print'deleting ',HOST,'from knownNodes because it is more than 48 hours old and we could not connect to it.'
if(int(time.time())-timeLastSeen)>172800andlen(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.
delknownNodes[self.streamNumber][HOST]
print'deleting ',HOST,'from knownNodes because it is more than 48 hours old and we could not connect to it.'
exceptException,err:
print'An exception has occurred in the outgoingSynSender thread that was not caught by other exception types:',err
time.sleep(1)
#Only one singleListener thread will ever exist. It creates the receiveDataThread and sendDataThread for each incoming connection. Note that it cannot set the stream number because it is not known yet- the other node will have to tell us its stream number in a version message. If we don't care about their stream, we will close the connection (within the recversion function of the recieveData thread)
@ -114,6 +166,9 @@ class singleListener(QThread):
defrun(self):
#We don't want to accept incoming connections if the user is using a SOCKS proxy. If they eventually select proxy 'none' then this will start listening for connections.
self.incomingConnectionList=[]#This list isn't used for anything. The reason it exists is because receiveData threads expect that a list be passed to them. They expect this because the outgoingSynSender thread DOES use a similar list to keep track of the number of outgoing connections it has created.
whileTrue:
#for i in range(0,1): #uncomment this line and comment the line above this to accept only one connection.
rd=receiveDataThread()
#We don't want to accept incoming connections if the user is using a SOCKS proxy. If they eventually select proxy 'none' then this will start listening for connections.
#I think that the only way an exception could occur here is if we connect to ourselves because it would try to delete the same IP from connectedHostsList twice.
print'Could not delete',self.HOST,'from connectedHostsList.',err
defprocessData(self):
globalverbose
@ -279,10 +340,10 @@ class receiveDataThread(QThread):
print'The stream number encoded in this msg ('+streamNumberAsClaimedByMsg+') message does not match the stream number on which it was received. Ignoring it.'
return
readPosition+=streamNumberAsClaimedByMsgLength
inventoryLock.acquire()
ifinventoryHashininventory:
print'We have already received this msg message. Ignoring.'
inventoryLock.release()
return
elifisInSqlInventory(inventoryHash):
print'We have already received this msg message (it is stored on disk in the SQL inventory). Ignoring it.'
print'The stream number encoded in this msg ('+streamNumberAsClaimedByMsg+') message does not match the stream number on which it was received. Ignoring it.'
return
readPosition+=streamNumberAsClaimedByMsgLength
#This msg message is valid. Let's let our peers know about it.
print'(For pubkey message) Found proof of work',trialValue,'Nonce:',nonce
payload=pack('>Q',nonce)+payload
t=(self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],True,payload,int(time.time())+1209600)#after two weeks (1,209,600 seconds), we may remove our own pub key from our database. It will be regenerated and put back in the database if it is requested.
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
queryreturn=sqlReturnQueue.get()
#print 'queryreturn', queryreturn
ifqueryreturn==[]:
print'pubkey request is for me but the pubkey is not in our database of pubkeys. Making it.'
payload='\x00\x00\x00\x01'#bitfield of features supported by me (see the wiki).
print'(For pubkey message) Found proof of work',trialValue,'Nonce:',nonce
payload=pack('>Q',nonce)+payload
t=(self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],True,payload,int(time.time())+1209600)#after two weeks (1,209,600 seconds), we may remove our own pub key from our database. It will be regenerated and put back in the database if it is requested.
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
#Now that we have the key either from getting it earlier or making it and storing it ourselves...
timeSomeoneElseReceivedMessageFromThisNode,=unpack('>I',self.data[24+lengthOfNumberOfAddresses+(34*i):28+lengthOfNumberOfAddresses+(34*i)])#This is the 'time' value in the received addr message.
iflen(knownNodes[recaddrStream])<20000andtimeSomeoneElseReceivedMessageFromThisNode>(int(time.time())-10800)andtimeSomeoneElseReceivedMessageFromThisNode<(int(time.time())+10800):#If we have more than 20000 nodes in our list already then just forget about adding more. Also, make sure that the time that someone else received a message from this node is within three hours from now.
@ -1187,7 +1263,7 @@ class receiveDataThread(QThread):
addrsInMyStream={}
addrsInChildStreamLeft={}
addrsInChildStreamRight={}
print'knownNodes',knownNodes
#print 'knownNodes', knownNodes
#We are going to share a maximum number of 1000 addrs with our peer. 500 from this stream, 250 from the left child stream, and 250 from the right child stream.
@ -1550,7 +1626,8 @@ class sqlThread(QThread):
self.cur.execute('''DELETE FROM pubkeys WHERE hash='1234'''')
self.conn.commit()
iftransmitdata=='':
sys.stderr.write('Problem: The version of SQLite you have cannot store Null values. Please download and install the latest revision of your version of Python (for example, the latest Python 2.7 revision) and try again. Exiting.\n')
sys.stderr.write('Problem: The version of SQLite you have cannot store Null values. Please download and install the latest revision of your version of Python (for example, the latest Python 2.7 revision) and try again.\n')
sys.stderr.write('PyBitmessage will now exist very abruptly. You may now see threading errors related to this abrupt exit but the problem you need to solve is related to SQLite.\n\n')
sys.exit()
exceptException,err:
printerr
@ -2015,6 +2092,7 @@ class addressGenerator(QThread):
config.add_section(address)
config.set(address,'label',self.label)
config.set(address,'enabled','true')
config.set(address,'decoy','false')
config.set(address,'n',str(privkey['n']))
config.set(address,'e',str(privkey['e']))
config.set(address,'d',str(privkey['d']))
@ -2027,57 +2105,6 @@ class addressGenerator(QThread):
self.ui.labelSettingsNote.setText('Options have been disabled because they either arn\'t applicable or because they haven\'t yet been implimented for your operating system.')
elif'linux'insys.platform:
pass
self.ui.checkBoxStartOnLogon.setDisabled(True)
self.ui.labelSettingsNote.setText('Options have been disabled because they either arn\'t applicable or because they haven\'t yet been implimented for your operating system.')
@ -2182,6 +2252,9 @@ class MyForm(QtGui.QMainWindow):
menu=QtGui.QMenu()
self.exitAction=menu.addAction("Exit",self.close)
self.trayIcon.setContextMenu(menu)
#I'm currently under the impression that Mac users have different expectations for the tray icon. They don't necessairly expect it to open the main window when clicked and they still expect a program showing a tray icon to also be in the dock.
reply=QtGui.QMessageBox.question(self,'Open keys.dat?','You may manage your keys by editing the keys.dat file stored in\n'+appdata+'\nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)',QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
ifreply==QtGui.QMessageBox.Yes:
self.openKeysFile()
else:
pass
if'darwin'insys.platformor'linux'insys.platform:
reply=QtGui.QMessageBox.information(self,'keys.dat?','You may manage your keys by editing the keys.dat file stored in\n'+appdata+'\nIt is important that you back up this file.',QMessageBox.Ok)
elifsys.platform=='win32'orsys.platform=='win64':
reply=QtGui.QMessageBox.question(self,'Open keys.dat?','You may manage your keys by editing the keys.dat file stored in\n'+appdata+'\nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)',QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
ifreply==QtGui.QMessageBox.Yes:
self.openKeysFile()
else:
pass
defopenKeysFile(self):
if'linux'insys.platform:
@ -2506,13 +2581,13 @@ class MyForm(QtGui.QMainWindow):
QMessageBox.about(self,"Restart","Bitmessage will use your proxy from now on now but you may want to manually restart Bitmessage now to close existing connections.")
connectionsCount={}#Used for the 'network status' tab.
connectionsCountLock=threading.Lock()
inventoryLock=threading.Lock()#Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual)
connectedHostsList={}#List of hosts to which we are connected. Used to guarantee that the outgoingSynSender thread won't connect to the same remote node twice.
neededPubkeys={}
@ -3464,7 +3562,7 @@ if __name__ == "__main__":
print'Could not find home folder, please report this message and your OS X version to the BitMessage Github.'
self.label_2.setText(QtGui.QApplication.translate("iconGlossaryDialog","You have no connections with other peers. ",None,QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("iconGlossaryDialog","You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn\'t configured to foward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node.",None,QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("iconGlossaryDialog","You do have connections with other peers and your firewall is correctly configured.",None,QtGui.QApplication.UnicodeUTF8))
self.labelPortNumber.setText(QtGui.QApplication.translate("iconGlossaryDialog","You are using TCP port ?. (This can be changed in the settings).",None,QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("iconGlossaryDialog","You do have connections with other peers and your firewall is correctly configured.",None,QtGui.QApplication.UnicodeUTF8))
<string>You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn't configured to foward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node.</string>
<string>You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn't configured to foward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node.</string>