예제 #1
0
    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)
예제 #2
0
def pendingDownload():
    tmp = {}
    for connection in BMConnectionPool().inboundConnections.values() + \
            BMConnectionPool().outboundConnections.values():
        for k in connection.objectsNewToMe.keys():
            tmp[k] = True
    return len(tmp)
예제 #3
0
    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()
예제 #4
0
 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()
예제 #5
0
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()
예제 #6
0
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()
예제 #7
0
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
예제 #8
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)
예제 #9
0
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
예제 #10
0
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()
예제 #11
0
 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)
예제 #12
0
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)
예제 #13
0
    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)
예제 #14
0
 def run(self):
     try:
         while not self._stopped and state.shutdown == 0:
             BMConnectionPool().loop()
     except Exception as e:
         excQueue.put((self.name, e))
         raise
예제 #15
0
 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()
예제 #16
0
    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)
예제 #17
0
 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)
예제 #18
0
 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]))
예제 #19
0
    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()
예제 #20
0
 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]))
예제 #21
0
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()
예제 #22
0
    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)
예제 #23
0
 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')
예제 #24
0
 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))
예제 #25
0
    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)
예제 #26
0
    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()
예제 #27
0
    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')
예제 #28
0
 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)
예제 #30
0
    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)