示例#1
0
    def handle_read(self):
        try:
            (recdata, addr) = self.socket.recvfrom(self._buf_len)
        except socket.error as e:
            logger.error("socket error: %s", e)
            return

        self.destination = Peer(*addr)
        encodedAddr = protocol.encodeHost(addr[0])
        self.local = bool(protocol.checkIPAddress(encodedAddr, True))
        # overwrite the old buffer to avoid mixing data and so that
        # self.local works correctly
        self.read_buf[0:] = recdata
        self.bm_proto_reset()
        receiveDataQueue.put(self.listening)
示例#2
0
def chooseConnection(stream):
    """Returns an appropriate connection"""
    haveOnion = BMConfigParser().safeGet("bitmessagesettings",
                                         "socksproxytype")[0:5] == 'SOCKS'
    onionOnly = BMConfigParser().safeGetBoolean("bitmessagesettings",
                                                "onionservicesonly")
    try:
        retval = portCheckerQueue.get(False)
        portCheckerQueue.task_done()
        return retval
    except Queue.Empty:
        pass
    # with a probability of 0.5, connect to a discovered peer
    if random.choice((False, True)) and not haveOnion:
        # discovered peers are already filtered by allowed streams
        return getDiscoveredPeer()
    for _ in range(50):
        peer = random.choice(knownnodes.knownNodes[stream].keys())
        try:
            peer_info = knownnodes.knownNodes[stream][peer]
            if peer_info.get('self'):
                continue
            rating = peer_info["rating"]
        except TypeError:
            logger.warning('Error in %s', peer)
            rating = 0
        if haveOnion:
            # do not connect to raw IP addresses
            # --keep all traffic within Tor overlay
            if onionOnly and not peer.host.endswith('.onion'):
                continue
            # onion addresses have a higher priority when SOCKS
            if peer.host.endswith('.onion') and rating > 0:
                rating = 1
            # TODO: need better check
            elif not peer.host.startswith('bootstrap'):
                encodedAddr = protocol.encodeHost(peer.host)
                # don't connect to local IPs when using SOCKS
                if not protocol.checkIPAddress(encodedAddr, False):
                    continue
        if rating > 1:
            rating = 1
        try:
            if 0.05 / (1.0 - rating) > random.random():
                return peer
        except ZeroDivisionError:
            return peer
    raise ValueError
示例#3
0
 def __init__(self, address=None, sock=None):
     BMProto.__init__(self, address=address, sock=sock)
     self.verackReceived = False
     self.verackSent = False
     self.streams = [0]
     self.fullyEstablished = False
     self.connectedAt = 0
     self.skipUntil = 0
     if address is None and sock is not None:
         self.destination = Peer(*sock.getpeername())
         self.isOutbound = False
         TLSDispatcher.__init__(self, sock, server_side=True)
         self.connectedAt = time.time()
         logger.debug(
             'Received connection from %s:%i',
             self.destination.host, self.destination.port)
         self.nodeid = randomBytes(8)
     elif address is not None and sock is not None:
         TLSDispatcher.__init__(self, sock, server_side=False)
         self.isOutbound = True
         logger.debug(
             'Outbound proxy connection to %s:%i',
             self.destination.host, self.destination.port)
     else:
         self.destination = address
         self.isOutbound = True
         self.create_socket(
             socket.AF_INET6 if ":" in address.host else socket.AF_INET,
             socket.SOCK_STREAM)
         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         TLSDispatcher.__init__(self, sock, server_side=False)
         self.connect(self.destination)
         logger.debug(
             'Connecting to %s:%i',
             self.destination.host, self.destination.port)
     try:
         self.local = (
             protocol.checkIPAddress(
                 protocol.encodeHost(self.destination.host), True)
             and not protocol.checkSocksIP(self.destination.host)
         )
     except socket.error:
         # it's probably a hostname
         pass
     self.network_group = protocol.network_group(self.destination.host)
     ObjectTracker.__init__(self)  # pylint: disable=non-parent-init-called
     self.bm_proto_reset()
     self.set_state("bm_header", expectBytes=protocol.Header.size)
示例#4
0
    def handle_read(self):
        try:
            (recdata, addr) = self.socket.recvfrom(AdvancedDispatcher._buf_len)
        except socket.error as e:
            logger.error("socket error: %s", str(e))
            return

        self.destination = state.Peer(addr[0], addr[1])
        encodedAddr = protocol.encodeHost(addr[0])
        # if protocol.checkIPAddress(encodedAddr, True):
        #     self.local = True
        # else:
        #     self.local = False
        # overwrite the old buffer to avoid mixing data and so that self.local works correctly
        self.read_buf[0:] = recdata
        self.bm_proto_reset()
        receiveDataQueue.put(self.listening)
示例#5
0
 def __init__(self, address=None, sock=None):
     BMProto.__init__(self, address=address, sock=sock)
     self.verackReceived = False
     self.verackSent = False
     self.streams = [0]
     self.fullyEstablished = False
     self.connectedAt = 0
     self.skipUntil = 0
     if address is None and sock is not None:
         self.destination = state.Peer(sock.getpeername()[0],
                                       sock.getpeername()[1])
         self.isOutbound = False
         TLSDispatcher.__init__(self, sock, server_side=True)
         self.connectedAt = time.time()
         logger.debug("Received connection from %s:%i",
                      self.destination.host, self.destination.port)
         self.nodeid = randomBytes(8)
     elif address is not None and sock is not None:
         TLSDispatcher.__init__(self, sock, server_side=False)
         self.isOutbound = True
         logger.debug("Outbound proxy connection to %s:%i",
                      self.destination.host, self.destination.port)
     else:
         self.destination = address
         self.isOutbound = True
         if ":" in address.host:
             self.create_socket(socket.AF_INET6, socket.SOCK_STREAM)
         else:
             self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         TLSDispatcher.__init__(self, sock, server_side=False)
         self.connect(self.destination)
         logger.debug("Connecting to %s:%i", self.destination.host,
                      self.destination.port)
     encodedAddr = protocol.encodeHost(self.destination.host)
     if protocol.checkIPAddress(
             encodedAddr,
             True) and not protocol.checkSocksIP(self.destination.host):
         self.local = True
     else:
         self.local = False
     #shared.connectedHostsList[self.destination] = 0
     ObjectTracker.__init__(self)
     UISignalQueue.put(('updateNetworkStatusTab', 'no data'))
     self.bm_proto_reset()
     self.set_state("bm_header", expectBytes=protocol.Header.size)
示例#6
0
    def handle_read(self):
        try:
            (recdata, addr) = self.socket.recvfrom(AdvancedDispatcher._buf_len)
        except socket.error as e:
            logger.error("socket error: %s", str(e))
            return

        self.destination = state.Peer(addr[0], addr[1])
        encodedAddr = protocol.encodeHost(addr[0])
        if protocol.checkIPAddress(encodedAddr, True):
            self.local = True
        else:
            self.local = False
        # overwrite the old buffer to avoid mixing data and so that self.local works correctly
        self.read_buf[0:] = recdata
        self.bm_proto_reset()
        receiveDataQueue.put(self.listening)
示例#7
0
 def assembleAddr(peerList):
     if isinstance(peerList, state.Peer):
         peerList = (peerList)
     if not peerList:
         return b''
     retval = b''
     for i in range(0, len(peerList), BMProto.maxAddrCount):
         payload = addresses.encodeVarint(len(peerList[i:i + BMProto.maxAddrCount]))
         for address in peerList[i:i + BMProto.maxAddrCount]:
             stream, peer, timestamp = address
             payload += struct.pack(
                 '>Q', timestamp)  # 64-bit time
             payload += struct.pack('>I', stream)
             payload += struct.pack(
                 '>q', 1)  # service bit flags offered by this node
             payload += protocol.encodeHost(peer.host)
             payload += struct.pack('>H', peer.port)  # remote port
         retval += protocol.CreatePacket('addr', payload)
     return retval
示例#8
0
 def assembleAddr(peerList):
     if isinstance(peerList, state.Peer):
         peerList = (peerList)
     if not peerList:
         return b''
     retval = b''
     for i in range(0, len(peerList), BMProto.maxAddrCount):
         payload = addresses.encodeVarint(len(peerList[i:i + BMProto.maxAddrCount]))
         for address in peerList[i:i + BMProto.maxAddrCount]:
             stream, peer, timestamp = address
             payload += struct.pack(
                 '>Q', timestamp)  # 64-bit time
             payload += struct.pack('>I', stream)
             payload += struct.pack(
                 '>q', 1)  # service bit flags offered by this node
             payload += protocol.encodeHost(peer.host)
             payload += struct.pack('>H', peer.port)  # remote port
         retval += protocol.CreatePacket('addr', payload)
     return retval
示例#9
0
def assemble_addr(peerList):
    """Create address command"""
    if isinstance(peerList, Peer):
        peerList = [peerList]
    if not peerList:
        return b''
    retval = b''
    for i in range(0, len(peerList), MAX_ADDR_COUNT):
        payload = addresses.encodeVarint(len(peerList[i:i + MAX_ADDR_COUNT]))
        for stream, peer, timestamp in peerList[i:i + MAX_ADDR_COUNT]:
            # 64-bit time
            payload += struct.pack('>Q', timestamp)
            payload += struct.pack('>I', stream)
            # service bit flags offered by this node
            payload += struct.pack('>q', 1)
            payload += encodeHost(peer.host)
            # remote port
            payload += struct.pack('>H', peer.port)
        retval += CreatePacket('addr', payload)
    return retval
def chooseConnection(stream):
    haveOnion = BMConfigParser().safeGet("lmessagesettings",
                                         "socksproxytype")[0:5] == 'SOCKS'
    if state.trustedPeer:
        return state.trustedPeer
    try:
        retval = portCheckerQueue.get(False)
        portCheckerQueue.task_done()
        return retval
    except Queue.Empty:
        pass
    # with a probability of 0.5, connect to a discovered peer
    if helper_random.randomchoice((False, True)) and not haveOnion:
        # discovered peers are already filtered by allowed streams
        return getDiscoveredPeer()
    for _ in range(50):
        peer = helper_random.randomchoice(knownnodes.knownNodes[stream].keys())
        try:
            rating = knownnodes.knownNodes[stream][peer]["rating"]
        except TypeError:
            print "Error in %s" % (peer)
            rating = 0
        if haveOnion:
            # onion addresses have a higher priority when SOCKS
            if peer.host.endswith('.onion') and rating > 0:
                rating = 1
            else:
                encodedAddr = protocol.encodeHost(peer.host)
                # don't connect to local IPs when using SOCKS
                if not protocol.checkIPAddress(encodedAddr, False):
                    continue
        if rating > 1:
            rating = 1
        try:
            if 0.05 / (1.0 - rating) > random.random():
                return peer
        except ZeroDivisionError:
            return peer
    raise ValueError
示例#11
0
 def __init__(self, address=None, sock=None):
     BMProto.__init__(self, address=address, sock=sock)
     self.verackReceived = False
     self.verackSent = False
     self.streams = [0]
     self.fullyEstablished = False
     self.connectedAt = 0
     self.skipUntil = 0
     if address is None and sock is not None:
         self.destination = state.Peer(sock.getpeername()[0], sock.getpeername()[1])
         self.isOutbound = False
         TLSDispatcher.__init__(self, sock, server_side=True)
         self.connectedAt = time.time()
         logger.debug("Received connection from %s:%i", self.destination.host, self.destination.port)
         self.nodeid = randomBytes(8)
     elif address is not None and sock is not None:
         TLSDispatcher.__init__(self, sock, server_side=False)
         self.isOutbound = True
         logger.debug("Outbound proxy connection to %s:%i", self.destination.host, self.destination.port)
     else:
         self.destination = address
         self.isOutbound = True
         if ":" in address.host:
             self.create_socket(socket.AF_INET6, socket.SOCK_STREAM)
         else:
             self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         TLSDispatcher.__init__(self, sock, server_side=False)
         self.connect(self.destination)
         logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port)
     encodedAddr = protocol.encodeHost(self.destination.host)
     if protocol.checkIPAddress(encodedAddr, True) and not protocol.checkSocksIP(self.destination.host):
         self.local = True
     else:
         self.local = False
     #shared.connectedHostsList[self.destination] = 0
     ObjectTracker.__init__(self)
     self.bm_proto_reset()
     self.set_state("bm_header", expectBytes=protocol.Header.size)
def chooseConnection(stream):
    haveOnion = BMConfigParser().safeGet("bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS'
    if state.trustedPeer:
        return state.trustedPeer
    try:
        retval = portCheckerQueue.get(False)
        portCheckerQueue.task_done()
        return retval
    except Queue.Empty:
        pass
    # with a probability of 0.5, connect to a discovered peer
    if random.choice((False, True)) and not haveOnion:
        # discovered peers are already filtered by allowed streams
        return getDiscoveredPeer()
    for _ in range(50):
        peer = random.choice(knownnodes.knownNodes[stream].keys())
        try:
            rating = knownnodes.knownNodes[stream][peer]["rating"]
        except TypeError:
            print "Error in %s" % (peer)
            rating = 0
        if haveOnion:
            # onion addresses have a higher priority when SOCKS
            if peer.host.endswith('.onion') and rating > 0:
                rating = 1
            else:
                encodedAddr = protocol.encodeHost(peer.host)
                # don't connect to local IPs when using SOCKS
                if not protocol.checkIPAddress(encodedAddr, False):
                    continue
        if rating > 1:
            rating = 1
        try:
            if 0.05/(1.0-rating) > random.random():
                return peer
        except ZeroDivisionError:
            return peer
    raise ValueError
    def run(self):
        logger.debug('sendDataThread starting. ID: ' + str(id(self)) +
                     '. Number of queues in sendDataQueues: ' +
                     str(len(state.sendDataQueues)))
        while self.sendBytes():
            deststream, command, data = self.sendDataThreadQueue.get()

            if deststream == 0 or deststream in self.streamNumber:
                if command == 'shutdown':
                    logger.debug('sendDataThread (associated with ' +
                                 str(self.peer) + ') ID: ' + str(id(self)) +
                                 ' shutting down now.')
                    break
                # When you receive an incoming connection, a sendDataThread is
                # created even though you don't yet know what stream number the
                # remote peer is interested in. They will tell you in a version
                # message and if you too are interested in that stream then you
                # will continue on with the connection and will set the
                # streamNumber of this send data thread here:
                elif command == 'setStreamNumber':
                    self.streamNumber = data
                    logger.debug('setting the stream number to %s',
                                 ', '.join(str(x) for x in self.streamNumber))
                elif command == 'setRemoteProtocolVersion':
                    specifiedRemoteProtocolVersion = data
                    logger.debug(
                        'setting the remote node\'s protocol version in the sendDataThread (ID: '
                        + str(id(self)) + ') to ' +
                        str(specifiedRemoteProtocolVersion))
                    self.remoteProtocolVersion = specifiedRemoteProtocolVersion
                elif command == 'sendaddr':
                    if self.connectionIsOrWasFullyEstablished:  # only send addr messages if we have sent and heard a verack from the remote node
                        numberOfAddressesInAddrMessage = len(data)
                        payload = ''
                        for hostDetails in data:
                            timeLastReceivedMessageFromThisNode, streamNumber, services, host, port = hostDetails
                            payload += pack('>Q',
                                            timeLastReceivedMessageFromThisNode
                                            )  # now uses 64-bit time
                            payload += pack('>I', streamNumber)
                            payload += pack(
                                '>q', services
                            )  # service bit flags offered by this node
                            payload += protocol.encodeHost(host)
                            payload += pack('>H', port)

                        payload = encodeVarint(
                            numberOfAddressesInAddrMessage) + payload
                        packet = protocol.CreatePacket('addr', payload)
                        if not self.sendBytes(packet):
                            break
                elif command == 'advertiseobject':
                    self.objectHashHolderInstance.holdHash(data)
                elif command == 'sendinv':
                    if self.connectionIsOrWasFullyEstablished:  # only send inv messages if we have send and heard a verack from the remote node
                        payload = ''
                        for hash in data:
                            payload += hash
                        if payload != '':
                            payload = encodeVarint(len(payload) / 32) + payload
                            packet = protocol.CreatePacket('inv', payload)
                            if not self.sendBytes(packet):
                                break
                elif command == 'pong':
                    if self.lastTimeISentData < (int(time.time()) - 298):
                        # Send out a pong message to keep the connection alive.
                        logger.debug('Sending pong to ' + str(self.peer) +
                                     ' to keep connection alive.')
                        packet = protocol.CreatePacket('pong')
                        if not self.sendBytes(packet):
                            break
                elif command == 'sendRawData':
                    objectHash = None
                    if type(data) in [list, tuple]:
                        objectHash, data = data
                    if not self.sendBytes(data):
                        break
                    if objectHash:
                        PendingUpload().delete(objectHash)
                elif command == 'connectionIsOrWasFullyEstablished':
                    self.connectionIsOrWasFullyEstablished = True
                    self.services, self.sock = data
            elif self.connectionIsOrWasFullyEstablished:
                logger.error('sendDataThread ID: ' + str(id(self)) +
                             ' ignoring command ' + command +
                             ' because the thread is not in stream ' +
                             str(deststream) + ' but in streams ' +
                             ', '.join(str(x) for x in self.streamNumber))
            self.sendDataThreadQueue.task_done()
        # Flush if the cycle ended with break
        try:
            self.sendDataThreadQueue.task_done()
        except ValueError:
            pass

        try:
            self.sock.shutdown(socket.SHUT_RDWR)
            self.sock.close()
        except:
            pass
        state.sendDataQueues.remove(self.sendDataThreadQueue)
        PendingUpload().threadEnd()
        logger.info('sendDataThread ending. ID: ' + str(id(self)) +
                    '. Number of queues in sendDataQueues: ' +
                    str(len(state.sendDataQueues)))
        self.objectHashHolderInstance.close()
    def run(self):
        logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues)))
        while self.sendBytes():
            deststream, command, data = self.sendDataThreadQueue.get()

            if deststream == 0 or deststream in self.streamNumber:
                if command == 'shutdown':
                    logger.debug('sendDataThread (associated with ' + str(self.peer) + ') ID: ' + str(id(self)) + ' shutting down now.')
                    break
                # When you receive an incoming connection, a sendDataThread is
                # created even though you don't yet know what stream number the
                # remote peer is interested in. They will tell you in a version
                # message and if you too are interested in that stream then you
                # will continue on with the connection and will set the
                # streamNumber of this send data thread here:
                elif command == 'setStreamNumber':
                    self.streamNumber = data
                    logger.debug('setting the stream number to %s', ', '.join(str(x) for x in self.streamNumber))
                elif command == 'setRemoteProtocolVersion':
                    specifiedRemoteProtocolVersion = data
                    logger.debug('setting the remote node\'s protocol version in the sendDataThread (ID: ' + str(id(self)) + ') to ' + str(specifiedRemoteProtocolVersion))
                    self.remoteProtocolVersion = specifiedRemoteProtocolVersion
                elif command == 'advertisepeer':
                    self.objectHashHolderInstance.holdPeer(data)
                elif command == 'sendaddr':
                    if self.connectionIsOrWasFullyEstablished: # only send addr messages if we have sent and heard a verack from the remote node
                        numberOfAddressesInAddrMessage = len(data)
                        payload = ''
                        for hostDetails in data:
                            timeLastReceivedMessageFromThisNode, streamNumber, services, host, port = hostDetails
                            payload += pack(
                                '>Q', timeLastReceivedMessageFromThisNode)  # now uses 64-bit time
                            payload += pack('>I', streamNumber)
                            payload += pack(
                                '>q', services)  # service bit flags offered by this node
                            payload += protocol.encodeHost(host)
                            payload += pack('>H', port)
    
                        payload = encodeVarint(numberOfAddressesInAddrMessage) + payload
                        packet = protocol.CreatePacket('addr', payload)
                        try:
                            self.sendBytes(packet)
                        except:
                            logger.error('sendaddr: self.sock.sendall failed')
                            break
                elif command == 'advertiseobject':
                    self.objectHashHolderInstance.holdHash(data)
                elif command == 'sendinv':
                    if self.connectionIsOrWasFullyEstablished: # only send inv messages if we have send and heard a verack from the remote node
                        payload = ''
                        for hash in data:
                            payload += hash
                        if payload != '':
                            payload = encodeVarint(len(payload)/32) + payload
                            packet = protocol.CreatePacket('inv', payload)
                            try:
                                self.sendBytes(packet)
                            except:
                                logger.error('sendinv: self.sock.sendall failed')
                                break
                elif command == 'pong':
                    if self.lastTimeISentData < (int(time.time()) - 298):
                        # Send out a pong message to keep the connection alive.
                        logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.')
                        packet = protocol.CreatePacket('pong')
                        try:
                            self.sendBytes(packet)
                        except:
                            logger.error('send pong failed')
                            break
                elif command == 'sendRawData':
                    objectHash = None
                    if type(data) in [list, tuple]:
                        objectHash, data = data
                    try:
                        self.sendBytes(data)
                        PendingUpload().delete(objectHash)
                    except:
                        logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.', exc_info=True)
                        break
                elif command == 'connectionIsOrWasFullyEstablished':
                    self.connectionIsOrWasFullyEstablished = True
                    self.services, self.sslSock = data
            elif self.connectionIsOrWasFullyEstablished:
                logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream ' + str(deststream) + ' but in streams ' + ', '.join(str(x) for x in self.streamNumber))
            self.sendDataThreadQueue.task_done()
        # Flush if the cycle ended with break
        try:
            self.sendDataThreadQueue.task_done()
        except ValueError:
            pass

        try:
            self.sock.shutdown(socket.SHUT_RDWR)
            self.sock.close()
        except:
            pass
        state.sendDataQueues.remove(self.sendDataThreadQueue)
        PendingUpload().threadEnd()
        logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues)))
        self.objectHashHolderInstance.close()
示例#15
0
    def sendaddr(self):
        def sendChunk():
            if numberOfAddressesInAddrMessage == 0:
                return
            self.sendDataThreadQueue.put((0, 'sendRawData', \
                protocol.CreatePacket('addr', \
                encodeVarint(numberOfAddressesInAddrMessage) + payload)))

        # We are going to share a maximum number of 1000 addrs (per overlapping
        # stream) with our peer. 500 from overlapping streams, 250 from the
        # left child stream, and 250 from the right child stream.
        maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings",
                                                   "maxaddrperstreamsend", 500)

        # protocol defines this as a maximum in one chunk
        protocolAddrLimit = 1000

        # init
        numberOfAddressesInAddrMessage = 0
        payload = ''

        for stream in self.streamNumber:
            addrsInMyStream = {}
            addrsInChildStreamLeft = {}
            addrsInChildStreamRight = {}

            with knownnodes.knownNodesLock:
                if len(knownnodes.knownNodes[stream]) > 0:
                    filtered = {
                        k: v
                        for k, v in knownnodes.knownNodes[stream].items()
                        if v > (int(time.time()) -
                                shared.maximumAgeOfNodesThatIAdvertiseToOthers)
                    }
                    elemCount = len(filtered)
                    if elemCount > maxAddrCount:
                        elemCount = maxAddrCount
                    # only if more recent than 3 hours
                    addrsInMyStream = random.sample(filtered.items(),
                                                    elemCount)
                # sent 250 only if the remote isn't interested in it
                if len(knownnodes.knownNodes[
                        stream * 2]) > 0 and stream not in self.streamNumber:
                    filtered = {
                        k: v
                        for k, v in knownnodes.knownNodes[stream * 2].items()
                        if v > (int(time.time()) -
                                shared.maximumAgeOfNodesThatIAdvertiseToOthers)
                    }
                    elemCount = len(filtered)
                    if elemCount > maxAddrCount / 2:
                        elemCount = int(maxAddrCount / 2)
                    addrsInChildStreamLeft = random.sample(
                        filtered.items(), elemCount)
                if len(knownnodes.knownNodes[
                    (stream * 2) + 1]) > 0 and stream not in self.streamNumber:
                    filtered = {
                        k: v
                        for k, v in knownnodes.knownNodes[stream * 2 +
                                                          1].items()
                        if v > (int(time.time()) -
                                shared.maximumAgeOfNodesThatIAdvertiseToOthers)
                    }
                    elemCount = len(filtered)
                    if elemCount > maxAddrCount / 2:
                        elemCount = int(maxAddrCount / 2)
                    addrsInChildStreamRight = random.sample(
                        filtered.items(), elemCount)
            for (HOST,
                 PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream:
                numberOfAddressesInAddrMessage += 1
                payload += pack(
                    '>Q', timeLastReceivedMessageFromThisNode)  # 64-bit time
                payload += pack('>I', stream)
                payload += pack('>q',
                                1)  # service bit flags offered by this node
                payload += protocol.encodeHost(HOST)
                payload += pack('>H', PORT)  # remote port
                if numberOfAddressesInAddrMessage >= protocolAddrLimit:
                    sendChunk()
                    payload = ''
                    numberOfAddressesInAddrMessage = 0
            for (
                    HOST, PORT
            ), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft:
                numberOfAddressesInAddrMessage += 1
                payload += pack(
                    '>Q', timeLastReceivedMessageFromThisNode)  # 64-bit time
                payload += pack('>I', stream * 2)
                payload += pack('>q',
                                1)  # service bit flags offered by this node
                payload += protocol.encodeHost(HOST)
                payload += pack('>H', PORT)  # remote port
                if numberOfAddressesInAddrMessage >= protocolAddrLimit:
                    sendChunk()
                    payload = ''
                    numberOfAddressesInAddrMessage = 0
            for (
                    HOST, PORT
            ), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight:
                numberOfAddressesInAddrMessage += 1
                payload += pack(
                    '>Q', timeLastReceivedMessageFromThisNode)  # 64-bit time
                payload += pack('>I', (stream * 2) + 1)
                payload += pack('>q',
                                1)  # service bit flags offered by this node
                payload += protocol.encodeHost(HOST)
                payload += pack('>H', PORT)  # remote port
                if numberOfAddressesInAddrMessage >= protocolAddrLimit:
                    sendChunk()
                    payload = ''
                    numberOfAddressesInAddrMessage = 0

        # flush
        sendChunk()
    def sendaddr(self):
        def sendChunk():
            if numberOfAddressesInAddrMessage == 0:
                return
            self.sendDataThreadQueue.put((0, 'sendRawData', \
                protocol.CreatePacket('addr', \
                encodeVarint(numberOfAddressesInAddrMessage) + payload)))

        # We are going to share a maximum number of 1000 addrs (per overlapping
        # stream) with our peer. 500 from overlapping streams, 250 from the
        # left child stream, and 250 from the right child stream.
        maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500)

        # protocol defines this as a maximum in one chunk
        protocolAddrLimit = 1000

        # init
        numberOfAddressesInAddrMessage = 0
        payload = ''

        for stream in self.streamNumber:
            addrsInMyStream = {}
            addrsInChildStreamLeft = {}
            addrsInChildStreamRight = {}

            with knownnodes.knownNodesLock:
                if len(knownnodes.knownNodes[stream]) > 0:
                    filtered = {k: v for k, v in knownnodes.knownNodes[stream].items()
                        if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
                    elemCount = len(filtered)
                    if elemCount > maxAddrCount:
                        elemCount = maxAddrCount
                    # only if more recent than 3 hours
                    addrsInMyStream = random.sample(filtered.items(), elemCount)
                # sent 250 only if the remote isn't interested in it
                if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streamNumber:
                    filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items()
                        if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
                    elemCount = len(filtered)
                    if elemCount > maxAddrCount / 2:
                        elemCount = int(maxAddrCount / 2)
                    addrsInChildStreamLeft = random.sample(filtered.items(), elemCount)
                if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber:
                    filtered = {k: v for k, v in knownnodes.knownNodes[stream*2+1].items()
                        if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)}
                    elemCount = len(filtered)
                    if elemCount > maxAddrCount / 2:
                        elemCount = int(maxAddrCount / 2)
                    addrsInChildStreamRight = random.sample(filtered.items(), elemCount)
            for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream:
                numberOfAddressesInAddrMessage += 1
                payload += pack(
                    '>Q', timeLastReceivedMessageFromThisNode)  # 64-bit time
                payload += pack('>I', stream)
                payload += pack(
                    '>q', 1)  # service bit flags offered by this node
                payload += protocol.encodeHost(HOST)
                payload += pack('>H', PORT)  # remote port
                if numberOfAddressesInAddrMessage >= protocolAddrLimit:
                    sendChunk()
                    payload = ''
                    numberOfAddressesInAddrMessage = 0
            for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft:
                numberOfAddressesInAddrMessage += 1
                payload += pack(
                    '>Q', timeLastReceivedMessageFromThisNode)  # 64-bit time
                payload += pack('>I', stream * 2)
                payload += pack(
                    '>q', 1)  # service bit flags offered by this node
                payload += protocol.encodeHost(HOST)
                payload += pack('>H', PORT)  # remote port
                if numberOfAddressesInAddrMessage >= protocolAddrLimit:
                    sendChunk()
                    payload = ''
                    numberOfAddressesInAddrMessage = 0
            for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight:
                numberOfAddressesInAddrMessage += 1
                payload += pack(
                    '>Q', timeLastReceivedMessageFromThisNode)  # 64-bit time
                payload += pack('>I', (stream * 2) + 1)
                payload += pack(
                    '>q', 1)  # service bit flags offered by this node
                payload += protocol.encodeHost(HOST)
                payload += pack('>H', PORT)  # remote port
                if numberOfAddressesInAddrMessage >= protocolAddrLimit:
                    sendChunk()
                    payload = ''
                    numberOfAddressesInAddrMessage = 0
    
        # flush
        sendChunk()