Example #1
0
class ZyreNode():
    def __init__(self, interface, netiface=None):
        self.interface = interface

        # Peers book
        self.book = {}
        self.topics = []

        # Publisher
        self.pub_cache = {}
        self.publisher = Zsock.new_xpub(("tcp://*:*").encode())

        # TimeServer
        self.timereply = Zsock.new_rep(("tcp://*:*").encode())

        # Zyre
        self.zyre = Zyre(None)
        if netiface:
            self.zyre.set_interface(string_at(netiface))
            self.interface.log("ZYRE Node forced netiface: ",
                               string_at(netiface))

        self.zyre.set_name(str(self.interface.hplayer.name()).encode())
        self.zyre.set_header(b"TS-PORT",
                             str(get_port(self.timereply)).encode())
        self.zyre.set_header(b"PUB-PORT",
                             str(get_port(self.publisher)).encode())

        self.zyre.set_interval(PING_PEER)
        self.zyre.set_evasive_timeout(PING_PEER * 3)
        self.zyre.set_silent_timeout(PING_PEER * 5)
        self.zyre.set_expired_timeout(PING_PEER * 10)

        self.zyre.start()
        self.zyre.join(b"broadcast")
        self.zyre.join(b"sync")

        # Add self to book
        self.book[self.zyre.uuid()] = Peer(
            self, {
                'uuid': self.zyre.uuid(),
                'name': self.zyre.name().decode(),
                'ip': '127.0.0.1',
                'ts_port': get_port(self.timereply),
                'pub_port': get_port(self.publisher)
            })
        self.book[self.zyre.uuid()].subscribe(self.topics)

        # Start Poller
        self._actor_fn = zactor_fn(
            self.actor_fn
        )  # ctypes function reference must live as long as the actor.
        if netiface:
            netiface = create_string_buffer(str.encode(netiface))
        self.actor = Zactor(self._actor_fn, netiface)
        self.done = False

    # ZYRE Zactor
    def actor_fn(self, pipe, netiface):

        # Internal
        internal_pipe = Zsock(pipe, False)  # We don't own the pipe, so False.

        # Poller
        poller = Zpoller(self.zyre.socket(), internal_pipe, self.publisher,
                         self.timereply, None)

        # RUN
        self.interface.log('Node started')
        internal_pipe.signal(0)

        while True:
            sock = poller.wait(500)
            if not sock:
                continue

            #
            # ZYRE receive
            #
            if sock == self.zyre.socket():
                e = ZyreEvent(self.zyre)
                uuid = e.peer_uuid()

                # self.interface.log("ZYREmsg", uuid, e.peer_name().decode(), e.type().decode())

                # ENTER: add to book for external contact (i.e. TimeSync)
                if e.type() == b"ENTER":
                    newpeer = Peer(self, e)
                    existing = None

                    if uuid in self.book:
                        # print ('UUID already exist: replacing')  ## PROBLEM : Same name may appear with different uuid (not a real problem, only if crash and restart with new uuid in a short time..)
                        self.book[uuid].stop()
                        existing = uuid

                    for p in self.book.values():
                        if p.name == newpeer.name:
                            # print ('Name already exist: replacing')
                            p.stop()
                            existing = p.uuid

                    if existing:
                        del self.book[existing]

                    self.book[uuid] = newpeer
                    self.book[uuid].subscribe(self.topics)

                # EVASIVE
                elif e.type() == b"EVASIVE":
                    # if uuid in self.book:
                    #     self.book[uuid].linker(2)
                    pass

                # SILENT
                elif e.type() == b"SILENT":
                    if uuid in self.book:
                        self.book[uuid].linker(1)

                # EXIT
                elif e.type() == b"EXIT":
                    if uuid in self.book:
                        self.book[uuid].linker(0)
                        self.book[uuid].stop()
                        del self.book[uuid]

                # JOIN
                elif e.type() == b"JOIN":
                    # self.interface.log("peer join a group..", e.peer_name(), e.group().decode())

                    # SYNC clocks
                    if e.group() == b"sync":
                        if self.peer(uuid):
                            self.peer(uuid).sync()

                # LEAVE
                elif e.type() == b"LEAVE":
                    # self.interface.log("peer left a group..")
                    pass

                # SHOUT -> process event
                elif e.type() == b"SHOUT" or e.type() == b"WHISPER":

                    # Parsing message
                    data = json.loads(e.msg().popstr().decode())
                    data['from'] = uuid

                    # add group
                    if e.type() == b"SHOUT": data['group'] = e.group().decode()
                    else: data['group'] = 'whisper'

                    self.preProcessor1(data)

            #
            # PUBLISHER event
            #
            elif sock == self.publisher:
                msg = Zmsg.recv(self.publisher)
                if not msg: break
                topic = msg.popstr()

                # Somebody subscribed: push Last Value Cache !
                if len(topic) > 0 and topic[0] == 1:
                    topic = topic[1:]
                    if topic in self.pub_cache:
                        # self.interface.log('XPUB lvc send for', topic.decode())
                        msg = Zmsg.dup(self.pub_cache[topic])
                        Zmsg.send(msg, self.publisher)

                    # else:
                    #     self.interface.log('XPUB lvc empty for', topic.decode())

            #
            # TIMESERVER event
            #
            elif sock == self.timereply:
                msgin = Zmsg.recv(self.timereply)
                msg = Zmsg()
                msg.addstr(str(int(time.time() * PRECISION)).encode())
                Zmsg.send(msg, self.timereply)

            #
            # INTERNAL commands
            #
            elif sock == internal_pipe:
                msg = Zmsg.recv(internal_pipe)
                if not msg or msg.popstr() == b"$TERM":
                    # print('ZYRE Node TERM')
                    break

        internal_pipe.__del__()
        self.interface.log(' - node stopped'
                           )  # WEIRD: print helps the closing going smoothly..
        self.done = True

    def stop(self):
        for peer in self.book.values():
            peer.stop()

        self.actor.sock().send(b"ss", b"$TERM")
        retry = 0
        while not self.done and retry < 10:
            sleep(0.1)
            retry += 1

        # self.zyre.stop()        # HANGS !
        self.zyre.__del__()
        self.publisher.__del__()
        self.timereply.__del__()

    def peer(self, uuid):
        if uuid in self.book and self.book[uuid].active:
            return self.book[uuid]

    def peerByName(self, name):
        for peer in self.book.values():
            if peer.active and peer.name == name:
                return peer

    #
    # PUB/SUB
    #

    def subscribe(self, topics):
        if not isinstance(topics, list): topics = [topics]
        self.topics = list(set(self.topics)
                           | set(topics))  # merge lists and remove duplicates
        for peer in self.book.values():
            peer.subscribe(self.topics)

    def publish(self, topic, args=None):
        topic = topic.encode()

        msg = Zmsg()
        msg.addstr(topic)
        msg.addstr(self.zyre.uuid())
        msg.addstr(json.dumps(args).encode())

        self.pub_cache[topic] = Zmsg.dup(msg)
        Zmsg.send(msg, self.publisher)

    #
    # ZYRE send messages
    #

    def makeMsg(self, event, args=None, delay_ms=0, at=0):
        data = {}
        data['event'] = event
        data['args'] = []
        if args:
            if not isinstance(args, list):
                # self.interface.log('NOT al LIST', args)
                args = [args]
            data['args'] = args

        # at time
        if at > 0:
            data['at'] = at

        # add delay
        if delay_ms > 0:
            if not 'at' in data:
                data['at'] = 0
            data['at'] += int(time.time() * PRECISION +
                              delay_ms * PRECISION / 1000)

        return json.dumps(data).encode()

    def whisper(self, uuid, event, args=None, delay_ms=0, at=0):
        data = self.makeMsg(event, args, delay_ms, at)
        if uuid == self.zyre.uuid():
            data = json.loads(data.decode())
            data['from'] = 'self'
            data['group'] = 'whisper'
            self.preProcessor1(data)
        else:
            self.zyre.whispers(uuid, data)

    def shout(self, group, event, args=None, delay_ms=0, at=0):
        data = self.makeMsg(event, args, delay_ms, at)
        self.zyre.shouts(group.encode(), data)

        # if own group -> send to self too !
        groups = zlist_strlist(self.zyre.own_groups())
        if group in groups:
            data = json.loads(data.decode())
            data['from'] = 'self'
            data['group'] = group
            self.preProcessor1(data)

    def broadcast(self, event, args=None, delay_ms=0, at=0):
        self.shout('broadcast', event, args, delay_ms, at)

    def join(self, group):
        self.zyre.join(group.encode())

    def leave(self, group):
        self.zyre.leave(group.encode())

    #
    # ZYRE messages processor
    #

    def preProcessor1(self, data):
        # if a programmed time is provided, correct it with peer CS
        # Set timer
        if 'at' in data:
            if self.peer(data['from']):
                data['at'] -= self.peer(data['from']).clockshift()
            delay = (data['at']) / PRECISION - time.time()

            if delay <= -10000:
                self.interface.log('WARNING event already passed by', delay,
                                   's, its too late !! discarding... ')
            elif delay <= 0:
                self.interface.log('WARNING event already passed by', delay,
                                   's, playing late... ')
                self.preProcessor2(data)
            elif delay > 3000:
                self.interface.log('WARNING event in', delay,
                                   's, thats weird, playing now... ')
                self.preProcessor2(data)
            else:
                self.interface.log('programmed event in', delay, 's')
                t = Timer(delay, self.preProcessor2, args=[data])
                t.start()
                self.interface.emit('planned', data)

        else:
            self.preProcessor2(data)

    def preProcessor2(self, data):
        self.interface.emit('event', *[data])
        self.interface.emit(data['event'], *data['args'])
Example #2
0
class FMMonitor(threading.Thread):
    def __init__(self, context, hostAddress, riapsHome):
        threading.Thread.__init__(self)
        self.logger = logging.getLogger(__name__)
        self.context = context
        self.hostAddress = hostAddress
        self.riapsHome = riapsHome
        self.control = None
        self.peers = {}  # uuid : address - all peers
        self.groups = {}  # groupName : { peers* } - peers in group
        self.actors = {}  # appName : { actors* }  - actors in apps
        self.uuid = None
        self.logger.info('FMMon:__inited__')

    def setup(self):
        self.logger.info('FMMon:setup()')
        self.control = self.context.socket(zmq.PAIR)
        self.control.bind(const.fmMonitorEndpoint)
        return self.control

    def getUUID(self):
        while self.uuid == None:
            time.sleep(0.1)
        return self.uuid

    def setupApp(self, appName):
        msg = ('setupApp', appName)
        self.control.send_pyobj(msg)

    def cleanupApp(self, appName):
        msg = ('cleanupApp', appName)
        self.control.send_pyobj(msg)

    def addActor(self, appName, actorName):
        msg = ('addActor', appName, actorName)
        self.control.send_pyobj(msg)

    def delActor(self, appName, actorName):
        msg = ('delActor', appName, actorName)
        self.control.send_pyobj(msg)

    def dieActor(self, appName, actorName):
        msg = ('dieActor', appName, actorName)
        self.control.send_pyobj(msg)

    def terminate(self):
        if self.control != None:
            self.control.send_pyobj(('stop', ))
        else:
            self.setup()
            time.sleep(0.1)
            self.control.send_pyobj(('stop', ))

    def groupName(self, appName):
        return b'riaps.' + appName.encode('utf-8')

    def run(self):
        self.zyre = Zyre(None)
        if self.logger.level > 0:
            self.zyre.set_verbose()
            # Zsys.set_logsystem(1)
        else:
            # Zsys.set_logsystem(0)
            pass
        self.uuid = self.zyre.uuid()
        self.zyre.set_interface(Config.NIC_NAME.encode('utf-8'))
        if Config.SECURITY:
            certFile = os.path.join(self.riapsHome, "keys",
                                    const.zmqCertificate)
            cert = czmq.Zcert.load(ctypes.c_char_p(certFile.encode('utf-8')))
            self.zyre.set_zcert(cert)
        self.zyre.set_evasive_timeout(const.peerEvasiveTimeout)
        self.zyre.set_expired_timeout(const.peerExpiredTimeout)
        self.zyre.set_header(b'riaps@' + self.hostAddress.encode('utf-8'),
                             b'hello')
        self.command = self.context.socket(zmq.PAIR)
        self.command.connect(const.fmMonitorEndpoint)
        self.zyre.start()
        self.zyre.join(b'riaps')
        self.zyreSocket = self.zyre.socket()
        self.poller = czmq.Zpoller(zyre.c_void_p(self.command.underlying),
                                   self.zyreSocket, 0)
        while True:
            reader = self.poller.wait(-1)  # Wait forever
            if self.poller.terminated():
                self.logger.warning("FMMon.run - poller terminated")
                break
            if type(
                    reader
            ) == zyre.c_void_p and reader.value == self.command.underlying:
                msg = self.command.recv_pyobj()
                self.logger.info('FMMon.run - command: %s' % str(msg))
                cmd = msg[0]
                if cmd == 'stop':
                    break
                elif cmd == 'setupApp':
                    appName = msg[1]
                    group = self.groupName(appName)
                    self.zyre.join(group)
                    if appName not in self.groups:
                        self.groups[appName] = set()
                        self.actors[appName] = set()
                elif cmd == 'cleanupApp':
                    appName = msg[1]
                    group = self.groupName(appName)
                    self.zyre.leave(group)
                    if appName in self.groups:
                        del self.groups[appName]
                elif cmd == 'addActor':
                    appName, actorName = msg[1:]
                    assert appName in self.groups
                    self.actors[appName].add(actorName)
                    group = self.groupName(appName)
                    arg = "+ %s.%s" % (appName, actorName)
                    self.logger.info("FMMon.addActor.shout: %s" % arg)
                    self.zyre.shouts(group, arg.encode('utf-8'))
                    for peer in self.groups[appName]:
                        self.logger.info(
                            "FMMon.addactor tell %s.%s has peer at %s" %
                            (appName, actorName, str(peer)))
                        info = ('peer+', appName, actorName, peer)
                        self.command.send_pyobj(info)
                elif cmd == 'delActor':
                    appName, actorName = msg[1:]
                    assert appName in self.groups and actorName in self.actors[
                        appName]
                    self.actors[appName].remove(actorName)
                    group = self.groupName(appName)
                    arg = "- %s.%s" % (appName, actorName)
                    self.logger.info("FMMon.delActor.shout: %s" % arg)
                    self.zyre.shouts(group, arg.encode('utf-8'))
                elif cmd == 'dieActor':
                    appName, actorName = msg[1:]
                    assert appName in self.groups and actorName in self.actors[
                        appName]
                    self.actors[appName].remove(actorName)
                    group = self.groupName(appName)
                    arg = "? %s.%s" % (appName, actorName)
                    self.logger.info("FMMon.dieActor.shout: %s" % arg)
                    self.zyre.shouts(group, arg.encode('utf-8'))
                else:
                    pass  # Should be error
            elif reader == self.zyreSocket:
                event = ZyreEvent(self.zyre)
                eType = event.type()
                _pName = event.peer_name()
                pUUID = event.peer_uuid()
                pAddr = event.peer_addr()
                group = event.group()
                _headers = event.headers()
                msg = event.get_msg()
                #                 if eType != b'EVASIVE':
                #                     print("# %s %s %s %s %s %s %s"
                #                           % (str(eType),str(_pName),str(pUUID),str(pAddr),
                #                              str(group),str(_headers),str(msg)))
                if eType == b'ENTER':
                    self.logger.info("FMMon.ENTER %s from %s" %
                                     (str(pUUID), str(pAddr)))
                    self.peers[pUUID] = pAddr
                elif eType == b'JOIN':
                    groupName = group.decode()
                    self.logger.info("FMMon.JOIN %s from %s" %
                                     (str(groupName), str(pUUID)))
                    if groupName == 'riaps':
                        continue  # Joined riaps group - should be validated
                    else:
                        _, appName = groupName.split('.')
                        if appName not in self.groups:
                            self.groups[appName] = {pUUID}
                            if appName not in self.actors:
                                self.actors[appName] = set()
                        else:
                            self.groups[appName].add(pUUID)
                        if appName in self.actors:
                            peer = pUUID
                            for actorName in self.actors[appName]:
                                arg = "+ %s.%s" % (appName, actorName)
                                self.logger.info(
                                    "FMMon.JOIN.whisper: %s to %s " %
                                    (arg, str(peer)))
                                self.zyre.whispers(peer, arg.encode('utf-8'))
                                self.logger.info(
                                    "FMMon.JOIN tell %s.%s has peer at %s" %
                                    (appName, actorName, str(peer)))
                                info = ('peer+', appName, actorName, peer)
                                self.command.send_pyobj(info)
                elif eType == b'LEAVE':
                    groupName = group.decode()
                    self.logger.info("FMMon.LEAVE %s from %s" %
                                     (str(pUUID), str(group)))
                    if groupName == 'riaps':
                        continue  # Left riaps group - should be validated
                    else:
                        _, appName = groupName.split('.')
                        if appName in self.groups:
                            self.groups[appName].remove(pUUID)
                        if appName in self.actors:
                            for actorName in self.actors[appName]:
                                peer = pUUID
                                self.logger.info(
                                    "FMMon.LEAVE tell %s.%s lost peer at %s" %
                                    (appName, actorName, str(peer)))
                                info = ('peer-', appName, actorName, peer)
                                self.command.send_pyobj(info)
                elif eType == b'EXIT':
                    self.logger.info("FMMon.EXIT %s " % (str(pUUID)))
                    for appName, group in self.groups.items():
                        if pUUID in group:
                            if appName in self.actors:
                                for actorName in self.actors[appName]:
                                    peer = pUUID
                                    self.logger.info(
                                        "FMMon.EXIT tell %s.%s lost peer at %s"
                                        % (appName, actorName, str(peer)))
                                    info = ('peer-', appName, actorName, peer)
                                    self.command.send_pyobj(info)
                    del self.peers[pUUID]
                elif eType == b'SHOUT' or eType == b'WHISPER':
                    arg = msg.popstr().decode()
                    self.logger.info("FMMon.SHOUT %s = %s " %
                                     (str(pUUID), arg))
                    peer = pUUID
                    cmd, pair = arg.split(' ')
                    appName, actorName = pair.split('.')
                    head, cast = '?', '?'
                    if cmd == '+':
                        head, cast = 'peer+', ' has peer '
                    elif cmd == '-':
                        head, cast = 'peer-', ' lost peer '
                    elif cmd == '?':
                        head, cast = 'peer-', ' lost peer '
                    if appName not in self.groups:
                        self.groups[appName] = {pUUID}
                    if appName in self.actors:
                        for actorName in self.actors[appName]:
                            self.logger.info("FMMon.%s: tell %s.%s %s %s" %
                                             (eType.decode(), appName,
                                              actorName, cast, str(peer)))
                            info = (head, appName, actorName, peer)
                            self.command.send_pyobj(info)
                else:
                    pass
        self.command.close()
        for appName in self.actors:
            if appName in self.groups:
                group = self.groupName(appName)
                arg = "- %s.%s" % (appName, actorName)
                self.logger.info("FMMon.terminate.shout: %s" % arg)
                self.zyre.shouts(group, arg.encode('utf-8'))
        self.zyre.leave(b'riaps')
        self.zyre.stop()
Example #3
0
class DhtPeerMon(threading.Thread):
    def __init__(self, context, hostAddress, riapsHome, dht, dhtPort):
        threading.Thread.__init__(self, daemon=True)
        self.logger = logging.getLogger(__name__)
        self.context = context
        self.hostAddress = hostAddress
        self.riapsHome = riapsHome
        self.control = None
        self.dht = dht
        self.dhtPort = dhtPort
        self.peers = {}  # uuid : address - all peers
        self.peerGroup = set()  # set(uuid) of peer group members
        self.uuid = None
        self.logger.info('DhtPeerMon:__inited__')

    def setup(self):
        self.logger.info('DhtPeerMon:setup()')
        self.control = self.context.socket(zmq.PAIR)
        self.control.bind(const.discoDhtPeerMonEndpoint)
        return self.control

    def terminate(self):
        if self.control != None:
            self.control.send_pyobj(('stop', ))
        else:
            self.setup()
            time.sleep(0.1)
            self.control.send_pyobj(('stop', ))

    def peerHeaderKey(self, ipAddress):
        return b'riaps_disco@' + ipAddress.encode('utf-8')

    PEERMARK = b'CAFE'
    PEERGROUP = b'riaps_disco'

    def run(self):
        self.zyre = Zyre(None)
        if self.logger.level == logging.DEBUG:
            self.zyre.set_verbose()
        else:
            pass
        self.uuid = self.zyre.uuid()
        self.zyre.set_interface(Config.NIC_NAME.encode('utf-8'))
        if Config.SECURITY:
            certFile = os.path.join(self.riapsHome, "keys",
                                    const.zmqCertificate)
            cert = czmq.Zcert.load(ctypes.c_char_p(certFile.encode('utf-8')))
            self.zyre.set_zcert(cert)
        self.zyre.set_evasive_timeout(const.peerEvasiveTimeout)
        self.zyre.set_expired_timeout(const.peerExpiredTimeout)
        self.zyre.set_header(self.peerHeaderKey(self.hostAddress),
                             self.PEERMARK)
        self.command = self.context.socket(zmq.PAIR)
        self.command.connect(const.discoDhtPeerMonEndpoint)
        self.zyre.start()
        self.zyre.join(self.PEERGROUP)
        self.zyreSocket = self.zyre.socket()
        self.poller = czmq.Zpoller(zyre.c_void_p(self.command.underlying),
                                   self.zyreSocket, 0)
        while True:
            reader = self.poller.wait(-1)  # Wait forever
            if self.poller.terminated():
                self.logger.info("DhtPeerMon.run - poller terminated")
                break
            if type(
                    reader
            ) == zyre.c_void_p and reader.value == self.command.underlying:
                msg = self.command.recv_pyobj()
                self.logger.info('DhtPeerMon.run - command: %s' % str(msg))
                cmd = msg[0]
                if cmd == 'stop':
                    break
                else:
                    pass  # Should be error
            elif reader == self.zyreSocket:
                event = ZyreEvent(self.zyre)
                eType = event.type()
                _pName = event.peer_name()
                pUUID = event.peer_uuid()
                pAddr = event.peer_addr()
                group = event.group()
                _headers = event.headers()
                msg = event.get_msg()
                #                 if eType != b'EVASIVE':
                #                     print("# %s %s %s %s %s %s %s"
                #                           % (str(eType),str(_pName),str(pUUID),str(pAddr),
                #                              str(group),str(_headers),str(msg)))
                if eType == b'ENTER':
                    self.logger.info("DhtPeerMon.ENTER %s from %s" %
                                     (str(pUUID), str(pAddr)))
                    try:
                        pAddrStr = pAddr.decode('UTF-8')
                        (peerIp,
                         _peerPort) = parse.parse("tcp://{}:{}", pAddrStr)
                        peerHeaderKey = self.peerHeaderKey(peerIp)
                        _value = _headers.lookup(peerHeaderKey)
                        if (_value):
                            try:
                                value = ctypes.cast(_value,
                                                    ctypes.c_char_p).value
                                assert value == self.PEERMARK
                                self.peers[pUUID] = peerIp
                                self.logger.info("DhtPeerMon.ENTER valid peer")
                            except:
                                self.logger.info(
                                    "DhtPeerMon.ENTER header value mismatch")
                        else:
                            self.logger.info(
                                "DhtPeerMon.ENTER header key mismatch")
                    except:
                        self.logger.info(
                            "DhtPeerMon.ENTER peer addr parsing error")
                elif pUUID not in self.peers:  # Skip the rest if this is not a peer
                    continue
                elif eType == b'JOIN':
                    groupName = group.decode()
                    peer = pUUID
                    self.logger.info("DhtPeerMon.JOIN %s from %s" %
                                     (str(groupName), str(pUUID)))
                    if groupName != self.PEERGROUP:
                        self.logger.info("DhtPeerMon.JOIN another group")
                        pass
                    else:
                        self.peerGroup.add(peer)
                        self.zyre.whispers(
                            peer,
                            ("%s://%d" %
                             (self.PEERGROUP, self.dhtPort)).encode('utf-8'))
                elif eType == b'SHOUT' or eType == b'WHISPER':
                    arg = msg.popstr().decode()
                    self.logger.info("DhtPeerMon.SHOUT %s = %s " %
                                     (str(pUUID), arg))
                    try:
                        pAddrStr = pAddr.decode('UTF-8')
                        (peerIp,
                         _peerPort) = parse.parse("tcp://{}:{}", pAddrStr)
                        assert peerIp == self.peers[pUUID]
                        peerDhtPort = parse.parse("%s://{}" % self.PEERGROUP,
                                                  arg)
                        if peerDhtPort:
                            self.logger.info("DhtPeerMon.bootstrap %s:%s" %
                                             (peerIp, peerDhtPort))
                            self.dht.bootstrap(str(peerIp), str(peerDhtPort))
                    except:
                        self.logger.error("DhtPeerMon.bootstrap failed")
                elif eType == b'LEAVE':
                    groupName = group.decode()
                    self.logger.info("DhtPeerMon.LEAVE %s from %s" %
                                     (str(pUUID), str(group)))
                    if groupName != self.PEERGROUP:
                        self.logger.info("DhtPeerMon.LEAVE another group")
                        pass
                    else:
                        self.peerGroup.discard(pUUID)
                elif eType == b'EXIT':
                    self.logger.info("DhtPeerMon.EXIT %s " % (str(pUUID)))
                    if pUUID in self.peers:
                        del self.peers[pUUID]
                        self.peerGroup.discard(pUUID)
                else:
                    pass
        self.command.close()
        self.zyre.leave(self.PEERGROUP)
        self.zyre.stop()