def run(self): while not state.shutdown: chunk = [] while True: # Dandelion fluff trigger by expiration Dandelion().expire() try: data = invQueue.get(False) chunk.append((data[0], data[1])) # locally generated if len(data) == 2 or data[2] is None: self.handleLocallyGenerated(data[0], data[1]) except Queue.Empty: break if chunk: for connection in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): fluffs = [] stems = [] for inv in chunk: if inv[0] not in connection.streams: continue try: with connection.objectsNewToThemLock: del connection.objectsNewToThem[inv[1]] except KeyError: continue try: if connection == Dandelion().objectChildStem( inv[1]): # Fluff trigger by RNG # auto-ignore if config set to 0, i.e. dandelion is off if randint(1, 100) >= state.dandelion: fluffs.append(inv[1]) # send a dinv only if the stem node supports dandelion elif connection.services & protocol.NODE_DANDELION > 0: stems.append(inv[1]) else: fluffs.append(inv[1]) except KeyError: fluffs.append(inv[1]) if fluffs: shuffle(fluffs) connection.append_write_buf(protocol.CreatePacket('inv', \ addresses.encodeVarint(len(fluffs)) + "".join(fluffs))) if stems: shuffle(stems) connection.append_write_buf(protocol.CreatePacket('dinv', \ addresses.encodeVarint(len(stems)) + "".join(stems))) invQueue.iterate() for i in range(len(chunk)): invQueue.task_done() if Dandelion().refresh < time(): Dandelion().reRandomiseStems() self.stop.wait(1)
def pendingDownload(): tmp = {} for connection in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToMe.keys(): tmp[k] = True return len(tmp)
def run(self): while not self._stopped and state.shutdown == 0: try: dest = receiveDataQueue.get(block=True, timeout=1) except Queue.Empty: continue if self._stopped: break # cycle as long as there is data # methods should return False if there isn't enough data, or the connection is to be aborted # state_* methods should return False if there isn't enough data, # or the connection is to be aborted try: BMConnectionPool().getConnectionByAddr(dest).process() # KeyError = connection object not found # AttributeError = state isn't implemented except (KeyError, AttributeError): pass except socket.error as err: if err.errno == errno.EBADF: BMConnectionPool().getConnectionByAddr(dest).set_state("close", 0) else: logger.error("Socket error: %s", str(err)) receiveDataQueue.task_done()
def handleLocallyGenerated(self, stream, hashId): Dandelion().addHash(hashId, stream=stream) for connection in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): if state.dandelion and connection != Dandelion().objectChildStem(hashId): continue connection.objectsNewToThem[hashId] = time()
def pendingDownload(): if BMConfigParser().get("network", "asyncore"): tmp = {} for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToMe.keys(): tmp[k] = True return len(tmp) return PendingDownloadQueue.totalSize()
def pendingUpload(): if BMConfigParser().get("network", "asyncore"): return 0 tmp = {} for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToThem.keys(): tmp[k] = True return len(tmp) return PendingUpload().len()
def pendingUpload(): tmp = {} for connection in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToThem.keys(): tmp[k] = True #This probably isn't the correct logic so it's disabled #return len(tmp) return 0
def run(self): while not self._stopped: requested = 0 # Choose downloading peers randomly connections = BMConnectionPool().inboundConnections.values( ) + BMConnectionPool().outboundConnections.values() random.shuffle(connections) try: requestChunk = max( int(DownloadThread.maxRequestChunk / len(connections)), 1) except ZeroDivisionError: requestChunk = 1 for i in connections: now = time.time() timedOut = now - DownloadThread.requestTimeout # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk with i.objectsNewToMeLock: try: downloadPending = len( list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut and not v))) except KeyError: continue if downloadPending >= DownloadThread.minPending: continue # keys with True values in the dict try: request = list( (k for k, v in i.objectsNewToMe.iteritems() if k not in missingObjects or missingObjects[k] < timedOut)) except KeyError: continue random.shuffle(request) if not request: continue if len(request) > requestChunk - downloadPending: request = request[:requestChunk - downloadPending] # mark them as pending for k in request: i.objectsNewToMe[k] = False missingObjects[k] = now payload = bytearray() payload.extend(addresses.encodeVarint(len(request))) for chunk in request: payload.extend(chunk) i.append_write_buf(protocol.CreatePacket('getdata', payload)) logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, len(request)) requested += len(request) if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: self.cleanPending() if not requested: self.stop.wait(5)
def connectedHostsList(): retval = [] for i in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): if not i.fullyEstablished: continue try: retval.append(i) except AttributeError: pass return retval
def connectedHostsList(): if BMConfigParser().get("network", "asyncore"): retval = [] for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): if not i.fullyEstablished: continue try: retval.append(i) except AttributeError: pass return retval return shared.connectedHostsList.items()
def run(self): while not self._stopped: requested = 0 # Choose downloading peers randomly connections = [ x for x in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() if x.fullyEstablished ] helper_random.randomshuffle(connections) try: requestChunk = max( int( min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) except ZeroDivisionError: requestChunk = 1 for i in connections: now = time.time() # avoid unnecessary delay if i.skipUntil >= now: continue try: request = i.objectsNewToMe.randomKeys(requestChunk) except KeyError: continue payload = bytearray() chunkCount = 0 for chunk in request: if chunk in Inventory() and not Dandelion().hasHash(chunk): try: del i.objectsNewToMe[chunk] except KeyError: pass continue payload.extend(chunk) chunkCount += 1 missingObjects[chunk] = now if not chunkCount: continue payload[0:0] = addresses.encodeVarint(chunkCount) i.append_write_buf(protocol.CreatePacket('getdata', payload)) logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, chunkCount) requested += chunkCount if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: self.cleanPending() if not requested: self.stop.wait(1)
def connectToStream(streamNumber): state.streamsInWhichIAmParticipating.append(streamNumber) selfInitiatedConnections[streamNumber] = {} if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): # Some XP and Vista systems can only have 10 outgoing connections at a time. state.maximumNumberOfHalfOpenConnections = 9 else: state.maximumNumberOfHalfOpenConnections = 64 try: # don't overload Tor if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': state.maximumNumberOfHalfOpenConnections = 4 except: pass with knownnodes.knownNodesLock: if streamNumber not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber] = {} if streamNumber * 2 not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber * 2] = {} if streamNumber * 2 + 1 not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber * 2 + 1] = {} BMConnectionPool().connectToStream(streamNumber)
def run(self): while not state.shutdown: chunk = [] while True: try: data = addrQueue.get(False) chunk.append(data) except Queue.Empty: break if chunk: # Choose peers randomly connections = BMConnectionPool().establishedConnections() randomshuffle(connections) for i in connections: randomshuffle(chunk) filtered = [] for stream, peer, seen, destination in chunk: # peer's own address or address received from peer if i.destination in (peer, destination): continue if stream not in i.streams: continue filtered.append((stream, peer, seen)) if filtered: i.append_write_buf(assemble_addr(filtered)) addrQueue.iterate() for i in range(len(chunk)): addrQueue.task_done() self.stop.wait(1)
def run(self): try: while not self._stopped and state.shutdown == 0: BMConnectionPool().loop() except Exception as e: excQueue.put((self.name, e)) raise
def handleLocallyGenerated(stream, hashId): """Locally generated inventory items require special handling""" Dandelion().addHash(hashId, stream=stream) for connection in BMConnectionPool().connections(): if state.dandelion and connection != \ Dandelion().objectChildStem(hashId): continue connection.objectsNewToThem[hashId] = time()
def run(self): while not self._stopped: requested = 0 # Choose downloading peers randomly connections = BMConnectionPool().inboundConnections.values( ) + BMConnectionPool().outboundConnections.values() random.shuffle(connections) for i in connections: now = time.time() timedOut = now - DownloadThread.requestTimeout # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk with i.objectsNewToMeLock: downloadPending = len( list((k for k, v in i.objectsNewToMe.iteritems() if k in self.pending and self.pending[k] > timedOut))) if downloadPending >= DownloadThread.maxPending: continue # keys with True values in the dict request = list( (k for k, v in i.objectsNewToMe.iteritems() if k not in self.pending or self.pending[k] < timedOut )) if not request: continue if len(request ) > DownloadThread.requestChunk - downloadPending: request = request[:DownloadThread.requestChunk - downloadPending] # mark them as pending for k in request: i.objectsNewToMe[k] = False self.pending[k] = now payload = addresses.encodeVarint( len(request)) + ''.join(request) i.append_write_buf(protocol.CreatePacket('getdata', payload)) logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, len(request)) requested += len(request) if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: self.cleanPending() if not requested: self.stop.wait(1)
def run(self): while not self._stopped: uploaded = 0 # Choose downloading peers randomly connections = [x for x in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() if x.fullyEstablished] helper_random.randomshuffle(connections) for i in connections: now = time.time() # avoid unnecessary delay if i.skipUntil >= now: continue if len(i.write_buf) > UploadThread.maxBufSize: continue try: request = i.pendingUpload.randomKeys(RandomTrackingDict.maxPending) except KeyError: continue payload = bytearray() chunk_count = 0 for chunk in request: del i.pendingUpload[chunk] if Dandelion().hasHash(chunk) and \ i != Dandelion().objectChildStem(chunk): i.antiIntersectionDelay() logger.info('%s asked for a stem object we didn\'t offer to it.', i.destination) break try: payload.extend(protocol.CreatePacket('object', Inventory()[chunk].payload)) chunk_count += 1 except KeyError: i.antiIntersectionDelay() logger.info('%s asked for an object we don\'t have.', i.destination) break if not chunk_count: continue i.append_write_buf(payload) logger.debug("%s:%i Uploading %i objects", i.destination.host, i.destination.port, chunk_count) uploaded += chunk_count if not uploaded: self.stop.wait(1)
def announceSelf(self): for connection in BMConnectionPool().udpSockets.values(): if not connection.announcing: continue for stream in state.streamsInWhichIAmParticipating: addr = (stream, state.Peer( '127.0.0.1', BMConfigParser().safeGetInt( "lmessagesettings", "port")), time.time()) connection.append_write_buf(BMProto.assembleAddr([addr]))
def stopThread(self): super(BMNetworkThread, self).stopThread() for i in BMConnectionPool().listeningSockets: try: i.close() except: pass for i in BMConnectionPool().outboundConnections: try: i.close() except: pass for i in BMConnectionPool().inboundConnections: try: i.close() except: pass # just in case asyncore.close_all()
def announceSelf(): """Announce our presence""" for connection in BMConnectionPool().udpSockets.values(): if not connection.announcing: continue for stream in state.streamsInWhichIAmParticipating: addr = ( stream, Peer( '127.0.0.1', BMConfigParser().safeGetInt( 'bitmessagesettings', 'port')), time.time()) connection.append_write_buf(assemble_addr([addr]))
def handleExpiredDandelion(expired): """For expired dandelion objects, mark all remotes as not having the object""" if not expired: return for i in BMConnectionPool().connections(): if not i.fullyEstablished: continue for x in expired: streamNumber, hashid, _ = x try: del i.objectsNewToMe[hashid] except KeyError: if streamNumber in i.streams: with i.objectsNewToThemLock: i.objectsNewToThem[hashid] = time()
def run(self): while not state.shutdown: chunk = [] while True: try: data = addrQueue.get(False) chunk.append((data[0], data[1])) if len(data) > 2: source = BMConnectionPool().getConnectionByAddr( data[2]) except Queue.Empty: break except KeyError: continue #finish addrQueue.iterate() self.stop.wait(1)
def test_onionservicesonly(self): # this should start after bootstrap """ set onionservicesonly, wait for 3 connections and check them all are onions """ BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'SOCKS5') BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true') self._initiate_bootstrap() BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') for _ in range(360): time.sleep(1) for n, peer in enumerate(BMConnectionPool().outboundConnections): if n > 2: return if (not peer.host.endswith('.onion') and not peer.host.startswith('bootstrap')): self.fail( 'Found non onion hostname %s in outbound connections!' % peer.host) self.fail('Failed to connect to at least 3 nodes within 360 sec')
def _check_bootstrap(self): _started = time.time() BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') proxy_type = BMConfigParser().safeGet('bitmessagesettings', 'socksproxytype') if proxy_type == 'SOCKS5': connection_base = Socks5BMConnection elif proxy_type == 'SOCKS4a': connection_base = Socks4aBMConnection else: connection_base = TCPConnection for _ in range(180): time.sleep(1) for peer, con in BMConnectionPool().outboundConnections.iteritems( ): if not peer.host.startswith('bootstrap'): self.assertIsInstance(con, connection_base) self.assertNotEqual(peer.host, '127.0.0.1') return self.fail('Failed to connect during %s sec' % (time.time() - _started))
def run(self): while not state.shutdown: chunk = [] while True: try: data = invQueue.get(False) if len(data) == 2: BMConnectionPool().handleReceivedObject( data[0], data[1]) else: source = BMConnectionPool().getConnectionByAddr( data[2]) BMConnectionPool().handleReceivedObject( data[0], data[1], source) chunk.append((data[0], data[1])) except Queue.Empty: break # connection not found, handle it as if generated locally except KeyError: BMConnectionPool().handleReceivedObject(data[0], data[1]) if chunk: for connection in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): hashes = [] for inv in chunk: if inv[0] not in connection.streams: continue try: with connection.objectsNewToThemLock: del connection.objectsNewToThem[inv[1]] hashes.append(inv[1]) except KeyError: continue if hashes: connection.append_write_buf(protocol.CreatePacket('inv', \ addresses.encodeVarint(len(hashes)) + "".join(hashes))) invQueue.iterate() self.stop.wait(1)
def run(self): while not self._stopped and state.shutdown == 0: try: dest = receiveDataQueue.get(block=True, timeout=1) except Queue.Empty: continue if self._stopped or state.shutdown: break # cycle as long as there is data # methods should return False if there isn't enough data, # or the connection is to be aborted # state_* methods should return False if there isn't # enough data, or the connection is to be aborted try: connection = BMConnectionPool().getConnectionByAddr(dest) # connection object not found except KeyError: receiveDataQueue.task_done() continue try: connection.process() # state isn't implemented except UnknownStateError: pass except socket.error as err: if err.errno == errno.EBADF: connection.set_state("close", 0) else: self.logger.error('Socket error: %s', err) except: self.logger.error('Error processing', exc_info=True) receiveDataQueue.task_done()
def updateNetworkStatusTab(self, outbound, add, destination): """Add or remove an entry to the list of connected peers""" # pylint: disable=too-many-branches,undefined-variable if outbound: try: c = BMConnectionPool().outboundConnections[destination] except KeyError: if add: return else: try: c = BMConnectionPool().inboundConnections[destination] except KeyError: try: c = BMConnectionPool().inboundConnections[destination.host] except KeyError: if add: return self.tableWidgetConnectionCount.setUpdatesEnabled(False) self.tableWidgetConnectionCount.setSortingEnabled(False) if add: self.tableWidgetConnectionCount.insertRow(0) self.tableWidgetConnectionCount.setItem( 0, 0, QtGui.QTableWidgetItem("%s:%i" % (destination.host, destination.port)) ) self.tableWidgetConnectionCount.setItem( 0, 2, QtGui.QTableWidgetItem("%s" % (c.userAgent)) ) self.tableWidgetConnectionCount.setItem( 0, 3, QtGui.QTableWidgetItem("%s" % (c.tlsVersion)) ) self.tableWidgetConnectionCount.setItem( 0, 4, QtGui.QTableWidgetItem("%s" % (",".join(map(str, c.streams)))) ) try: # .. todo:: FIXME: hard coded stream no rating = "%.1f" % (knownnodes.knownNodes[1][destination]['rating']) except KeyError: rating = "-" self.tableWidgetConnectionCount.setItem( 0, 1, QtGui.QTableWidgetItem("%s" % (rating)) ) if outbound: brush = QtGui.QBrush(QtGui.QColor("yellow"), QtCore.Qt.SolidPattern) else: brush = QtGui.QBrush(QtGui.QColor("green"), QtCore.Qt.SolidPattern) for j in range(1): self.tableWidgetConnectionCount.item(0, j).setBackground(brush) self.tableWidgetConnectionCount.item(0, 0).setData(QtCore.Qt.UserRole, destination) self.tableWidgetConnectionCount.item(0, 1).setData(QtCore.Qt.UserRole, outbound) else: for i in range(self.tableWidgetConnectionCount.rowCount()): if self.tableWidgetConnectionCount.item(i, 0).data(QtCore.Qt.UserRole).toPyObject() != destination: continue if self.tableWidgetConnectionCount.item(i, 1).data(QtCore.Qt.UserRole).toPyObject() == outbound: self.tableWidgetConnectionCount.removeRow(i) break self.tableWidgetConnectionCount.setUpdatesEnabled(True) self.tableWidgetConnectionCount.setSortingEnabled(True) self.labelTotalConnections.setText( _translate( "networkstatus", "Total Connections: %1").arg( str(self.tableWidgetConnectionCount.rowCount()))) # FYI: The 'singlelistener' thread sets the icon color to green when it # receives an incoming connection, meaning that the user's firewall is # configured correctly. if self.tableWidgetConnectionCount.rowCount() and shared.statusIconColor == 'red': self.window().setStatusIcon('yellow') elif self.tableWidgetConnectionCount.rowCount() == 0 and shared.statusIconColor != "red": self.window().setStatusIcon('red')
def run(self): while not self._stopped and state.shutdown == 0: BMConnectionPool().loop()
def run(self): gc.disable() timeWeLastClearedInventoryAndPubkeysTables = 0 try: shared.maximumLengthOfTimeToBotherResendingMessages = ( float(BMConfigParser().get('lmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(BMConfigParser().get( 'lmessagesettings', 'stopresendingafterxmonths')) * (60 * 60 * 24 * 365) / 12) except: # Either the user hasn't set stopresendingafterxdays and # stopresendingafterxmonths yet or the options are missing # from the config file. shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') # initial wait if state.shutdown == 0: self.stop.wait(singleCleaner.cycleLength) while state.shutdown == 0: queues.UISignalQueue.put( ('updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)' )) Inventory().flush() queues.UISignalQueue.put(('updateStatusBar', '')) # If we are running as a daemon then we are going to fill up the UI # queue which will never be handled by a UI. We should clear it to # save memory. # FIXME redundant? if shared.thisapp.daemon or not state.enableGUI: queues.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < \ int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) Inventory().clean() # pubkeys sqlExecute( "DELETE FROM pubkeys WHERE time<? AND usedpersonally='no'", int(time.time()) - shared.lengthOfTimeToHoldOnToAllPubkeys) # Let us resend getpubkey objects if we have not yet heard # a pubkey, and also msg objects if we have not yet heard # an acknowledgement queryreturn = sqlQuery( "SELECT toaddress, ackdata, status FROM sent" " WHERE ((status='awaitingpubkey' OR status='msgsent')" " AND folder='sent' AND sleeptill<? AND senttime>?)", int(time.time()), int(time.time()) - shared.maximumLengthOfTimeToBotherResendingMessages) for row in queryreturn: if len(row) < 2: logger.error( 'Something went wrong in the singleCleaner thread:' ' a query did not return the requested fields. %r', row) self.stop.wait(3) break toAddress, ackData, status = row if status == 'awaitingpubkey': resendPubkeyRequest(toAddress) elif status == 'msgsent': resendMsg(ackData) # cleanup old nodes now = int(time.time()) with knownnodes.knownNodesLock: for stream in knownnodes.knownNodes: keys = knownnodes.knownNodes[stream].keys() for node in keys: try: # scrap old nodes if now - knownnodes.knownNodes[stream][node][ "lastseen"] > 2419200: # 28 days shared.needToWriteKnownNodesToDisk = True del knownnodes.knownNodes[stream][node] continue # scrap old nodes with low rating if now - knownnodes.knownNodes[stream][node][ "lastseen"] > 10800 and knownnodes.knownNodes[ stream][node][ "rating"] <= knownnodes.knownNodesForgetRating: shared.needToWriteKnownNodesToDisk = True del knownnodes.knownNodes[stream][node] continue except TypeError: print "Error in %s" % node keys = [] # Let us write out the knowNodes to disk # if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: try: knownnodes.saveKnownNodes() except Exception as err: if "Errno 28" in str(err): logger.fatal('(while receiveDataThread' ' knownnodes.needToWriteKnownNodesToDisk)' ' Alert: Your disk or data storage volume' ' is full. ') queues.UISignalQueue.put( ('alert', (tr._translate("MainWindow", "Disk full"), tr._translate( "MainWindow", 'Alert: Your disk or data storage volume' ' is full. LMessage will now exit.'), True))) # FIXME redundant? if shared.daemon or not state.enableGUI: os._exit(0) shared.needToWriteKnownNodesToDisk = False # # clear download queues # for thread in threading.enumerate(): # if thread.isAlive() and hasattr(thread, 'downloadQueue'): # thread.downloadQueue.clear() # inv/object tracking for connection in \ BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): connection.clean() # discovery tracking exp = time.time() - singleCleaner.expireDiscoveredPeers reaper = (k for k, v in state.discoveredPeers.items() if v < exp) for k in reaper: try: del state.discoveredPeers[k] except KeyError: pass # TODO: cleanup pending upload / download gc.collect() if state.shutdown == 0: self.stop.wait(singleCleaner.cycleLength)
def start(self): _fixSocket() daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') try: opts, args = getopt.getopt(sys.argv[1:], "hcd", ["help", "curses", "daemon"]) except getopt.GetoptError: self.usage() sys.exit(2) for opt, arg in opts: if opt in ("-h", "--help"): self.usage() sys.exit() elif opt in ("-d", "--daemon"): daemon = True elif opt in ("-c", "--curses"): state.curses = True # is the application already running? If yes then exit. shared.thisapp = singleinstance("", daemon) if daemon: with shared.printLock: print('Running as a daemon. Send TERM signal to end.') self.daemonize() self.setSignalHandler() helper_threading.set_thread_name("PyBitmessage") state.dandelion = BMConfigParser().safeGetInt('network', 'dandelion') # dandelion requires outbound connections, without them, stem objects will get stuck forever if state.dandelion and not BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'sendoutgoingconnections'): state.dandelion = 0 helper_bootstrap.knownNodes() # Start the address generation thread addressGeneratorThread = addressGenerator() addressGeneratorThread.daemon = True # close the main program even if there are threads left addressGeneratorThread.start() # Start the thread that calculates POWs singleWorkerThread = singleWorker() singleWorkerThread.daemon = True # close the main program even if there are threads left singleWorkerThread.start() # Start the SQL thread sqlLookup = sqlThread() sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully. sqlLookup.start() Inventory() # init Dandelion( ) # init, needs to be early because other thread may access it early # SMTP delivery thread if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread if daemon and BMConfigParser().safeGetBoolean("bitmessagesettings", "smtpd"): smtpServerThread = smtpServer() smtpServerThread.start() # Start the thread that calculates POWs objectProcessorThread = objectProcessor() objectProcessorThread.daemon = False # DON'T close the main program even the thread remains. This thread checks the shutdown variable after processing each object. objectProcessorThread.start() # Start the cleanerThread singleCleanerThread = singleCleaner() singleCleanerThread.daemon = True # close the main program even if there are threads left singleCleanerThread.start() shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: apiNotifyPath = BMConfigParser().get('bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' if apiNotifyPath != '': with shared.printLock: print('Trying to call', apiNotifyPath) call([apiNotifyPath, "startingUp"]) singleAPIThread = singleAPI() singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() BMConnectionPool() asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() for i in range(BMConfigParser().getint("threads", "receive")): receiveQueueThread = ReceiveQueueThread(i) receiveQueueThread.daemon = True receiveQueueThread.start() announceThread = AnnounceThread() announceThread.daemon = True announceThread.start() state.invThread = InvThread() state.invThread.daemon = True state.invThread.start() state.addrThread = AddrThread() state.addrThread.daemon = True state.addrThread.start() state.downloadThread = DownloadThread() state.downloadThread.daemon = True state.downloadThread.start() connectToStream(1) if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() if daemon == False and BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'daemon') == False: if state.curses == False: if not depends.check_pyqt(): print( 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' ) print( 'You can also run PyBitmessage with the new curses interface by providing \'-c\' as a commandline argument.' ) sys.exit() import bitmessageqt bitmessageqt.run() else: if True: # if depends.check_curses(): print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() else: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') if daemon: while state.shutdown == 0: sleep(1)