@ -18,28 +18,12 @@ useVeryEasyProofOfWorkForTesting = False #If you set this to True while on the n
encryptedBroadcastSwitchoverTime=1369735200
importsys
importConfigParser
try:
fromPyQt4.QtCoreimport*
fromPyQt4.QtGuiimport*
exceptException,err:
print'PyBitmessage requires PyQt. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).'
print'Error message:',err
sys.exit()
frombitmessageuiimport*
importConfigParser
fromnewaddressdialogimport*
fromnewsubscriptiondialogimport*
fromregenerateaddressesimport*
fromspecialaddressbehaviorimport*
fromsettingsimport*
fromaboutimport*
fromhelpimport*
fromiconglossaryimport*
fromaddressesimport*
importQueue
fromaddressesimport*
#from shared import *
importshared
fromdefaultKnownNodesimport*
importtime
importsocket
@ -49,9 +33,8 @@ from struct import *
importpickle
importrandom
importsqlite3
importthreading#used for the locks, not for the threads
importthreading
fromtimeimportstrftime,localtime,gmtime
importos
importshutil#used for moving the messages.dat file
importstring
importsocks
@ -65,14 +48,6 @@ from SimpleXMLRPCServer import *
importjson
fromsubprocessimportcall#used when the API must execute an outside program
classiconGlossaryDialog(QtGui.QDialog):
def__init__(self,parent):
QtGui.QWidget.__init__(self,parent)
self.ui=Ui_iconGlossaryDialog()
self.ui.setupUi(self)
self.parent=parent
self.ui.labelPortNumber.setText('You are using TCP port '+str(config.getint('bitmessagesettings','port'))+'. (This can be changed in the settings).')
#Clear out the alreadyAttemptedConnectionsList every half hour so that this program will again attempt a connection to any nodes, even ones it has already tried.
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.
knownNodesLock.acquire()
del knownNodes[self.streamNumber][HOST]
knownNodesLock.release()
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(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()
delshared.knownNodes[self.streamNumber][HOST]
shared.knownNodesLock.release()
print'deleting ',HOST,'from shared.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.
if(int(time.time())-timeLastSeen)>172800andlen(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()
delshared.knownNodes[self.streamNumber][HOST]
shared.knownNodesLock.release()
print'deleting ',HOST,'from knownNodes because it is more than 48 hours old and we could not connect to it.'
exceptException,err:
sys.stderr.write('An exception has occurred in the outgoingSynSender thread that was not caught by other exception types: %s\n'%err)
@ -210,12 +185,14 @@ class singleListener(threading.Thread):
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.
while config.get('bitmessagesettings','socksproxytype')[0:5]=='SOCKS':
@ -225,7 +202,7 @@ class singleListener(threading.Thread):
whileTrue:
#We don't want to accept incoming connections if the user is using a SOCKS proxy. If the user eventually select proxy 'none' then this will start listening for connections.
while config.get('bitmessagesettings','socksproxytype')[0:5]=='SOCKS':
#Users are finding that if they run more than one node in the same network (thus with the same public IP), they can not connect with the second node. This is because this section of code won't accept the connection from the same IP. This problem will go away when the Bitmessage network grows beyond being tiny but in the mean time I'll comment out this code section.
@ -238,9 +215,9 @@ class singleListener(threading.Thread):
ifself.connectionIsOrWasFullyEstablished:#We don't want to decrement the number of connections and show the result if we never incremented it in the first place (which we only do if the connection is fully established- meaning that both nodes accepted each other's version packets.)
print'Updating network status tab with current connections count:',connectionsCount[self.streamNumber]
printLock.release()
shared.printLock.release()
connectionsCountLock.release()
try:
delconnectedHostsList[self.HOST]
exceptException,err:
print'Could not delete',self.HOST,'from connectedHostsList.',err
printLock.acquire()
shared.printLock.acquire()
print'The size of the connectedHostsList is now:',len(connectedHostsList)
printLock.release()
shared.printLock.release()
defprocessData(self):
globalverbose
#if verbose >= 3:
#printLock.acquire()
#shared.printLock.acquire()
#print 'self.data is currently ', repr(self.data)
#printLock.release()
#shared.printLock.release()
iflen(self.data)<20:#if so little of the data has arrived that we can't even unpack the payload length
pass
elifself.data[0:4]!='\xe9\xbe\xb4\xd9':
ifverbose>=1:
printLock.acquire()
shared.printLock.acquire()
sys.stderr.write('The magic bytes were not correct. First 40 bytes of data: %s\n'%repr(self.data[0:40]))
print'self.data:',self.data.encode('hex')
printLock.release()
shared.printLock.release()
self.data=""
else:
self.payloadLength,=unpack('>L',self.data[16:20])
@ -356,14 +333,14 @@ class receiveDataThread(threading.Thread):
#print 'message checksum is correct'
#The time we've last seen this node is obviously right now since we just received valid data from it. So update the knownNodes list so that other peers can be made aware of its existance.
ifself.initiatedConnection:#The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port).
ifself.payloadLength<=180000000:#If the size of the message is greater than 180MB, ignore it. (I get memory errors when processing messages much larger than this though it is concievable that this value will have to be lowered if some systems are less tolarant of large messages.)
delself.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash]#It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway.
print'(concerning',self.HOST+')','number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now',len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
print'(concerning',self.HOST+')','number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now',len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
print'(concerning',self.HOST+')','number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now',len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
printLock.release()
shared.printLock.release()
iflen(self.ackDataThatWeHaveYetToSend)>0:
self.data=self.ackDataThatWeHaveYetToSend.pop()
self.processData()
@ -456,30 +433,30 @@ class receiveDataThread(threading.Thread):
sqlSubmitQueue.put('''SELECT hash FROM inventory WHERE ((receivedtime>? and objecttype<>'pubkey') or (receivedtime>? and objecttype='pubkey')) and streamnumber=?''')
sqlSubmitQueue.put(t)
queryreturn=sqlReturnQueue.get()
sqlLock.release()
shared.sqlSubmitQueue.put('''SELECT hash FROM inventory WHERE ((receivedtime>? and objecttype<>'pubkey') or (receivedtime>? and objecttype='pubkey')) and streamnumber=?''')
print'Not including an object hash in a big inv message because the remote node is already aware of it.'#This line is here to check that this feature is working.
printLock.release()
shared.printLock.release()
#We also have messages in our inventory in memory (which is a python dictionary). Let's fetch those too.
print'Not including an object hash in a big inv message because the remote node is already aware of it.'#This line is here to check that this feature is working.
printLock.release()
shared.printLock.release()
numberOfObjectsInInvMessage=0
payload=''
#Now let us start appending all of these hashes together. They will be sent out in a big inv message to our new peer.
@ -535,9 +512,9 @@ class receiveDataThread(threading.Thread):
print'Sending huge inv message with',numberOfObjects,'objects to just this one peer'
printLock.release()
shared.printLock.release()
self.sock.sendall(headerData+payload)
#We have received a broadcast message
@ -574,23 +551,23 @@ class receiveDataThread(threading.Thread):
print'The stream number encoded in this broadcast message ('+str(streamNumber)+') does not match the stream number on which it was received. Ignoring it.'
return
inventoryLock.acquire()
shared.inventoryLock.acquire()
self.inventoryHash=calculateInventoryHash(data)
ifself.inventoryHashin inventory:
ifself.inventoryHashinshared.inventory:
print'We have already received this broadcast object. Ignoring.'
inventoryLock.release()
shared.inventoryLock.release()
return
elifisInSqlInventory(self.inventoryHash):
print'We have already received this broadcast object (it is stored on disk in the SQL inventory). Ignoring it.'
inventoryLock.release()
shared.inventoryLock.release()
return
#It is valid so far. Let's let our peers know about it.
self.processbroadcast(readPosition,data)#When this function returns, we will have either successfully processed this broadcast because we are interested in it, ignored it because we aren't interested in it, or found problem with the broadcast that warranted ignoring it.
@ -608,13 +585,13 @@ class receiveDataThread(threading.Thread):
print'Time spent deciding that we are not interested in this v1 broadcast:',time.time()-self.messageProcessingStartTime
printLock.release()
shared.printLock.release()
return
#At this point, this message claims to be from sendersHash and we are interested in it. We still have to hash the public key to make sure it is truly the key that matches the hash, and also check the signiture.
readPosition+=20
@ -680,18 +657,18 @@ class receiveDataThread(threading.Thread):
#Let's store the public key in case we want to reply to this person.
#We don't have the correct nonce or time (which would let us send out a pubkey message) so we'll just fill it with 1's. We won't be able to send this pubkey to others (without doing the proof of work ourselves, which this program is programmed to not do.)
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlSubmitQueue.put('commit')
sqlLock.release()
workerQueue.put(('newpubkey',(sendersAddressVersion,sendersStream,ripe.digest())))#This will check to see whether we happen to be awaiting this pubkey in order to send a message. If we are, it will do the POW and send it.
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
shared.workerQueue.put(('newpubkey',(sendersAddressVersion,sendersStream,ripe.digest())))#This will check to see whether we happen to be awaiting this pubkey in order to send a message. If we are, it will do the POW and send it.
toRipe=key#This is the RIPE hash of the sender's pubkey. We need this below to compare to the RIPE hash of the sender's address to verify that it was encrypted by with their key rather than some other key.
@ -750,9 +727,9 @@ class receiveDataThread(threading.Thread):
#print 'cryptorObject.decrypt Exception:', err
ifnotinitialDecryptionSuccessful:
#This is not a broadcast I am interested in.
printLock.acquire()
shared.printLock.acquire()
print'Length of time program spent failing to decrypt this v2 broadcast:',time.time()-self.messageProcessingStartTime,'seconds.'
printLock.release()
shared.printLock.release()
return
#At this point this is a broadcast I have decrypted and thus am interested in.
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlSubmitQueue.put('commit')
sqlLock.release()
workerQueue.put(('newpubkey',(sendersAddressVersion,sendersStream,ripe.digest())))#This will check to see whether we happen to be awaiting this pubkey in order to send a message. If we are, it will do the POW and send it.
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
shared.workerQueue.put(('newpubkey',(sendersAddressVersion,sendersStream,ripe.digest())))#This will check to see whether we happen to be awaiting this pubkey in order to send a message. If we are, it will do the POW and send it.
self.processmsg(readPosition,data)#When this function returns, we will have either successfully processed the message bound for us, ignored it because it isn't bound for us, or found problem with the message that warranted ignoring it.
@ -931,13 +908,13 @@ class receiveDataThread(threading.Thread):
sqlSubmitQueue.put('UPDATE sent SET status=? WHERE ackdata=?')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlSubmitQueue.put('commit')
sqlLock.release()
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('UPDATE sent SET status=? WHERE ackdata=?')
shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
#self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),encryptedData[readPosition:],'Acknowledgement of the message received just now.')
UISignalQueue.put(('updateSentItemStatusByAckdata',(encryptedData[readPosition:],'Acknowledgement of the message received just now.')))
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(encryptedData[readPosition:],'Acknowledgement of the message received just now.')))
return
else:
printLock.acquire()
shared.printLock.acquire()
print'This was NOT an acknowledgement bound for me.'
@ -1050,9 +1027,9 @@ class receiveDataThread(threading.Thread):
exceptException,err:
print'ECDSA verify failed',err
return
printLock.acquire()
shared.printLock.acquire()
print'As a matter of intellectual curiosity, here is the Bitcoin address associated with the keys owned by the other person:',calculateBitcoinAddressFromPubkey(pubSigningKey),' ..and here is the testnet address:',calculateTestnetAddressFromPubkey(pubSigningKey),'. The other person must take their private signing key from Bitmessage and import it into Bitcoin (or a service like Blockchain.info) for it to be of any use. Do not use this unless you know what you are doing.'
printLock.release()
shared.printLock.release()
#calculate the fromRipe.
sha=hashlib.new('sha512')
sha.update(pubSigningKey+pubEncryptionKey)
@ -1060,42 +1037,42 @@ class receiveDataThread(threading.Thread):
ripe.update(sha.digest())
#Let's store the public key in case we want to reply to this person.
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlSubmitQueue.put('commit')
sqlLock.release()
workerQueue.put(('newpubkey',(sendersAddressVersionNumber,sendersStreamNumber,ripe.digest())))#This will check to see whether we happen to be awaiting this pubkey in order to send a message. If we are, it will do the POW and send it.
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
shared.sqlSubmitQueue.put(t)
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
shared.workerQueue.put(('newpubkey',(sendersAddressVersionNumber,sendersStreamNumber,ripe.digest())))#This will check to see whether we happen to be awaiting this pubkey in order to send a message. If we are, it will do the POW and send it.
#If this message is bound for one of my version 3 addresses (or higher), then we must check to make sure it meets our demanded proof of work requirement.
ifdecodeAddress(toAddress)[1]>=3:#If the toAddress version number is 3 or higher:
ifnot isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress):#If I'm not friendly with this person:
@ -1157,17 +1134,17 @@ class receiveDataThread(threading.Thread):
ackdata=OpenSSL.rand(32)#We don't actually need the ackdata for acknowledgement since this is a broadcast message but we can use it to update the user interface when the POW is done generating.