Ejemplo n.º 1
0
    def test_register(self):
        """test HalTransport#register.

        check whether none socket can be
        register, if the specific exception can't be catch case fail

        check
        whether the socket can be register, if the socket can't find in poller
        map case fail.

        :keyword:HalTransport#register
        :exception:assertEqual(str(e), "Cannot register to a None poller"),
                   assertIn(pullSock.socket, poller.poller._map)
        :parameter:
        :return:

        """
        pullSock = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode,
            index=20, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=None)

        poller = HalPoller()
        try:
            pullSock.register(None)
        except Exception as e:
            self.assertEqual(str(e), "Cannot register to a None poller")

        pullSock.register(poller)

        self.assertIn(pullSock.socket, poller.poller._map)

        pullSock.socket.disable_monitor()
        pullSock.monitor.close()
        pullSock.close()
Ejemplo n.º 2
0
    def test_poller(self):
        """test create HalPoller.

        check whether the socket can be register, if
        the socket can't find in poller map case fail

        check whether the socket
        can be unregister, if the socket can find in poller map case fail.

        :keyword:HalPoller
        :exception:assertIn(pullSock.socket, poller.poller._map),
                   assertNotIn(pullSock.socket, poller.poller._map)
        :parameter:
        :return:

        """
        pullSock = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode,
            index=20, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=None)

        poller = HalPoller()

        poller.register(pullSock.socket)
        self.assertIn(pullSock.socket, poller.poller._map)
        poller.unregister(pullSock.socket)
        self.assertNotIn(pullSock.socket, poller.poller._map)
        poller.register(pullSock.socket)

        socks = poller.poll(500)

        pullSock.socket.disable_monitor()
        pullSock.monitor.close()
        pullSock.close()
Ejemplo n.º 3
0
    def test_createTransport(self):

        transportMgr = HalTransport(
            HalTransport.HalTransportClientMgr, HalTransport.HalServerMode,
            disconnectHandlerCb=None)
        transportMgr.socket.disable_monitor()
        transportMgr.monitor.close()
        transportMgr.close()
        self.assertIsNotNone(transportMgr)
        try:
            shutil.rmtree(os.path.dirname("/tmp/HalUnitTest/"))
        except Exception as e:
            pass
        transportClient = HalTransport(
            HalTransport.HalTransportClientMgr, HalTransport.HalClientMode)
        transportClient.socket.disable_monitor()
        transportClient.monitor.close()
        transportClient.close()
        self.assertIsNotNone(transportClient)

        transportAgentPush = HalTransport(
            HalTransport.HalTransportClientAgentPush, HalTransport.HalServerMode,
            index=0, socketMode=HalTransport.HalSocketPushMode,
            disconnectHandlerCb=None)
        transportAgentPush.socket.disable_monitor()
        transportAgentPush.monitor.close()
        transportAgentPush.close()
        self.assertIsNotNone(transportAgentPush)

        transportAgentPull = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode,
            index=0, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=None)
        transportAgentPull.socket.disable_monitor()
        transportAgentPull.monitor.close()
        transportAgentPull.close()
        self.assertIsNotNone(transportAgentPull)

        transportAgentPull = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode,
            index=0, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=None)
        transportAgentPull.socket.disable_monitor()
        transportAgentPull.monitor.close()
        transportAgentPull.close()
        self.assertIsNotNone(transportAgentPull)

        # error case
        try:
            transport = HalTransport(1000, HalTransport.HalClientMode,
                                     index=0, socketMode=HalTransport.HalSocketPullMode,
                                     disconnectHandlerCb=None)
        except Exception as e:
            self.assertEqual(str(e), "Unsupported HalTransportType")
Ejemplo n.º 4
0
    def test_send(self):
        """test HalTransport#send.

        check whether none message can be send, if
        can't catch the specific exception case fail

        check whether hello
        message can be send, if the returned value is false case fail.

        :keyword:HalTransport#send
        :exception:assertRegexpMatches(str(e), "Cannot send the msg since the msg is None, agent.*"),
                   assertEqual(pushSock.send("hello"), True)
        :parameter:
        :return:

        """
        transport = HalTransport(
            HalTransport.HalTransportClientMgr, HalTransport.HalServerMode,
            disconnectHandlerCb=self._disconnectCb)

        try:
            transport.send(None)
        except Exception as e:
            self.assertRegexpMatches(
                str(e), "Cannot send the msg since the msg is None, agent.*")
        transport.socket.disable_monitor()
        transport.monitor.close()
        transport.close()

        pushSock = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode,
            index=19, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=None)
        self.assertEqual(pushSock.send("hello"), True)

        pushSock.socket.disable_monitor()
        pushSock.monitor.close()
        pushSock.close()
Ejemplo n.º 5
0
    def test_recv(self):
        """test HalTransport#recv.

        check if it can handle the method event, with
        the exception/logicality's correct

        check whether hello message can be
        receive after send out, if the returned value match case fail.

        :keyword:HalTransport#recv
        :exception:assertEqual(pullSock.recv(), "hello")
        :parameter:
        :return:

        """
        pullSock = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode,
            index=20, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=None)
        pullSock.socket.disable_monitor()
        pullSock.monitor.close()
        pullSock.close()

        pullSock = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode,
            index=20, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=None)
        pushSock = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode,
            index=20, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=None)

        pushSock.send("hello")
        print("Try to receive the message")
        self.assertEqual("hello", pullSock.recv())

        pullSock.socket.disable_monitor()
        pullSock.monitor.close()
        pullSock.close()

        pushSock.socket.disable_monitor()
        pushSock.monitor.close()
        pushSock.close()
Ejemplo n.º 6
0
class OpenRpdDriver(HalDriverClient):
    """The OpenRPD base driver

    """

    ##    __metaclass__ = AddLoggerToClass

    def __init__(self,
                 drvName,
                 drvDesc,
                 drvVer,
                 supportedMsgType,
                 supportedNotificationMsgs,
                 interestedNotification=None):
        """

        :param drvName: The driver name, such as Generic Driver
        :param drvDesc: driver for full Cable Labs RPHY support
        :param drvVer: driver version
        :param supportedMsgType: will support all RPHY OpenRPD message types
        :param supportedNotificationMsgs: the supported notification msg types
        :return: OpenRPD Driver object

        NOTES: The 'supportedNotificationMsgs' parameter passed to HalDriverClient
        and then forwarded to HalManager.py, but it seems HalManager.py does NOT
        do anything with this parameter.  Consider remove it from ClientProvision.proto?
        As of now, we don't need to have this parameter.  It just adds confusion!
        """

        if supportedMsgType is None:
            supportedMsgType = OpenRpdMsgHandler.default_supported_msg_types
        super(OpenRpdDriver,
              self).__init__(drvName, drvDesc, drvVer, supportedMsgType,
                             supportedNotificationMsgs, interestedNotification)

        # update the supported messages
        self.HalMsgsHandler = {
            "HalClientRegisterRsp": self.recv_register_msg_cb,
            "HalClientHelloRsp": self.recvHelloRspMsgCb,
            "HalConfig": self.recv_cfg_msg_cb,
            "HalConfigRsp": self.recv_cfg_msg_rsp_cb,
            "HalNotification": self.recvNotificationCb,
        }

        # Handlers for different configuration messages
        self.hal_config_msg_handlers = {
            HalConfigMsg.MsgTypeRpdCapabilities:
            OpenRpdMsgHandler.capabilities_get,
            HalConfigMsg.MsgTypeDsRfPort:
            OpenRpdMsgHandler.config_ds_port,
            HalConfigMsg.MsgTypeDsScQamChannelConfig:
            OpenRpdMsgHandler.config_dsqam_channel,
            HalConfigMsg.MsgTypeDsOfdmChannelConfig:
            OpenRpdMsgHandler.config_dsofdm_channel,
            HalConfigMsg.MsgTypeDsOfdmProfile:
            OpenRpdMsgHandler.config_dsofdm_profile,
            HalConfigMsg.MsgTypeDsRfPortPerf:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeDsScQamChannelPerf:
            OpenRpdMsgHandler.req_dsqam_channel_status,
            HalConfigMsg.MsgTypeDsOfdmChannelPerf:
            OpenRpdMsgHandler.req_dsofdm_channel_status,
            HalConfigMsg.MsgTypeDsOob551IPerf:
            OpenRpdMsgHandler.req_oob551_mod_status,
            HalConfigMsg.MsgTypeDsOob552Perf:
            OpenRpdMsgHandler.req_oob552_mod_status,
            HalConfigMsg.MsgTypeNdfPerf:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeUsRfPortPerf:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeUsScQamChannelConfig:
            OpenRpdMsgHandler.config_usatdma_channel,
            HalConfigMsg.MsgTypeUsOfdmaChannelConfig:
            OpenRpdMsgHandler.config_usofdma_channel,
            HalConfigMsg.MsgTypeUsOfdmaInitialRangingIuc:
            OpenRpdMsgHandler.config_dummy,
            HalConfigMsg.MsgTypeUsOfdmaFineRangingIuc:
            OpenRpdMsgHandler.config_dummy,
            HalConfigMsg.MsgTypeUsOfdmaDataRangingIuc:
            OpenRpdMsgHandler.config_dummy,
            HalConfigMsg.MsgTypeUsOfdmaDataIuc:
            OpenRpdMsgHandler.config_dummy,
            HalConfigMsg.MsgTypeUsOfdmaSubcarrierCfgState:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeUsScQamChannelPerf:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeUsOfdmaChannelPerf:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeUsOob551IPerf:
            OpenRpdMsgHandler.req_oob551_demod_status,
            HalConfigMsg.MsgTypeUsOob552Perf:
            OpenRpdMsgHandler.req_oob552_demod_status,
            HalConfigMsg.MsgTypeNdrPerf:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeSidQos:
            OpenRpdMsgHandler.config_sid_qos,
            # L2TPv3 messages
            HalConfigMsg.MsgTypeL2tpv3CapabilityQuery:
            OpenRpdMsgHandler.capabilities_get,
            HalConfigMsg.MsgTypeL2tpv3SessionReqNone:
            OpenRpdMsgHandler.req_depi_pw,
            HalConfigMsg.MsgTypeL2tpv3SessionReqDsOfdm:
            OpenRpdMsgHandler.req_depi_pw,
            HalConfigMsg.MsgTypeL2tpv3SessionReqDsOfdmPlc:
            OpenRpdMsgHandler.req_depi_pw,
            HalConfigMsg.MsgTypeL2tpv3SessionReqDsScqam:
            OpenRpdMsgHandler.req_depi_pw,
            HalConfigMsg.MsgTypeL2tpv3SessionReqUsAtdma:
            OpenRpdMsgHandler.req_uepi_pw,
            HalConfigMsg.MsgTypeL2tpv3SessionReqUsOfdma:
            OpenRpdMsgHandler.req_uepi_pw,
            HalConfigMsg.MsgTypeL2tpv3SessionReqScte551Fwd:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeL2tpv3SessionReqScte551Ret:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeL2tpv3SessionReqScte552Fwd:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeL2tpv3SessionReqScte552Ret:
            OpenRpdMsgHandler.req_dummy,
            HalConfigMsg.MsgTypeL2tpv3SessionReqNdf:
            OpenRpdMsgHandler.req_ndf,
            HalConfigMsg.MsgTypeL2tpv3SessionReqNdr:
            OpenRpdMsgHandler.req_ndr,

            # Ptp
            # HalConfigMsg.MsgTypeRdtiConfig:                  config_docsis_timer
            HalConfigMsg.MsgTypeL2tpv3CinIfAssignment:
            OpenRpdMsgHandler.cin_if_assign,
            HalConfigMsg.MsgTypeL2tpv3LcceIdAssignment:
            OpenRpdMsgHandler.lcce_id_assign,

            # VspAvpQuery
            HalConfigMsg.MsgTypeVspAvpExchange:
            OpenRpdMsgHandler.vsp_avp_handler,
            # RcpVendorSpecificTlv
            HalConfigMsg.MsgTypeRcpVendorSpecific:
            OpenRpdMsgHandler.vsp_tlv_handler,
        }

        self.disconnected = True
        self.dispatcher = Dispatcher()

        # setup the logging
        self.logger = OpenRpdMsgHandler.get_msg_handler_logger()
        self.logger.info("OpenRPD Driver Initialized")
        self.seqNum = 0

    # start modeled from HalPtpDriver.py

    def start(self, simulate_mode=False):
        """start poll the transport socket

        :return:

        """
        self.logger.info("Setup the Hal Transport connection...")
        self.connectionSetup()
        self.logger.info("Connection setup done...")

        self.logger.info("Register the driver with the Hal manager...")
        self.register(self.drvID)
        self.logger.info("End of register...")

        self.dispatcher.loop()

    def recv_register_msg_cb(self, cfg):
        """the callback handler for the configuration message
        Modified from base class by registering the sockets
        with dispatcher.

        :param cfg: the configuration message received from the Hal
        :return:

        """
        # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg))

        if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
            self.logger.error("Cannot register to Hal, reason[%s]" %
                              cfg.msg.Rsp.ErrorDescription)
            return

        self.drvID = cfg.msg.ClientID

        # Setup the push and pull connection
        self.pullPath = cfg.msg.PathFromHalToClient
        self.pushPath = cfg.msg.PathFromClientToHal

        # get the index of the path
        index = self._getIndexFromPath()
        if index == -1:
            self.logger.error("Cannot get index from the path [%s]" %
                              self.pushPath)
            return
        if self.index == -1:
            self.index = index
            self.pushSock = HalTransport(
                HalTransport.HalTransportClientAgentPull,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPushMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            self.pullSock = HalTransport(
                HalTransport.HalTransportClientAgentPush,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPullMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            # register driver's sockets with the dispatcher
            self.dispatcher.fd_register(self.pullSock.socket, zmq.POLLIN,
                                        self.openrpd_drv_hal_cb)
            self.dispatcher.fd_register(self.pushSock.monitor, zmq.POLLIN,
                                        self.openrpd_drv_hal_cb)
            self.dispatcher.fd_register(self.pullSock.monitor, zmq.POLLIN,
                                        self.openrpd_drv_hal_cb)

        # send Hello To Hal
        self.sayHelloToHal()
        if (None is not self.interestedNotification):
            self.sendInterestedNotifications(self.interestedNotification)

        self.disconnected = False

        return

    def connectionSetup(self):
        """Create the connection to the mgr

        :return:

        """
        self.logger.info("Create the connection to the mgr....")
        # Create a connection to Hal driver mgr
        self.mgrConnection = HalTransport(
            HalTransport.HalTransportClientMgr,
            HalTransport.HalClientMode,
            disconnectHandlerCb=self.disconnectCb)
        self.mgrConnection.connects()

        self.HalMsgsHandler[
            self.mgrConnection.socket] = self.recv_register_msg_cb

        # register the mgr socket with the dispatcher
        self.dispatcher.fd_register(self.mgrConnection.socket, zmq.POLLIN,
                                    self.openrpd_drv_hal_cb)
        self.dispatcher.fd_register(self.mgrConnection.monitor, zmq.POLLIN,
                                    self.openrpd_drv_hal_cb)

    def connection_cleanup(self):
        """Close the connection to the mgr

        :return:

        """
        if self.disconnected:
            self.logger.debug("A previous event has been processed, skip it!")
            return

        if self.mgrConnection is not None:
            self.dispatcher.fd_unregister(self.mgrConnection.socket)
            self.dispatcher.fd_unregister(self.mgrConnection.monitor)
            self.mgrConnection.socket.disable_monitor()
            self.mgrConnection.monitor.close()
            self.mgrConnection.socket.close()

        if self.pullSock is not None:
            self.dispatcher.fd_unregister(self.pullSock.socket)
            self.dispatcher.fd_unregister(self.pullSock.monitor)
            self.pullSock.socket.disable_monitor()
            self.pullSock.monitor.close()
            self.pullSock.socket.close()

        if self.pushSock is not None:
            self.dispatcher.fd_unregister(self.pushSock.monitor)
            self.pushSock.socket.disable_monitor()
            self.pushSock.monitor.close()
            self.pushSock.socket.close()

        self.disconnected = True

    def disconnectCb(self, msg):
        """A disconnect condition has been detected, 
        clean up the connection and then reconnect
        and re-register with the Hal.

        :param msg:
        :return:

        """
        self.logger.error("Detected disconnected condition")

        if self.disconnected:
            self.logger.info("A previous event has been processed, skip it!")
            return
        self.logger.info("Detected disconnected, registering again")
        # clean up the push and pull socket
        self.dispatcher.fd_unregister(self.mgrConnection.socket)
        self.dispatcher.fd_unregister(self.mgrConnection.monitor)
        self.mgrConnection.monitor.close()
        self.mgrConnection.close()

        # re-register the message
        self.connectionSetup()
        # The zmq lower part will handle the reconnect
        self.register(self.drvID)

        self.disconnected = True

    def openrpd_drv_hal_cb(self, sock, mask):
        self.logger.debug("Driver received hal cb event")
        if self.pushSock is not None and sock == self.pushSock.monitor:
            self.pushSock.monitorHandler(recv_monitor_message(sock))
            return
        if self.pullSock is not None and sock == self.pullSock.monitor:
            self.pullSock.monitorHandler(recv_monitor_message(sock))
            return

        if sock == self.mgrConnection.monitor:
            self.mgrConnection.monitorHandler(recv_monitor_message(sock))
            return

        while sock.getsockopt(zmq.EVENTS) and zmq.POLLIN:
            try:
                bin = sock.recv(flags=zmq.NOBLOCK)
                msg = HalMessage.DeSerialize(bin)
                self.logger.debug("Got a zmq msg:%s type:%s" %
                                  (msg.msg, msg.type))
                if msg.type in self.HalMsgsHandler:
                    handler = self.HalMsgsHandler[msg.type]
                    handler(msg)
            except zmq.ZMQError as e:
                self.logger.debug(
                    "Got an error when trying with nonblock read:" + str(e))
                break
            except Exception as e:
                self.logger.error("Got an un-expected error:%s", str(e))
                break

    def recvNotificationCb(self, ntf):
        """Receive a notification message from the HAL.

        :param ntf:
        :return:

        """
        try:
            handler = self.hal_config_msg_handlers[ntf.msg.HalNotificationType]
            self.logger.info("Receive a interest notification message:" +
                             str(ntf.msg))

            if not isinstance(ntf, HalMessage):
                raise AttributeError("Invalid HAL message passed")

            ntf = handler(ntf)
            if None is not ntf:
                self.send_cfg_msg(HalConfigMsg.MsgTypeVspAvpExchange,
                                  ntf.msg.HalNotificationPayLoad)
            else:
                self.logger.info("Notification message return is None")
        except Exception as e:
            self.logger.error("Got an error:%s, the ntf msg:%s", str(e),
                              ntf.msg)

    def send_cfg_msg(self, cfgMsgType, payload):
        msg = HalMessage("HalConfig",
                         SrcClientID=self.drvID,
                         CfgMsgType=cfgMsgType,
                         SeqNum=self.seqNum,
                         CfgMsgPayload=payload)
        self.logger.debug("sending config - type: %d, msg: %s" %
                          (cfgMsgType, msg))
        self.pushSock.send(msg.Serialize())
        self.seqNum += 1
        return

    def send_cfg_rsp_msg(self, cfg):
        """The configuration response routine

        :param cfg: The original configuration message
        :return:

        """
        result = HalCommon_pb2.SUCCESS
        cfgMsg = cfg.msg
        l2tpcfgmsgType = (HalConfigMsg.MsgTypeL2tpv3SessionReqDsOfdm,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqDsOfdmPlc,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqDsScqam,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqUsAtdma,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqUsOfdma,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqScte551Fwd,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqScte551Ret,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqScte552Fwd,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqScte552Ret,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqNdf,
                          HalConfigMsg.MsgTypeL2tpv3SessionReqNdr,
                          HalConfigMsg.MsgTypeL2tpv3CinIfAssignment,
                          HalConfigMsg.MsgTypeL2tpv3LcceIdAssignment)
        if cfgMsg.CfgMsgType in l2tpcfgmsgType:
            rsp = L2tpv3Hal_pb2.t_l2tpSessionRsp()
            req = L2tpv3Hal_pb2.t_l2tpSessionReq()
            req.ParseFromString(cfgMsg.CfgMsgPayload)
            # fill session_selector
            rsp.session_selector.local_session_id = req.session_selector.local_session_id
            rsp.session_selector.remote_session_id = req.session_selector.remote_session_id
            rsp.session_selector.local_ip = req.session_selector.local_ip
            rsp.session_selector.remote_ip = req.session_selector.remote_ip
            rsp.result = True
        elif (cfgMsg.CfgMsgType == HalConfigMsg.MsgTypeVspAvpExchange):
            rsp = L2tpv3VspAvp_pb2.t_l2tpVspAvpMsg()
            rsp.ParseFromString(cfgMsg.CfgMsgPayload)
            self.logger.debug(
                "vsp_avp_handler re-parse srcClientID: %s, Seq num:  %d, "
                "op: %d, vid %d, attr %d, strVal %s" %
                (cfg.msg.SrcClientID, cfg.msg.SeqNum, rsp.oper, rsp.vendorId,
                 rsp.attrType, rsp.attrValBuf))
            if rsp.rspCode == L2tpv3VspAvp_pb2.t_l2tpVspAvpMsg(
            ).VSP_AVP_STATUS_FAILURE:
                # send HalConfigRsp with failure status if OpenRPD driver can't handle this.
                result = HalCommon_pb2.FAILED
        elif (cfgMsg.CfgMsgType == HalConfigMsg.MsgTypeRcpVendorSpecific):
            rsp = t_RcpMessage()
            rsp.ParseFromString(cfgMsg.CfgMsgPayload)
            self.logger.debug("send_cfg_rsp_msg payload: %s, result: %d" %
                              (rsp.RpdDataMessage.RpdData, rsp.RcpDataResult))
        else:
            rsp = t_RcpMessage()
            rsp.ParseFromString(cfgMsg.CfgMsgPayload)
            self.logger.debug("send_cfg_rsp_msg payload: %s" %
                              rsp.RpdDataMessage.RpdData)
            rsp.RcpDataResult = t_RcpMessage.RCP_RESULT_OK
        payload = rsp.SerializeToString()

        self.logger.debug("cfg response srcClientID: %s, Seq num:  %d" %
                          (cfgMsg.SrcClientID, cfgMsg.SeqNum))
        msg = HalMessage("HalConfigRsp",
                         SrcClientID=cfgMsg.SrcClientID,
                         SeqNum=cfgMsg.SeqNum,
                         Rsp={
                             "Status": HalCommon_pb2.SUCCESS,
                             "ErrorDescription": ""
                         },
                         CfgMsgType=cfgMsg.CfgMsgType,
                         CfgMsgPayload=payload)
        self.logger.debug("sending cfg response - type: %d, msg: %s" %
                          (cfgMsg.CfgMsgType, msg))
        self.pushSock.send(msg.Serialize())

    def recv_cfg_msg_rsp_cb(self, cfg):
        cfgMsg = cfg.msg
        self.logger.debug("receive cfg response - type: %d" %
                          (cfgMsg.CfgMsgType))
        pass

    def recv_cfg_msg_cb(self, cfg):
        """Receive a configuration message from the Hal, processing it

        :param cfg:
        :return:

        """
        try:
            handler = self.hal_config_msg_handlers[cfg.msg.CfgMsgType]
            self.logger.info("Received a cfg message type: %d",
                             cfg.msg.CfgMsgType)

            if not isinstance(cfg, HalMessage):
                raise AttributeError("Invalid HAL message passed")

            cfg = handler(cfg)
            self.send_cfg_rsp_msg(cfg)
        except Exception as e:
            self.logger.error("Got an error:%s, the cfg msg:%s", str(e),
                              cfg.msg)

    def cleanup_sockets(self):
        for fd in self.fd_to_socket:
            sock = self.fd_to_socket[fd]
            self.poller.unregister(sock)
            sock.close()
        self.fd_to_socket.clear()
Ejemplo n.º 7
0
class ProvMgrHalDriver(HalDriverClient):
    __metaclass__ = AddLoggerToClass

    ntfmsg_list = [
        MsgTypeRpdCapabilities,
    ]
    cfgmsg_list = [
        MsgTypeCcapCoreIdentification,
        MsgTypeRedundantCoreIpAddress,
        MsgTypeRpdCtrl,
    ]

    def __init__(self,
                 drvName,
                 drvDesc,
                 drvVer,
                 supportedMsgType,
                 supportedNotificationMsgs,
                 interestedNotification,
                 dispatcher,
                 logConfigurePath=None,
                 mgr=None):
        """

        :param drvName:
        :param drvDesc:
        :param drvVer:
        :param supportedMsgType:
        :param supportedNotificationMsgs:
        :param dispatcher:
        :param logConfigurePath:
        :param mgr:
        """
        super(ProvMgrHalDriver,
              self).__init__(drvName, drvDesc, drvVer, supportedMsgType,
                             supportedNotificationMsgs, interestedNotification)

        self.mgr = mgr
        self.rpd_cap = None
        self.dispatcher = dispatcher

        self.HalConfigMsgHandlers = {
            MsgTypeCcapCoreIdentification: self.recvCcapCoreIdentification,
            MsgTypeRedundantCoreIpAddress: self.recvRedundantCoreIpAddress,
            MsgTypeRpdCtrl: self.recvRpdResetCtrl,
        }

        self.HalNtfHandlers = {
            MsgTypeRpdCapabilities: self.recvRpdCapabilities,
        }

        self.HalConfigMsgRspHandlers = {
            MsgTypeRpdCapabilities: self.recMsgTypeRpdCapabilitiesRspCb,
        }

    RESET_CTRL_FILENAME = '/rpd/config/reset_ctrl'

    def recvRegisterMsgCb(self, cfg):
        # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg))

        if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
            self.logger.error("Cannot register to Hal, reason[%s]" %
                              cfg.msg.Rsp.ErrorDescription)
            return

        self.drvID = cfg.msg.ClientID

        # Setup the push and pull connection
        self.pullPath = cfg.msg.PathFromHalToClient
        self.pushPath = cfg.msg.PathFromClientToHal

        # get the index of the path
        index = self._getIndexFromPath()
        if index == -1:
            self.logger.error("Cannot get index from the path [%s]" %
                              self.pushPath)
            return
        if self.index == -1:
            self.index = index
            self.pushSock = HalTransport(
                HalTransport.HalTransportClientAgentPull,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPushMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            self.pullSock = HalTransport(
                HalTransport.HalTransportClientAgentPush,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPullMode,
                disconnectHandlerCb=self.connectionDisconnectCb)
            # register to the poller
            self.dispatcher.fd_register(self.pullSock.socket, zmq.POLLIN,
                                        self.provmgr_cb)
            self.dispatcher.fd_register(self.pushSock.monitor, zmq.POLLIN,
                                        self.provmgr_cb)
            self.dispatcher.fd_register(self.pullSock.monitor, zmq.POLLIN,
                                        self.provmgr_cb)
        # send Hello To Hal
        self.sayHelloToHal()
        if self.interestedNotification is not None:
            self.sendInterestedNotifications(self.interestedNotification)

        self.disconnected = False

        return

    def sendCfgRspMsg(self, cfg, rsp=None):
        """The configuration response routine, the driver implementor should
        fill sth into this function.

        :param cfg: The original configuration message
        :param rsp: respond
        :return:

        """
        cfgMsg = cfg.msg
        msg = HalMessage("HalConfigRsp",
                         SrcClientID=cfgMsg.SrcClientID,
                         SeqNum=cfgMsg.SeqNum,
                         Rsp=rsp,
                         CfgMsgType=cfgMsg.CfgMsgType,
                         CfgMsgPayload=cfgMsg.CfgMsgPayload)
        self.send(msg.Serialize())

    def recvCfgMsgCb(self, cfgMsg):
        """Receive a configuration message from the Hal, processing it.

        :param cfgMsg:
        :return:

        """
        try:
            msgType = cfgMsg.msg.CfgMsgType
            if msgType not in self.HalConfigMsgHandlers \
                    or self.HalConfigMsgHandlers[msgType] is None:
                rsp = {
                    "Status": HalCommon_pb2.NOTSUPPORTED,
                    "ErrorDescription": "msgType %d is not supported" % msgType
                }
            else:
                rsp = self.HalConfigMsgHandlers[msgType](cfgMsg.msg)

        except Exception as e:  # pragma: no cover
            self.logger.error("Got an error:%s, the cfg msg:%s", str(e),
                              cfgMsg.msg)
            rsp = {
                "Status":
                HalCommon_pb2.FAILED,
                "ErrorDescription":
                "Process configuration failed, reason:%s" % str(e)
            }

        self.sendCfgRspMsg(cfgMsg, rsp)

    def recvCfgMsgRspCb(self, cfg):
        """Receive a configuration response message from the Hal, processing it.

        :param cfg:
        :return:

        """
        self.logger.debug("Recv a configuration response message:" +
                          str(cfg.msg.CfgMsgType))
        if cfg.msg.CfgMsgType in self.HalConfigMsgRspHandlers:
            cb = self.HalConfigMsgRspHandlers[cfg.msg.CfgMsgType]
            cb(cfg)

    def sendNotificationMsg(self, notificationType, notificationPayload):
        """Send a notification to Hal.

        :param notificationType: The notification type, the client must
         declare the notification type to Hal first
        :param notificationPayload: the string payload, Hal will not touch
         this part
        :return:

        """
        self.logger.debug("send a a notification message to Hal")
        if self.disconnected:
            self.logger.warning(
                "The client is on disconnected state,"
                " skip to send the message, notification type:%s",
                notificationType)
            return

        if notificationType is None or not isinstance(notificationPayload,
                                                      str):
            self.logger.warning("Cannot send a None or incorrect type to HAL, "
                                "str is required for msg.")
            return

        notification = HalMessage("HalNotification",
                                  ClientID=self.drvID,
                                  HalNotificationType=notificationType,
                                  HalNotificationPayLoad=notificationPayload)
        self.send(notification.Serialize())

    def recvNotificationCb(self, ntf):
        """Receive a notification message from the HAL.

        :param ntf:
        :return:

        """
        self.logger.info("Receive a interest notification message:" +
                         str(ntf.msg))
        self.recvNtf += 1
        try:
            msgType = ntf.msg.HalNotificationType
            if msgType in self.HalNtfHandlers:
                self.HalNtfHandlers[msgType](ntf.msg.HalNotificationPayLoad)
            else:
                self.logger.debug(
                    "Receive a interest notification message: no handler for %s",
                    str(msgType))
        except Exception as e:
            self.logger.error("Got an error:%s, the ntf msg:%s", str(e),
                              str(msgType))

    def recvHelloRspMsgCb(self, hello):
        """Call back for Hello Message.

        :param hello:
        :return:

        """
        self.logger.debug("Recv a hello message")
        self.sendRpdCapReq()

    def connectionSetup(self, dispatcher):
        """Create the connection to the mgr and setup the poller.

        :return:

        """
        self.logger.debug("Create the connection to the mgr....")
        # Create a connection to Hal driver mgr
        self.mgrConnection = HalTransport(
            HalTransport.HalTransportClientMgr,
            HalTransport.HalClientMode,
            disconnectHandlerCb=self.connectionDisconnectCb)

        # create the poller
        if self.poller is None:
            self.poller = dispatcher.get_poll()

        # register the mgr socket
        dispatcher.fd_register(self.mgrConnection.socket, zmq.POLLIN,
                               self.provmgr_cb)
        dispatcher.fd_register(self.mgrConnection.monitor, zmq.POLLIN,
                               self.provmgr_cb)

    def connectionDisconnectCb(self, msg):
        """The connection has been detected disconnected , register it again.

        :param msg:
        :return:

        """

        if self.disconnected:
            self.logger.debug("A previous event has been processed, skip it!")
            return
        self.logger.debug("Detected disconnected, register again")

        self.poller.unregister(self.mgrConnection.socket)
        self.poller.unregister(self.mgrConnection.monitor)
        self.mgrConnection.socket.disable_monitor()
        self.mgrConnection.monitor.close()
        self.mgrConnection.close()

        # re-register the message
        self.connectionSetup(self.dispatcher)
        self.register(self.drvID)
        # The zmq lower part will handle the reconnect

        self.disconnected = True

    def start(self):
        """start poll the transport socket.

        :return:

        """
        self.logger.debug("Start the driver poll...")
        try:
            self.connectionSetup(self.dispatcher)
            self.register(self.drvID)
        except Exception as e:
            self.logger.warn("ProvMgr hal client start fail exception %s",
                             str(e))

    def provmgr_cb(self, sock, mask):
        if self.pushSock is not None and sock == self.pushSock.monitor:
            self.pushSock.monitorHandler(recv_monitor_message(sock))
            return
        if self.pullSock is not None and sock == self.pullSock.monitor:
            self.pullSock.monitorHandler(recv_monitor_message(sock))
            return
        if self.mgrConnection is not None and sock == self.mgrConnection.monitor:
            self.mgrConnection.monitorHandler(recv_monitor_message(sock))
            return

        while sock.getsockopt(zmq.EVENTS) and zmq.POLLIN:
            try:
                bin = sock.recv(flags=zmq.NOBLOCK)
                msg = HalMessage.DeSerialize(bin)
                if msg.type in self.HalMsgsHandler:
                    handler = self.HalMsgsHandler[msg.type]
                    handler(msg)
            except zmq.ZMQError as e:
                self.logger.debug(
                    "Got an error when trying with non-block read:" + str(e))
                break
            except Exception as e:
                self.logger.warn(
                    "Exception happens when provmgr hal recv socket, reason:%s"
                    % str(e))
                break

    def DeSerializeConfigMsgPayload(self, cfgMsg):
        if cfgMsg.CfgMsgPayload is None:
            return None
        cfgMsgPayload = t_RcpMessage()
        cfgMsgPayload.ParseFromString(cfgMsg.CfgMsgPayload)
        return cfgMsgPayload

    def recvCcapCoreIdentification(self, cfgMsg):
        rcp_msg = self.DeSerializeConfigMsgPayload(cfgMsg)
        if rcp_msg is None:
            return {
                "Status": HalCommon_pb2.FAILED,
                "ErrorDescription": "DeSerialize ConfigMsgPayload fail"
            }
        self.logger.debug(
            "ProvMgr driver receive Config CcapCoreIdentification %s" %
            str(rcp_msg))
        if rcp_msg.RpdDataMessage.RpdDataOperation == t_RpdDataMessage.RPD_CFG_READ:
            rcp_msg.RcpDataResult = t_RcpMessage.RCP_RESULT_OK
            del rcp_msg.RpdDataMessage.RpdData.CcapCoreIdentification[0]
            for key in CcapCoreIdentification.get_keys():
                ccapCoreIdent = rcp_msg.RpdDataMessage.RpdData.CcapCoreIdentification.add(
                )
                ccapCore = CcapCoreIdentification(key)
                ccapCore.read()

                ccapCoreIdent.Index = key
                ccapCoreIdent.CoreId = ccapCore.core_id
                ccapCoreIdent.CoreIpAddress = ccapCore.core_ip_addr
                ccapCoreIdent.IsPrincipal = ccapCore.is_principal
                ccapCoreIdent.CoreName = ccapCore.core_name
                ccapCoreIdent.VendorId = ccapCore.vendor_id
                ccapCoreIdent.InitialConfigurationComplete = ccapCore.initial_configuration_complete
                ccapCoreIdent.MoveToOperational = ccapCore.move_to_operational
                ccapCoreIdent.CoreFunction = ccapCore.core_function
                ccapCoreIdent.ResourceSetIndex = ccapCore.resource_set_index
                ccapCoreIdent.CoreMode = ccapCore.core_mode
                self.logger.debug("ProvMgr driver rsp ccapCoreIdent tlv %s" %
                                  ccapCoreIdent)
            cfgMsg.CfgMsgPayload = rcp_msg.SerializeToString()

            rsp = {
                "Status": HalCommon_pb2.SUCCESS,
                "ErrorDescription": "Serialize ConfigMsgPayload success"
            }
            return rsp
        if rcp_msg.RpdDataMessage.RpdDataOperation == t_RpdDataMessage.RPD_CFG_WRITE or \
           rcp_msg.RpdDataMessage.RpdDataOperation == t_RpdDataMessage.RPD_CFG_ALLOCATE_WRITE:
            rsp = {
                "Status":
                HalCommon_pb2.SUCCESS_IGNORE_RESULT,
                "ErrorDescription":
                "manager hal ignore write and allocate write for ccapCoreIdentification"
            }
            return rsp

    def recvRedundantCoreIpAddress(self, cfgMsg):
        rcp_msg = self.DeSerializeConfigMsgPayload(cfgMsg)
        self.logger.info("ProvMgr driver receive RedundantCoreIpAddress %s" %
                         str(rcp_msg))
        rsp = {"Status": HalCommon_pb2.SUCCESS, "ErrorDescription": "success"}
        return rsp

    def recvRpdResetCtrl(self, cfgMsg):
        rcp_msg = self.DeSerializeConfigMsgPayload(cfgMsg)
        if rcp_msg is None:
            return {
                "Status": HalCommon_pb2.FAILED,
                "ErrorDescription": "DeSerialize ConfigMsgPayload fail"
            }
        self.logger.debug("\nProvMgr receive RpdResetCtrl:" + str(rcp_msg))
        operation = rcp_msg.RpdDataMessage.RpdDataOperation

        recv_rcp_msg = rcp_msg.RpdDataMessage.RpdData
        if recv_rcp_msg.HasField("RpdCtrl") and recv_rcp_msg.RpdCtrl.HasField(
                "ResetCtrl"):
            if operation not in [
                    t_RpdDataMessage.RPD_CFG_WRITE,
                    t_RpdDataMessage.RPD_CFG_READ
            ]:
                return {
                    "Status":
                    HalCommon_pb2.FAILED,
                    "ErrorDescription":
                    "Operation %d for RpdResetCtrl is not supported" %
                    operation
                }
            rcp_rpd_resetctrl = recv_rcp_msg.RpdCtrl.ResetCtrl
            if operation == t_RpdDataMessage.RPD_CFG_WRITE:
                reset = rcp_rpd_resetctrl.Reset
                reset_type = rcp_tlv_def.RESET_TYPE[reset]
                with open(self.RESET_CTRL_FILENAME, 'w') as f:
                    f.write(str(reset) + ":" + str(reset_type) + "\n")
                for ccap_core in CCAPCore.ccap_core_db.values():
                    ccap_core.del_ccap_core()
                SysTools.reboot(reset_type)
            if operation == t_RpdDataMessage.RPD_CFG_READ:
                try:
                    with open(self.RESET_CTRL_FILENAME, 'r') as fr:
                        reset_rd = fr.read()
                        rcp_rpd_resetctrl.Reset = int(reset_rd.strip(":")[0])
                except IOError:
                    # file don't exist,skip check
                    pass
            cfgMsg.CfgMsgPayload = rcp_msg.SerializeToString()
            return {
                "Status":
                HalCommon_pb2.SUCCESS,
                "ErrorDescription":
                "ProMgr handle RpdResetCtrl success for %d" % operation
            }
        else:
            return {
                "Status": HalCommon_pb2.SUCCESS_IGNORE_RESULT,
                "ErrorDescription": "ProvMgr Do not Have RpdCtrl Filed."
            }

    def valid_rpd_cap(self, rcp_rpd_cap):
        # check the instance
        if not isinstance(rcp_rpd_cap, t_RpdCapabilities):
            return False
        # check it is not the default value
        default_cap = t_RpdCapabilities()
        GCPObject.default_gpb(default_cap)
        if rcp_rpd_cap == default_cap:
            return False

        return True

    def recMsgTypeRpdCapabilitiesRspCb(self, halrspmsg):
        try:
            # Check the status
            if halrspmsg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
                # yes, we recv a error message from HAL
                self.logger.warning("Receive a hal fail message:%s" %
                                    halrspmsg.msg)
                return False

            cfg_rsp = t_RcpMessage()
            cfg_rsp.ParseFromString(halrspmsg.msg.CfgMsgPayload)
            if cfg_rsp.RcpDataResult != t_RcpMessage.RCP_RESULT_OK:
                # yes we recv a error msg from driver
                self.logger.warning("Recv a driver fail message:%s" %
                                    str(cfg_rsp))
                return False
            rcp_rpd_cap = cfg_rsp.RpdDataMessage.RpdData.RpdCapabilities
            if not self.valid_rpd_cap(rcp_rpd_cap):
                self.logger.debug(
                    "Receive invalid RpdCapabilities rsp from driver")
                return False
            if not self.rpd_cap:
                self.rpd_cap = t_RpdCapabilities()
            self.rpd_cap.CopyFrom(rcp_rpd_cap)
            self.logger.debug("Receive RpdCapabilities rsp from driver")
            return True
        except Exception as e:
            self.logger.warning("cap fail %s", str(e))
            return False

    def recvRpdCapabilities(self, ntfMsg):
        rpd_cap = t_RpdCapabilities()
        rpd_cap.ParseFromString(ntfMsg)
        if not self.valid_rpd_cap(rpd_cap):
            self.logger.warning(
                "ProvMgr receive invalid rpdCapabilities notification from driver"
            )
            return
        self.rpd_cap = rpd_cap
        self.logger.debug("Receive rpdCapabilities notification:  %s",
                          str(self.rpd_cap))
        return

    def sendRpdCapReq(self):
        try:
            if self.rpd_cap:
                self.logger.debug(
                    "Already has Rpd cap in store, no need to send req")
                return True
            rcp_msg = t_RcpMessage()
            rcp_msg.RcpDataResult = t_RcpMessage.RCP_RESULT_OK
            rcp_msg.RcpMessageType = t_RcpMessage.RPD_CONFIGURATION
            rpd_data_msg = t_RpdDataMessage()
            rpd_data_msg.RpdDataOperation = t_RpdDataMessage.RPD_CFG_READ
            rcp_cfg = config()
            sub_tlv = rcp_cfg.RpdCapabilities
            GCPObject.default_gpb(gpb=sub_tlv)
            rpd_data_msg.RpdData.CopyFrom(rcp_cfg)
            rcp_msg.RpdDataMessage.CopyFrom(rpd_data_msg)

            cfgMsgContent = rcp_msg.SerializeToString()
            msg = HalMessage("HalConfig",
                             SrcClientID=self.drvID,
                             SeqNum=self.seqNum,
                             CfgMsgType=MsgTypeRpdCapabilities,
                             CfgMsgPayload=cfgMsgContent)
            self.send(msg.Serialize())
            self.seqNum += 1
            self.logger.debug("send RPD capabilities req to hal driver")
            return True
        except Exception as e:
            self.logger.warning("send RPD cap req failed :%s", str(e))
            return False

    def sendOperationalStatusNtf(self, operational):
        """
        :param operational:  True or False to represent the current operational status
        :return:
        """
        led_msg = t_LED()
        led_msg.setLed.ledType = led_msg.LED_TYPE_STATUS
        led_msg.setLed.color = led_msg.LED_COLOR_GREEN
        if operational:
            led_msg.setLed.action = led_msg.LED_ACTION_LIT
        else:
            led_msg.setLed.action = led_msg.LED_ACTION_DARK
        self.logger.debug("Set led notification message: %s", led_msg)
        self.sendNotificationMsg(MsgTypeSetLed, led_msg.SerializeToString())
Ejemplo n.º 8
0
class CliHalIpc(object):
    """
    The Client for Hal
    """
    __metaclass__ = AddLoggerToClass

    def __init__(self, appName, appDesc, appVer, interestedNotification, logConfigurePath=None):
        """
        :param appName: The application name, such as RPD CLI
        :param appDesc: A brief description about this application, such as the functionality description
        :param appVer: Driver specific version, such as 1.0.1
        :param interestedNotification: a tuple or list for the application interested msg types, the form will be
                                       (1, 2, 456, 10)
        :return: HalClient object
        """
        # sanity check the input args
        if not isinstance(appName, str) or not isinstance(appDesc, str) or not isinstance(appVer, str):
            raise HalClientError("Driver name/desc/version should be a str type")

        if not isinstance(interestedNotification, tuple) and not isinstance(interestedNotification, list):
            raise HalClientError("supportedMsgType should be a tuple or list")

        self.appName = appName
        self.appDesc = appDesc
        self.appVer = appVer
        self.interestedNotification = list(interestedNotification)

        # setup the logging
        # self.logger = log
        self.pollTimeout = 2000

        # update the supported messages
        self.HalMsgsHandler = {
            "HalClientRegisterRsp": self.recvRegisterMsgCb,
            "HalClientHelloRsp": self.recvHelloRspMsgCb,
            "HalClientInterestNotificationCfgRsp": self.sendInterestedNotificationsRspCb,
        }

        self.clientID = None

        self.mgrConnection = None
        self.pushSock = None
        self.pullSock = None

        self.disconnected = True

        self.seqNum = 0
        self.index = -1
        self.CfgMsgId_dict = dict(CLI_TO_HAL_MSG_TYPE.items())

    def start(self):
        """
        start poll the transport socket
        :return:
        """
        self.logger.debug("Start connect to hal...")
        self.connectionSetup()

        self.register(self.clientID)

    def connectionSetup(self):
        """
        Create the connection to the mgr and setup the poller
        :return:
        """
        self.logger.debug("Create the connection to the mgr....")
        # Create a connection to Hal driver mgr
        self.mgrConnection = HalTransport(HalTransport.HalTransportClientMgr, HalTransport.HalClientMode,
                                          disconnectHandlerCb=self.connectionDisconnectCb)

    def register(self, clientID):
        """
        send a register message to Hal and get the device ID from the Hal.
        :return:
        """
        if clientID is None:
            registerMsg = HalMessage("HalClientRegister",
                                     ClientName=self.appName,
                                     ClientDescription=self.appDesc,
                                     ClientVersion=self.appVer)
        else:
            registerMsg = HalMessage("HalClientRegister",
                                     ClientName=self.appName,
                                     ClientDescription=self.appDesc,
                                     ClientVersion=self.appVer,
                                     ClientID=clientID)

        if self.mgrConnection is None:
            errMsg = "Cannot send the register since the mgr connection is not setup"
            self.logger.error(errMsg)
            raise HalClientError(errMsg)
        self.logger.debug("Send the register msg to Hal...")
        self.mgrConnection.send(registerMsg.Serialize())
        bin = self.mgrConnection.recv()
        rsp = HalMessage.DeSerialize(bin)
        self.recvRegisterMsgCb(rsp)

    def _send(self, msg):
        if self.pushSock:
            self.pushSock.send(msg)
        else:
            self.logger.error("Cannot send the msg since the push socket is NULL")

    def sendMsg(self, cfgMsg):
        """
        The configutaion response routine, the driver implementor should fill
        sth into this function
        :param cfg: The original configutaion message
        :return:
        """
        if self.disconnected:
            self.logger.error("The client is on disconencted state,"
                              " skip to send the message.")
            return

        if cfgMsg is None or not isinstance(cfgMsg, t_CliMessage):
            self.logger.error("Cannot send a None or incorrect type to HAL")
            return

        for desc, value in cfgMsg.CliData.ListFields():
            if desc.name not in self.CfgMsgId_dict:
                self.logger.error("Cannot not find %s" % desc.name)
                return
            msg = HalMessage("HalConfig", SrcClientID=self.clientID,
                             SeqNum=self.seqNum,
                             CfgMsgType=self.CfgMsgId_dict[desc.name],
                             CfgMsgPayload=cfgMsg.SerializeToString())
            self._send(msg.Serialize())

            seq = self.seqNum
            self.seqNum += 1
            return seq

    def recvMsg(self, timeout=None):
        if self.pullSock:
            try:
                bin = self.pullSock.recv()
            except Exception as e:
                print("Got exception when receiving the msg, reason:%s" % str(e))
                return None
            rsp = HalMessage.DeSerialize(bin)
            if rsp.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
                self.logger.error("Get rsp msg fail, reason[%s]" % rsp.msg.Rsp.ErrorDescription)
                return None
            cli_msg = t_CliMessage()
            cli_msg.ParseFromString(rsp.msg.CfgMsgPayload)
            return cli_msg
        else:
            self.logger.error("Cannot receive msg since the pull socket is NULL")
            return None

    def sayHelloToHal(self):
        """
        Send a hello message to verify the agent path is correct
        :return:
        """
        self.logger.debug("Send a Hello message to Hal")
        helloMsg = HalMessage("HalClientHello", ClientID=self.clientID)
        self._send(helloMsg.Serialize())

    def sendInterestedNotifications(self, notifications):
        """
        Send the notifications to the HAL
        :param notifications:
        :return:
        """
        self.logger.debug("Send a Interested notification configuration msg to HAL")
        if notifications is not None and not isinstance(notifications, tuple) and not isinstance(notifications, list):
            self.logger.error("Cannot set an notification with wrong type, you can pass a tuple or list to it ")
            return
        configMsg = HalMessage("HalClientInterestNotificationCfg", ClientID=self.clientID,
                               ClientNotificationMessages=notifications)
        self.mgrConnection.send(configMsg.Serialize())
        # REQ/RSP
        bin = self.mgrConnection.recv()
        return bin

    def sendInterestedNotificationsRspCb(self, rsp):
        """
        Receive a response message from the HAL for the notification rsp callback
        :param rsp:
        :return:
        """
        self.logger.debug("Receive a interest notification response message:" + str(rsp.msg))

    def recvHelloRspMsgCb(self, hello):
        """
        Call back for Hello Message
        :param hello:
        :return:
        """
        self.logger.debug("Recv a hello message:" + str(hello.msg))

    def connectionDisconnectCb(self, msg):
        """
        the connection has been detected disconnected , register it again
        We have reconenct, we have to assure the regiter message is received by the HAL
        :param msg:
        :return:
        """

        if self.disconnected:
            self.logger.debug("A previous event has been processed, skip it!")
            return
        self.logger.debug("Detected disconnected, register again")
        # clean up the push and pull socket
        if 0:
            self.pushSock.close()
            self.pullSock.close()

            self.pushSock = None
            self.pullSock = None
            self.mgrConnection = None
            # self.clientID = None #will not set it to none since

            self.connectionSetup()

        self.mgrConnection.monitor.close()
        self.mgrConnection.close()

        # create the connection again
        self.connectionSetup()
        self.register(self.clientID)  # The zmq lower part will handle the reconnect

        self.disconnected = True

    def recvRegisterMsgCb(self, cfg):
        """
        the callback handler for the configuration message
        :param cfg: the configuration message received frm the Hal
        :return:
        """
        # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg))

        if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
            self.logger.error("Cannot register to Hal, reason[%s]" % cfg.msg.Rsp.ErrorDescription)
            return

        self.clientID = cfg.msg.ClientID

        # Setup the push and pull connection
        self.pullPath = cfg.msg.PathFromHalToClient
        self.pushPath = cfg.msg.PathFromClientToHal

        # get the index of the path
        index = self._getIndexFromPath()
        if index == -1:
            self.logger.error("Cannot get index from the path [%s]" % self.pushPath)
            return
        if self.index == -1:
            self.index = index
            self.pushSock = HalTransport(HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode,
                                         index=index, socketMode=HalTransport.HalSocketPushMode,
                                         disconnectHandlerCb=self.connectionDisconnectCb)

            self.pullSock = HalTransport(HalTransport.HalTransportClientAgentPush, HalTransport.HalClientMode,
                                         index=index, socketMode=HalTransport.HalSocketPullMode,
                                         disconnectHandlerCb=self.connectionDisconnectCb)

        self.sendInterestedNotifications(self.interestedNotification)

        self.disconnected = False

        return

    def clientQuery(self):
        """
        Send a client query message to get all registered client info
        :return:
        """

        if self.disconnected:
            self.logger.error("The client is on disconencted state,"
                              " skip to send the message.")
            return None
        self.logger.debug("Send a client query message to Hal")
        clientQueryMsg = HalMessage("HalClientQuery", ClientID=self.clientID)
        self.mgrConnection.send(clientQueryMsg.Serialize())
        try:
            bin = self.mgrConnection.recv()
        except Exception as e:
            print("Got exception when receiving the msg, reason:%s" % str(e))
            return None
        rsp = HalMessage.DeSerialize(bin)
        if rsp.msg.MsgType != "HalClientQueryRsp":
            self.logger.error("Cannot Query client, "
                              "reason[msgType mismatch:%s]" % rsp.msg.MsgType)
            return None
        return rsp

    def getClientstats(self, clientId):
        """
        Send a client statistics request message
        :return:
        """

        if self.disconnected:
            self.logger.error("The client is on disconencted state,"
                              " skip to send the message.")
            return None
        self.logger.debug("Send a client statistics message to Hal")
        statsQueryMsg = HalMessage("HalAgentStatsReq", ClientID=clientId)
        self.mgrConnection.send(statsQueryMsg.Serialize())
        try:
            bin = self.mgrConnection.recv()
        except Exception as e:
            print("Got exception when receiving the msg, reason:%s" % str(e))
            return None
        rsp = HalMessage.DeSerialize(bin)
        if rsp.msg.MsgType != "HalAgentStatsRsp":
            self.logger.error("Cannot Query client statistics, "
                              "reason[msgType mismatch:%s]" % rsp.msg.MsgType)
            return None
        return rsp

    def _getIndexFromPath(self):
        rePattern = r"/(\d+)/"
        ret = re.search(rePattern, self.pushPath)

        if ret is not None:
            digitStr = ret.group(1)
            return int(digitStr)

        return -1
Ejemplo n.º 9
0
    def test_eventHandlerMonitor(self):
        """test HalTransport#monitorHandler,

        check whether the
        EVENT_DISCONNECTED can be handle, if status is false case fail

        check
        whether the EVENT_CONNECT_RETRIED can be handle, if status before the
        timeout/after timeout was wrong, case fail

        check whether the
        EVENT_CLOSED can be handle, if status before the timeout/after timeout
        was wrong, case fail

        check whether the unnormal event can be handle, if
        status was wrong case fail.

        :keyword:HalTransport#monitorHandler
        :exception:assertFalse(transport.monitorHandler(msg)),
                   assertFalse(transport.monitorHandler(msg)),
                   assertFalse(transport.monitorHandler(msg)),
                   assertFalse(transport.monitorHandler(msg))
        :parameter:
        :return:

        """
        transport = HalTransport(
            HalTransport.HalTransportClientMgr, HalTransport.HalServerMode,
            disconnectHandlerCb=None)

        msg = {
            "event": zmq.EVENT_DISCONNECTED,
        }
        self.assertFalse(transport.monitorHandler(msg))
        transport.socket.disable_monitor()
        transport.monitor.close()
        transport.close()

        transport = HalTransport(
            HalTransport.HalTransportClientMgr, HalTransport.HalServerMode,
            disconnectHandlerCb=self._disconnectCb)
        self.assertTrue(transport.monitorHandler(msg))

        msg = {
            "event": zmq.EVENT_CONNECT_RETRIED,
        }
        self.assertFalse(transport.monitorHandler(msg))
        time.sleep(transport.socketLogTimeout)
        self.assertTrue(transport.monitorHandler(msg))

        transport.socket.disable_monitor()
        transport.monitor.close()
        transport.close()

        transport = HalTransport(
            HalTransport.HalTransportClientMgr, HalTransport.HalServerMode,
            disconnectHandlerCb=self._disconnectCb)
        msg = {
            "event": zmq.EVENT_CLOSED,
        }
        self.assertFalse(transport.monitorHandler(msg))
        time.sleep(transport.socketLogTimeout)
        self.assertTrue(transport.monitorHandler(msg))

        msg = {
            "event": 10001,
        }
        self.assertFalse(transport.monitorHandler(msg))

        transport.socket.disable_monitor()
        transport.monitor.close()
        transport.close()
Ejemplo n.º 10
0
class HalDriverClient(object):
    """The Driver Client for Hal."""

    __metaclass__ = AddLoggerToClass

    def __init__(self,
                 drvName,
                 drvDesc,
                 drvVer,
                 supportedMsgType,
                 supportedNotificationMsgs,
                 interestedNotification=None):
        """Init.

        :param drvName: The driver name, such as BCM3160 Driver
        :param drvDesc: A brief description about this driver, such as the driver main functionality description
        :param drvVer: Driver specific version, such as 1.0.1
        :param supportedMsgType: a tuple or list for the driver supported msg types, the form will be (1, 2, 456, 10)
        :param supportedNotificationMsgs: the driver supported notification msg types the form will be (1, 3, 4)
        :return: HalDriverClient object

        """
        # sanity check the input args
        if not isinstance(drvName, str) or not isinstance(
                drvDesc, str) or not isinstance(drvVer, str):
            raise HalDriverClientError(
                "Driver name/desc/version should be a str type")

        if not isinstance(supportedMsgType, tuple) and not isinstance(
                supportedMsgType, list):
            raise HalDriverClientError(
                "supportedMsgType should be a tuple or list")

        if (supportedNotificationMsgs is not None) and (
                not isinstance(supportedNotificationMsgs, list)
                and not isinstance(supportedNotificationMsgs, tuple)):
            raise HalDriverClientError(
                "supportedNotificationMsgs is allowed none or tuple or list")

        self.drvname = drvName
        self.drvDesc = drvDesc
        self.drvVer = drvVer
        if None is not interestedNotification:
            self.interestedNotification = list(interestedNotification)
        else:
            self.interestedNotification = None
        self.supportedMsgType = list(supportedMsgType)
        if supportedNotificationMsgs is not None:
            self.supportedNotificationMsgs = list(supportedNotificationMsgs)
        else:
            self.supportedNotificationMsgs = None
        self.recvNtf = 0

        self.pollTimeout = 1000

        # update the supported messages
        self.HalMsgsHandler = {
            "HalClientRegisterRsp": self.recvRegisterMsgCb,
            "HalClientHelloRsp": self.recvHelloRspMsgCb,
            "HalConfig": self.recvCfgMsgCb,
            "HalConfigRsp": self.recvCfgMsgRspCb,
            "HalClientInterestNotificationCfgRsp":
            self.sendInterestedNotificationsRspCb,
            "HalNotification": self.recvNotificationCb,
        }

        self.drvID = None

        self.mgrConnection = None
        self.pushSock = None
        self.pullSock = None

        self.pullPath = None
        self.pushPath = None

        self.disconnected = True
        self.poller = None

        self.index = -1
        self.seqNum = 0

    def start(self):
        """Start polling the transport socket.

        :return:

        """
        self.logger.debug("Start the driver client poll...")
        self.connectionSetup()

        self.register(self.drvID)
        lastTimeout = time()

        while True:  # Todo we should support quit flag?
            socks = self.poller.poll(self.pollTimeout)
            if time() - lastTimeout > self.pollTimeout / 1000:
                lastTimeout = time()
                # self.logger.debug("Got a timeout event")
                if self.recvNtf:
                    rcp_msg = t_RcpMessage()
                    rcp_msg.RpdDataMessage.RpdDataOperation = t_RpdDataMessage.RPD_CFG_READ
                    rcp_msg.RcpMessageType = t_RcpMessage.RPD_CONFIGURATION
                    rcp_msg.RpdDataMessage.RpdData.CopyFrom(config())
                    payload = rcp_msg.SerializeToString()
                    self.sendCfgMsg(1025, payload)
                    self.recvNtf -= 1

            if not socks:
                continue
            for sock in socks:
                if self.pushSock is not None and sock == self.pushSock.monitor:
                    self.pushSock.monitorHandler(recv_monitor_message(sock))
                    continue
                if self.pullSock is not None and sock == self.pullSock.monitor:
                    self.pullSock.monitorHandler(recv_monitor_message(sock))
                    continue
                if sock == self.mgrConnection.monitor:
                    self.mgrConnection.monitorHandler(
                        recv_monitor_message(sock))
                    continue
                if socks[sock] == HalPoller.POLLIN:
                    try:
                        bin = sock.recv(flags=zmq.NOBLOCK)
                        msg = HalMessage.DeSerialize(bin)
                        self.logger.debug("Got a zmq msg:%s" % msg.msg)
                        if msg.type in self.HalMsgsHandler:
                            handler = self.HalMsgsHandler[msg.type]
                            handler(msg)
                        else:
                            self.logger.warn("Unsupported msg type:%s" %
                                             msg.type)
                    except zmq.ZMQError as e:
                        self.logger.debug(
                            "Geting an error when trying with nonblock read:" +
                            str(e))
                    except Exception as e:
                        self.logger.debug("Geting an error:" + str(e))
                continue

    def connectionSetup(self):
        """Create the connection to the mgr and setup the poller.

        :return:

        """
        self.logger.debug("Create the connection to the mgr....")
        # Create a connection to Hal driver mgr
        self.mgrConnection = HalTransport(HalTransport.HalTransportClientMgr,
                                          HalTransport.HalClientMode)
        self.mgrConnection.connects()

        self.HalMsgsHandler[self.mgrConnection.socket] = self.recvRegisterMsgCb
        # create the poller
        if self.poller is None:
            self.poller = HalPoller()

        # register the mgr socket
        self.poller.register(self.mgrConnection.socket)
        self.poller.register(self.mgrConnection.monitor)

    def register(self, driverID):
        """Send a register message to Hal and get the client ID from the Hal.

        :return:

        """
        if driverID is None:
            registerMsg = HalMessage(
                "HalClientRegister",
                ClientName=self.drvname,
                ClientDescription=self.drvDesc,
                ClientVersion=self.drvVer,
                ClientSupportedMessages=self.supportedMsgType,
                ClientSupportedNotificationMessages=self.
                supportedNotificationMsgs)
        else:
            registerMsg = HalMessage(
                "HalClientRegister",
                ClientName=self.drvname,
                ClientDescription=self.drvDesc,
                ClientVersion=self.drvVer,
                ClientSupportedMessages=self.supportedMsgType,
                ClientSupportedNotificationMessages=self.
                supportedNotificationMsgs,
                ClientID=driverID)

        if self.mgrConnection is None:
            errMsg = "Cannot send the register since the mgr connection is not setup"
            self.logger.error(errMsg)
            raise HalDriverClientError(errMsg)
        self.logger.debug("Send the register msg to Hal...")
        self.mgrConnection.send(registerMsg.Serialize())

    def send(self, msg):
        if self.pushSock:
            self.pushSock.send(msg)
        else:
            self.logger.warning(" ".join([
                str(self.drvname),
                str(self.drvID),
                ":Cannot send the msg since the push socket is none"
            ]))

    def sayHelloToHal(self):
        """Send a hello message to verify the agent path is correct.

        :return:

        """
        self.logger.debug(" ".join([
            str(self.drvname),
            str(self.drvID), ":Send a Hello message to Hal"
        ]))
        helloMsg = HalMessage("HalClientHello", ClientID=self.drvID)
        self.send(helloMsg.Serialize())

    def recvHelloRspMsgCb(self, hello):
        """Call back for Hello Message.

        :param hello:
        :return:

        """
        self.logger.debug("Recv a hello message")

    def sendInterestedNotifications(self, notifications):
        """Send the notifications to the HAL.

        :param notifications:
        :return:

        """
        self.logger.debug(
            "Send a Interested notification configuration msg to HAL")
        if notifications is not None and not isinstance(
                notifications, tuple) and not isinstance(notifications, list):
            self.logger.error(
                "Cannot set an notification with wrong type, you can pass a tuple or list to it "
            )
            return
        configMsg = HalMessage("HalClientInterestNotificationCfg",
                               ClientID=self.drvID,
                               ClientNotificationMessages=notifications)
        self.mgrConnection.send(configMsg.Serialize())

    def sendInterestedNotificationsRspCb(self, rsp):
        """Receive a response message from the HAL for the notification rsp
        callback.

        :param rsp:
        :return:

        """
        self.logger.debug("Receive a interest notification response message:" +
                          str(rsp.msg))

    def recvNotificationCb(self, ntf):
        """Receive a notification message from the HAL.

        :param ntf:
        :return:

        """
        self.logger.debug("Receive a interest notification message:" +
                          str(ntf.msg))
        self.recvNtf += 1

    def recvCfgMsgCb(self, cfg):
        """Receive a configuration message from the Hal, processing it.

        :param cfg:
        :return:

        """
        self.logger.debug(
            "Recv a configuration message, send a fake rsp to it")
        self.sendCfgRspMsg(cfg)

    def recvCfgMsgRspCb(self, cfg):
        """Receive a configuration response message from the Hal, processing it.

        :param cfg:
        :return:

        """
        self.logger.debug("Recv a configuration response message:" +
                          str(cfg.msg))

    def connectionSetupCb(self):
        pass

    def connectionDisconnectCb(self, msg):
        """The connection has been detected disconnected , register it again.

        :param msg:
        :return:

        """

        if self.disconnected:
            self.logger.debug("A previous event has been processed, skip it!")
            return
        self.logger.debug("Detected disconnected, register again")
        # clean up the push and pull socket
        # self.poller.unregister(self.pullSock.socket)

        self.poller.unregister(self.mgrConnection.socket)
        self.poller.unregister(self.mgrConnection.monitor)
        self.mgrConnection.socket.disable_monitor()
        self.mgrConnection.monitor.close()
        self.mgrConnection.close()

        # re-register the message
        self.connectionSetup()
        self.register(self.drvID)
        # The zmq lower part will handle the reconnect

        self.disconnected = True

    def sendNotificationMsg(self, notificationType, notificationPayload):
        """Send a notification to Hal.

        :param notificationType: The notification type, the client must declare the notification type to Hal first
        :param notificationPayload: the string payload, Hal will not touch this part
        :return:

        """
        self.logger.debug("send a a notification message to Hal")
        notfication = HalMessage("HalNotification",
                                 ClientID=self.drvID,
                                 HalNotificationType=notificationType,
                                 HalNotificationPayLoad=notificationPayload)
        self.send(notfication.Serialize())

    def sendCfgMsg(self, cfgMsgType, cfgMsgContent):
        """The configutaion response routine, the driver implementor should
        fill sth into this function.

        :param cfg: The original configuration message
        :return:

        """
        self.logger.debug("Send a config message to HAL: %r", cfgMsgContent)

        if self.disconnected:
            self.logger.warn(
                "The client is on disconencted state, skip to send the message."
            )
            return

        if cfgMsgContent is None or not isinstance(cfgMsgContent, str):
            self.logger.error(
                "Cannot send a None or incorrect type to HAL, str is required for msg"
            )
            return

        msg = HalMessage("HalConfig",
                         SrcClientID=self.drvID,
                         SeqNum=self.seqNum,
                         CfgMsgType=cfgMsgType,
                         CfgMsgPayload=cfgMsgContent)
        self._sendMsg(msg.Serialize())

        seq = self.seqNum
        self.seqNum += 1
        return seq

    def sendCfgRspMsg(self, cfg, rsp=None):
        """The configuration response routine, the driver implementor should
        fill sth into this function.

        :param cfg: The original configuration message
        :param rsp: respond
        :return:

        """
        cfgMsg = cfg.msg

        if rsp == None:
            rsp = {"Status": HalCommon_pb2.SUCCESS, "ErrorDescription": ""}

        msg = HalMessage("HalConfigRsp",
                         SrcClientID=cfgMsg.SrcClientID,
                         SeqNum=cfgMsg.SeqNum,
                         Rsp=rsp,
                         CfgMsgType=cfgMsg.CfgMsgType,
                         CfgMsgPayload=cfgMsg.CfgMsgPayload)
        if None is not self.pushSock:
            self.pushSock.send(msg.Serialize())

    def recvRegisterMsgCb(self, cfg):
        """The callback handler for the configuration message.

        :param cfg: the configuration message received frm the Hal
        :return:

        """
        # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg))

        if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
            self.logger.error("Cannot register to Hal, reason[%s]" %
                              cfg.msg.Rsp.ErrorDescription)
            return

        self.drvID = cfg.msg.ClientID

        # Setup the push and pull connection
        self.pullPath = cfg.msg.PathFromHalToClient
        self.pushPath = cfg.msg.PathFromClientToHal

        # get the index of the path
        index = self._getIndexFromPath()
        if index == -1:
            self.logger.error("Cannot get index from the path [%s]" %
                              self.pushPath)
            return
        if self.index == -1:
            self.index = index
            self.pushSock = HalTransport(
                HalTransport.HalTransportClientAgentPull,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPushMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            self.pullSock = HalTransport(
                HalTransport.HalTransportClientAgentPush,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPullMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            # register to the poller
            self.poller.register(self.pushSock.monitor)
            self.poller.register(self.pullSock.monitor)
            self.poller.register(self.pullSock.socket)

        # send Hello To Hal
        self.sayHelloToHal()
        if None is not self.interestedNotification:
            self.sendInterestedNotifications(self.interestedNotification)

        self.disconnected = False

        return

    def _getIndexFromPath(self):
        rePattern = r"/(\d+)/"
        ret = re.search(rePattern, self.pushPath)

        if ret is not None:
            digitStr = ret.group(1)
            return int(digitStr)

        return -1

    def _sendMsg(self, msg):
        if self.pushSock:
            self.pushSock.send(msg)
        else:
            self.logger.error(
                "Cannot send the msg since the push socket is NULL")
Ejemplo n.º 11
0
class HalClient(object):
    """The Client for Hal."""

    __metaclass__ = AddLoggerToClass

    def __init__(self,
                 appName,
                 appDesc,
                 appVer,
                 interestedNotification,
                 logConfigurePath=None,
                 supportedMsgType=[]):
        """
        :param appName: The application name, such as RPD CLI
        :param appDesc: A brief description about this application, such as the functionality description
        :param appVer: Driver specific version, such as 1.0.1
        :param interestedNotification: a tuple or list for the application interested msg types, the form will be
                                       (1, 2, 456, 10)
        :param supportedMsgType: a tuple or list of HalConfig message types, the form will be (5000,)
        :return: HalClient object

        """
        # sanity check the input args
        if not isinstance(appName, str) or not isinstance(
                appDesc, str) or not isinstance(appVer, str):
            raise HalClientError(
                "Driver name/desc/version should be a str type")

        if not isinstance(interestedNotification, tuple) and not isinstance(
                interestedNotification, list):
            raise HalClientError(
                "interestedNotification should be a tuple or list")

        if not isinstance(supportedMsgType, list):
            raise HalClientError("supportedMsgType should be a list")

        self.appName = appName
        self.appDesc = appDesc
        self.appVer = appVer
        self.interestedNotification = list(interestedNotification)
        self.supportedMsgType = list(supportedMsgType)

        self.pollTimeout = 2000

        # update the supported messages
        self.HalMsgsHandler = {
            "HalClientRegisterRsp":
            self.recvRegisterMsgCb,
            "HalSetLoggingLevelRsp":
            self.recvHalSetLoggingLevelRspCb,
            "HalClientHelloRsp":
            self.recvHelloRspMsgCb,
            "HalConfigRsp":
            self.recvCfgMsgRspCb,
            "HalClientInterestNotificationCfgRsp":
            self.sendInterestedNotificationsRspCb,
        }

        self.clientID = None

        self.mgrConnection = None
        self.pushSock = None
        self.pullSock = None

        self.disconnected = True
        self.poller = None

        self.seqNum = 0
        self.index = -1

    def start(self):
        """Start polling the transport socket.

        :return:

        """
        self.logger.debug("Start the client poll...")
        self.connectionSetup()

        self.register(self.clientID)
        lastTimeout = time()

        sendOnce = False

        while True:  # Todo we should support quit flag?
            socks = self.poller.poll(self.pollTimeout)

            if time() - lastTimeout > self.pollTimeout / 1000:
                lastTimeout = time()
                self.logger.debug("Got a timeout event")
                if not sendOnce:
                    # self.sendCfgMsg(100, "hello")
                    self.setHalDebugLevel("HalMain", logging.INFO)
                    sendOnce = True

            if not socks:
                continue
            for sock in socks:  # FIXME do we need to continue recv from the monitor interface?
                if self.pushSock is not None and sock == self.pushSock.monitor:
                    self.pushSock.monitorHandler(recv_monitor_message(sock))
                    continue
                if self.pullSock is not None and sock == self.pullSock.monitor:
                    self.pullSock.monitorHandler(recv_monitor_message(sock))
                    continue
                if self.mgrConnection is not None and sock == self.mgrConnection.monitor:
                    self.mgrConnection.monitorHandler(
                        recv_monitor_message(sock))
                    continue
                if socks[sock] == HalPoller.POLLIN:
                    try:
                        bin = sock.recv(flags=zmq.NOBLOCK)
                        msg = HalMessage.DeSerialize(bin)
                        self.logger.debug("Got a zmq msg:%s" % msg.msg)
                        if msg.type in self.HalMsgsHandler:
                            handler = self.HalMsgsHandler[msg.type]
                            handler(msg)
                        else:
                            self.logger.warn("Unsupported msg type:%s" %
                                             msg.type)
                    except zmq.ZMQError as e:
                        self.logger.debug(
                            "Got an error when trying with non-block read:" +
                            str(e))
                    except Exception as e:
                        self.logger.error("Error happens, reason:%s" % str(e))
                continue
                # self.logger.error("Cannot handle the event, No handler for
                # it")

    def connectionSetup(self):
        """Create the connection to the mgr and setup the poller.

        :return:

        """
        self.logger.debug("Create the connection to the mgr....")
        # Create a connection to Hal driver mgr
        self.mgrConnection = HalTransport(
            HalTransport.HalTransportClientMgr,
            HalTransport.HalClientMode,
            disconnectHandlerCb=self.connectionDisconnectCb)

        self.HalMsgsHandler[self.mgrConnection.socket] = self.recvRegisterMsgCb
        # create the poller
        if self.poller is None:
            self.poller = HalPoller()

        # register the mgr socket
        self.poller.register(self.mgrConnection.socket)
        self.poller.register(self.mgrConnection.monitor)

    def register(self, clientID):
        """Send a register message to Hal and get the client ID from the Hal.

        :return:

        """
        if clientID is None:
            if len(self.supportedMsgType) > 0:
                registerMsg = HalMessage(
                    "HalClientRegister",
                    ClientName=self.appName,
                    ClientDescription=self.appDesc,
                    ClientVersion=self.appVer,
                    ClientSupportedMessages=self.supportedMsgType)
            else:
                registerMsg = HalMessage("HalClientRegister",
                                         ClientName=self.appName,
                                         ClientDescription=self.appDesc,
                                         ClientVersion=self.appVer)
        else:
            if len(self.supportedMsgType) > 0:
                registerMsg = HalMessage(
                    "HalClientRegister",
                    ClientName=self.appName,
                    ClientDescription=self.appDesc,
                    ClientVersion=self.appVer,
                    ClientSupportedMessages=self.supportedMsgType,
                    ClientID=clientID)
            else:
                registerMsg = HalMessage("HalClientRegister",
                                         ClientName=self.appName,
                                         ClientDescription=self.appDesc,
                                         ClientVersion=self.appVer,
                                         ClientID=clientID)

        if self.mgrConnection is None:
            errMsg = "Cannot send the register since the mgr connection is not setup"
            self.logger.error(errMsg)
            raise HalClientError(errMsg)
        self.logger.debug("Send the register msg to Hal...")
        self.mgrConnection.send(registerMsg.Serialize())

    def _sendMsg(self, msg):
        if self.pushSock:
            self.pushSock.send(msg)
        else:
            self.logger.error(
                "Cannot send the msg since the push socket is None, msg:%s",
                str(msg))

    def sayHelloToHal(self):
        """Send a hello message to verify the agent path is correct.

        :return:

        """
        self.logger.debug(" ".join([
            str(self.appName),
            str(self.clientID), ":Send a Hello message to Hal"
        ]))
        helloMsg = HalMessage("HalClientHello", ClientID=self.clientID)
        self._sendMsg(helloMsg.Serialize())

    def sendNotificationMsg(self, notificationType, notificationPayload):
        """Send a notification to Hal.

        :param notificationType: The notification type, the client must declare the notification type to Hal first
        :param notificationPayload: the string payload, Hal will not touch this part
        :return:

        """
        self.logger.debug("send a notification message to Hal")
        notfication = HalMessage("HalNotification",
                                 ClientID=self.clientID,
                                 HalNotificationType=notificationType,
                                 HalNotificationPayLoad=notificationPayload)
        self.pushSock.send(notfication.Serialize())

    def sendInterestedNotifications(self, notifications):
        """Send the notifications to the HAL.

        :param notifications:
        :return:

        """
        self.logger.debug(
            "Send a Interested notification configuration msg to HAL")
        if notifications is not None and not isinstance(
                notifications, tuple) and not isinstance(notifications, list):
            self.logger.error(
                "Cannot set an notification with wrong type, you can pass a tuple or list to it "
            )
            return
        configMsg = HalMessage("HalClientInterestNotificationCfg",
                               ClientID=self.clientID,
                               ClientNotificationMessages=notifications)
        self.mgrConnection.send(configMsg.Serialize())

    def sendInterestedNotificationsRspCb(self, rsp):
        """Receive a response message from the HAL for the notification rsp
        callback.

        :param rsp:
        :return:

        """
        self.logger.debug("Receive a interest notification response message:" +
                          str(rsp.msg))

    def recvHelloRspMsgCb(self, hello):
        """Call back for Hello Message.

        :param hello:
        :return:

        """
        self.logger.debug("Recv a hello message:" + str(hello.msg))

    def recvCfgMsgRspCb(self, cfg):
        """Receive a configuration response message from the Hal, processing
        it.

        :param cfg:
        :return:

        """
        self.logger.debug("Recv a configuration response message:" +
                          str(cfg.msg))

    def connectionSetupCb(self):
        pass

    def connectionDisconnectCb(self, msg):
        """TODO: This comment is confusing. Need to be cleaned up.

        The connection has been detected disconnected , register it again
        We have reconenct, we have to assure the regiter message is received by the HAL

        :param msg:
        :return:

        """

        if self.disconnected:
            self.logger.debug("A previous event has been processed, skip it!")
            return
        self.logger.debug("Detected disconnected, register again")
        # clean up the push and pull socket
        if 0:
            self.pushSock.close()
            self.pullSock.close()

            self.poller.unregister(self.pullSock.socket)
            self.poller.unregister(self.pullSock.monitor)
            self.poller.unregister(self.pullSock.monitor)

            self.pushSock = None
            self.pullSock = None
            self.mgrConnection = None
            # self.clientID = None #will not set it to none since

            self.connectionSetup()

        self.poller.unregister(self.mgrConnection.socket)
        self.poller.unregister(self.mgrConnection.monitor)
        self.mgrConnection.socket.disable_monitor()
        self.mgrConnection.monitor.close()
        self.mgrConnection.close()

        # create the connection again
        self.connectionSetup()
        self.register(self.clientID)
        # The zmq lower part will handle the reconnect

        self.disconnected = True

    def sendCfgMsg(self, cfgMsgType, cfgMsgContent):
        """The configutaion response routine, the driver implementor
        should fill sth into this function.

        :param cfg: The original configutaion message
        :return:

        """
        self.logger.debug("Send a config message to HAL: %r", cfgMsgContent)

        if self.disconnected:
            self.logger.warn(
                "The client is on disconnected state, skip to send the message."
            )
            return

        if cfgMsgContent is None or not isinstance(cfgMsgContent, str):
            self.logger.error(
                "Cannot send a None or incorrect type to HAL, str is required for msg"
            )
            return

        msg = HalMessage("HalConfig",
                         SrcClientID=self.clientID,
                         SeqNum=self.seqNum,
                         CfgMsgType=cfgMsgType,
                         CfgMsgPayload=cfgMsgContent)
        self._sendMsg(msg.Serialize())

        seq = self.seqNum
        self.seqNum += 1
        return seq

    def sendCfgRspMsg(self, cfg, rsp=None):
        """The configuration response routine, the driver implementor should
        fill sth into this function.

        :param cfg: The original configuration message
        :param rsp: respond
        :return:

        """
        cfgMsg = cfg.msg
        msg = HalMessage("HalConfigRsp",
                         SrcClientID=cfgMsg.SrcClientID,
                         SeqNum=cfgMsg.SeqNum,
                         Rsp=rsp,
                         CfgMsgType=cfgMsg.CfgMsgType,
                         CfgMsgPayload=cfgMsg.CfgMsgPayload)
        if None is not self.pushSock:
            self.pushSock.send(msg.Serialize())

    def setHalDebugLevel(self, module, level):
        """Set the HAl debug level.

        :param module: the Hal module name
        :param level: the logging level
        :return:

        """
        self.logger.info("Set hal module[%s] to level [%s]" %
                         (module, logging.getLevelName(level)))

        if self.disconnected:
            self.logger.warn("Cannot send the HAL debug configuration to HAL"
                             " since the client is in disconnected  state.")
            return
        msg = HalMessage("HalSetLoggingLevel",
                         ClientID=self.clientID,
                         Module=module,
                         LoggingLevel=level)

        self.mgrConnection.send(msg.Serialize())

    def recvHalSetLoggingLevelRspCb(self, rsp):
        self.logger.debug(str(rsp.msg))

    def recvRegisterMsgCb(self, cfg):
        """The callback handler for the configuration message.

        :param cfg: the configuration message received frm the Hal
        :return:

        """
        # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg))

        if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
            self.logger.error("Cannot register to Hal, reason[%s]" %
                              cfg.msg.Rsp.ErrorDescription)
            return

        self.clientID = cfg.msg.ClientID

        # Setup the push and pull connection
        self.pullPath = cfg.msg.PathFromHalToClient
        self.pushPath = cfg.msg.PathFromClientToHal
        # get the index of the path
        index = self._getIndexFromPath()
        if index == -1:
            self.logger.error("Cannot get index from the path [%s]" %
                              self.pushPath)
            return
        if self.index == -1:
            self.index = index
            self.pushSock = HalTransport(
                HalTransport.HalTransportClientAgentPull,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPushMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            self.pullSock = HalTransport(
                HalTransport.HalTransportClientAgentPush,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPullMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            # register to the poller
            self.poller.register(self.pullSock.socket)
            self.poller.register(self.pushSock.monitor)
            self.poller.register(self.pullSock.monitor)
        # send Hello To Hal
        self.sayHelloToHal()
        self.sendInterestedNotifications(self.interestedNotification)

        self.disconnected = False

        return

    def _getIndexFromPath(self):
        rePattern = r"/(\d+)/"
        ret = re.search(rePattern, self.pushPath)

        if ret is not None:
            digitStr = ret.group(1)
            return int(digitStr)

        return -1
Ejemplo n.º 12
0
class HalAgentClient(HalAgent):
    """This class is the client agent class.

    the class will have the following API:

    * disconnectHandler:  the
      handler will be invoked when the transport layer get a disconnect
      event, the function will clean the agent
      resources, including the socket resource, remove it from the global
      runtime DB.
    * sendMsg: This API will send message via
      Agent's pushsock channel.
    * handleClientHello: The API will handle
      the Hello message
    * handleConfigRsp: This API will handle the
      configuration response HalMessage from client
    * handleNotification: This API will handle the notification HalMessage

    """
    ClientIndex = 0
    # self handle table
    HalGlobal.gHandleTable["HalClientHello"] = "handleClientHello"
    HalGlobal.gHandleTable["HalConfig"] = "handleConfig"
    HalGlobal.gHandleTable["HalConfigRsp"] = "handleConfigRsp"
    HalGlobal.gHandleTable["HalNotification"] = "handleNotification"

    __metaclass__ = AddLoggerToClass

    def __init__(self, poller, clientID, disconnectHandler, reuseIndex=None):
        """The function will generate the client agent object. the main
        function is to create the socket channel. for Hal the sock channel
        works at the server mode, it will listen at these sockets.

        :param poller: a global poller, the transport socket and the monitor socket will register into it.
        :param ClientID: a client  UUID
        :param disconnectHandler: the manager disconnect handler, will be called with agent gets a disconnect event.
        :param reuseIndex: for the client restart, it will provide it's previous ID, the agent will reuse
                            these ID and use the same transport path.
        :return: agent obj

        """
        super(HalAgentClient, self).__init__()

        if reuseIndex is None:
            # Generate the client index
            while True:
                index = HalAgentClient.ClientIndex
                HalAgentClient.ClientIndex += 1
                if str(index) not in HalGlobal.gClientIndex.values():
                    break
        else:
            index = reuseIndex

        self.index = index

        if clientID not in HalGlobal.gClientIndex:
            HalGlobal.gHalClientDbConnection.addMsgtoDB(
                "ClientIndex", {clientID: index}, expired=False)

        # Start the transport
        self.transportPush = HalTransport(
            HalTransport.HalTransportClientAgentPush, HalTransport.HalServerMode,
            index=index, socketMode=HalTransport.HalSocketPushMode,
            disconnectHandlerCb=self.disconnectHandler)

        # for the push, we don't need to register to the poller

        if self.transportPush.monitor:
            poller.register(self.transportPush.monitor)
            HalGlobal.gMonitorSocketMappingTable[
                self.transportPush.monitor] = self.transportPush

        # start the pull transport
        self.transportPull = HalTransport(
            HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode,
            index=index, socketMode=HalTransport.HalSocketPullMode,
            disconnectHandlerCb=self.disconnectHandler)
        poller.register(self.transportPull.socket)
        # add the pull socket to the socket agent mapping table
        HalGlobal.gSocketAgentMappingTable[self.transportPull.socket] = self

        # process the monitor
        if self.transportPull.monitor:
            poller.register(self.transportPull.monitor)
            HalGlobal.gMonitorSocketMappingTable[
                self.transportPull.monitor] = self.transportPull

        # For other variables
        self.mgrDisconnectCb = disconnectHandler
        self.disconnectProcessed = False
        self.poller = poller
        self.clientID = clientID

        # put the message into the resend list
        self.logger.debug("Check the last unsuccessful message.%s for client[%s]" % (
            HalGlobal.gRestartResendMsg, self.clientID))
        if self.clientID:
            for key in HalGlobal.gRestartResendMsg:
                if key.startswith(self.clientID):
                    self.logger.debug("Add message[%s] to resend list" % key)
                    cfg = HalGlobal.gRestartResendMsg[key]
                    seqNum = cfg.msg.SeqNum if cfg.msg.HasField(
                        "SeqNum") else 0
                    self.addToResendList(seq=seqNum, sendagent=self, msg=cfg)

    def disconnectHandler(self, transport):
        """the function will be invoked when the transport layer get a
        disconnect event, the fucntion will clean the agent resources,
        including the socket resource, remove it from the global runtime DB.

        :param transport: the transport object, pull/push
        :return:

        """
        self.logger.info(
            "Got a client[%s] disconnect event, process it in client agent" % self.clientID)

        # we have two transport layer can trigger this handler, we only need one time to process,
        # this flag is used for this
        if self.disconnectProcessed:
            self.logger.info(
                "client disconnect event has been processed")
            return

        # unregister/close the monitor socket
        if self.transportPull.monitor:
            HalGlobal.gMonitorSocketMappingTable.pop(
                self.transportPull.monitor)
            self.poller.unregister(self.transportPull.monitor)
            self.transportPull.socket.disable_monitor()
            self.transportPull.monitor.close()
        if self.transportPush.monitor:
            HalGlobal.gMonitorSocketMappingTable.pop(
                self.transportPush.monitor)
            self.poller.unregister(self.transportPush.monitor)
            self.transportPush.socket.disable_monitor()
            self.transportPush.monitor.close()

        # call the mgr callback to process the disconnect event
        self.mgrDisconnectCb(self)

        # remove the transportPull from the poller
        self.poller.unregister(self.transportPull.socket)

        # remove from the socket agent mapping table
        HalGlobal.gSocketAgentMappingTable.pop(self.transportPull.socket)

        # Remove from the global Agent DB
        self.removeFromAgentDB()

        # close the push and pull, monitor socket
        self.transportPull.close()
        self.transportPush.close()

        self.disconnectProcessed = True

    def sendMsg(self, msg):
        """Send a message via the transport push socket.

        :param msg: a stringlized msg, not the HAlMessage
        :return:

        """
        if msg is None:
            self.logger.error(
                "The msg is None, skip invoking the low level function")
            return

        self.transportPush.send(msg)

    def handleClientHello(self, hello):
        """The Hello message handler.

        :param hello: which is a HalMessage, hold all the info about the hello message
        :return:  NA

        """
        self.logger.debug("Send out the hello rsp message")

        # update the stats
        self.stats.NrMsgs += 1
        self.stats.NrHelloMsgs += 1
        if hello is None:
            msg = "Cannot handle a none client hello message"
            self.logger.error(msg)
            self.stats.NrErrorMsgs += 1
            raise Exception(msg)

        rsp = HalMessage("HalClientHelloRsp",
                         ClientID=hello.msg.ClientID)
        # send out
        self.transportPush.send(rsp.Serialize())
        self.stats.NrHelloRspMsgs += 1

    def handleConfigRsp(self, cfgRsp):
        """This API will handle the configuration response HalMessage from
        client.

        :param cfgRsp:
        :return:

        """
        if cfgRsp is None:
            msg = "Cannot handle a none config response message"
            self.logger.error(msg)
            raise Exception(msg)

        HalGlobal.gHalMsgDbConnection.removeMsgFromDB(
            cfgRsp.msg.SrcClientID + "-" + str(cfgRsp.msg.SeqNum))
        HalGlobal.gDispatcher.dispatchCfgRspMessage(self, cfgRsp)

        self.stats.NrCfgRspMsgs += 1

    def handleNotification(self, notification):
        """This API will handle the notification HalMessage.

        :param notification: the notification HalMessage
        :return:

        """
        if notification is None:
            msg = "Cannot handle the notification since the msg is None"
            self.logger.error(msg)
            raise Exception(msg)
        # update the stats
        self.stats.NrNotifyMsgs += 1
        self.stats.NrMsgs += 1
        HalGlobal.gDispatcher.dispatchNotificationMsg(self, notification)

    def handleConfig(self, cfg):
        """The configuration HalMessage handler.

        :param cfg:  The Config message from the client
        :return:

        """
        if cfg is None:
            msg = "Cannot handle a none config message"
            self.logger.error(msg)
            raise Exception(msg)

        # Add the message to the DB
        seqNum = cfg.msg.SeqNum if cfg.msg.HasField("SeqNum") else 0
        msgBinary = cfg.originalBinary \
            if cfg.originalBinary else cfg.Serialize()
        # add the msg to DB
        HalGlobal.gHalMsgDbConnection.addMsgtoDB(
            msgKey=cfg.msg.SrcClientID + "-" + str(seqNum),
            msg={
                "ClientID": cfg.msg.SrcClientID,
                "Msg": msgBinary
            }
        )

        # Update the stats
        self.stats.NrMsgs += 1
        self.stats.NrCfgMsgs += 1

        # first, process the resendList
        self.processResendList()

        # Dispatch this message to the correct client
        ret = HalGlobal.gDispatcher.dispatchCfgMessage(self, cfg)
        if ret == -1:
            self.addToResendList(seq=seqNum, sendagent=self, msg=cfg)
Ejemplo n.º 13
0
class HalPtpDriver(HalDriverClient):
    """The Driver Client for Hal."""

    SYNC = "ALIGNED"
    LOS = "LOSS OF SYNC"
    __metaclass__ = AddLoggerToClass

    def __init__(self,
                 drvName,
                 drvDesc,
                 drvVer,
                 supportedMsgType,
                 supportedNotificationMsgs,
                 logConfigurePath=None):
        """Init.

        :param drvName: The driver name, such as BCM3160 Driver
        :param drvDesc: A brief description about this driver, such as the 
         driver main functionality description
        :param drvVer: Driver specific version, such as 1.0.1
        :param supportedMsgType: a tuple or list for the driver supported 
         msg types, the form will be (1, 2, 456, 10)
        :param supportedNotificationMsgs: the driver supported notification 
         msg types the form will be (1, 3, 4)
        :return: HalDriverClient object

        """
        super(HalPtpDriver,
              self).__init__(drvName, drvDesc, drvVer, supportedMsgType,
                             supportedNotificationMsgs, logConfigurePath)

        # update the supported messages
        self.HalMsgsHandler = {
            "HalClientRegisterRsp": self.recvRegisterMsgCb,
            "HalClientHelloRsp": self.recvHelloRspMsgCb,
            "HalConfig": self.recvCfgMsgCb,
        }

        self.HalConfigMsgHandlers = {
            MsgTypePtpStatusGet: self.ptp_status_get,
            MsgTypeRdtiConfig: self.config_rdti,
        }

        self.ptpStatus = self.LOS
        self.ptpNewStatus = self.LOS
        self.dispatcher = Dispatcher()

    def start(self, simulate_mode=False):
        """Start polling the transport socket.

        :return:

        """
        self.logger.info("Start the driver client poll...")
        self.connectionSetup()
        self.logger.info("Connection setup done...")

        self.logger.info("Begin register...")
        self.register(self.drvID)
        self.logger.info("End of register...")

        self.dispatcher.loop()

    def ptpdrv_hal_cb(self, sock, mask):
        self.logger.debug("Receive prp drv event")
        if self.pushSock is not None and sock == self.pushSock.monitor:
            self.pushSock.monitorHandler(recv_monitor_message(sock))
            return
        if self.pullSock is not None and sock == self.pullSock.monitor:
            self.pullSock.monitorHandler(recv_monitor_message(sock))
            return

        if sock == self.mgrConnection.monitor:
            self.mgrConnection.monitorHandler(recv_monitor_message(sock))
            return

        while sock.getsockopt(zmq.EVENTS) and zmq.POLLIN:
            try:
                bin = sock.recv(flags=zmq.NOBLOCK)
                msg = HalMessage.DeSerialize(bin)
                self.logger.debug("Got a zmq msg:%s type:%s" %
                                  (msg.msg, msg.type))
                if msg.type in self.HalMsgsHandler:
                    handler = self.HalMsgsHandler[msg.type]
                    handler(msg)
            except zmq.ZMQError as e:
                self.logger.debug(
                    "Got an error when trying with nonblock read:" + str(e))
                break
            except Exception as e:
                self.logger.warning("Got an un-expected error:%s", str(e))
                break

    def register(self, DriverID):
        """Send a register message to Hal and get the client ID from the Hal.

        :return:

        """
        if DriverID is None:
            registerMsg = HalMessage(
                "HalClientRegister",
                ClientName=self.drvname,
                ClientDescription=self.drvDesc,
                ClientVersion=self.drvVer,
                ClientSupportedMessages=self.supportedMsgType,
                ClientSupportedNotificationMessages=self.
                supportedNotificationMsgs)
        else:
            registerMsg = HalMessage(
                "HalClientRegister",
                ClientName=self.drvname,
                ClientDescription=self.drvDesc,
                ClientVersion=self.drvVer,
                ClientSupportedMessages=self.supportedMsgType,
                ClientSupportedNotificationMessages=self.
                supportedNotificationMsgs,
                ClientID=DriverID)

        if self.mgrConnection is None:
            errMsg = "Cannot send the register since the mgr connection is not setup"
            self.logger.error(errMsg)
            raise HalDriverClientError(errMsg)
        self.logger.debug("Send the register msg to Hal...")
        self.mgrConnection.send(registerMsg.Serialize())

    def recvRegisterMsgCb(self, cfg):
        """The callback handler for the configuration message.

        :param cfg: the configuration message received frm the Hal
        :return:

        """
        self.logger.debug("Recv a register rsp Message from the Hal: %s" %
                          cfg.msg)

        if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS:
            self.logger.error("Cannot register to Hal, reason[%s]",
                              cfg.msg.Rsp.ErrorDescription)
            return

        self.drvID = cfg.msg.ClientID

        # Setup the push and pull connection
        self.pullPath = cfg.msg.PathFromHalToClient
        self.pushPath = cfg.msg.PathFromClientToHal

        # get the index of the path
        index = self._getIndexFromPath()
        if index == -1:
            self.logger.error("Cannot get index from the path [%s]" %
                              self.pushPath)
            return
        if self.index == -1:
            self.index = index
            self.pushSock = HalTransport(
                HalTransport.HalTransportClientAgentPull,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPushMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            self.pullSock = HalTransport(
                HalTransport.HalTransportClientAgentPush,
                HalTransport.HalClientMode,
                index=index,
                socketMode=HalTransport.HalSocketPullMode,
                disconnectHandlerCb=self.connectionDisconnectCb)

            # register to the poller
            self.dispatcher.fd_register(self.pullSock.socket, zmq.POLLIN,
                                        self.ptpdrv_hal_cb)
            self.dispatcher.fd_register(self.pushSock.monitor, zmq.POLLIN,
                                        self.ptpdrv_hal_cb)
            self.dispatcher.fd_register(self.pullSock.monitor, zmq.POLLIN,
                                        self.ptpdrv_hal_cb)
        # send Hello To Hal
        self.sayHelloToHal()
        if self.interestedNotification is not None:
            self.sendInterestedNotifications(self.interestedNotification)

        self.disconnected = False

        return

    def connectionSetup(self):
        """Create the connection to the mgr and setup the poller.

        :return:

        """
        self.logger.info("Create the connection to the mgr....")
        # Create a connection to Hal driver mgr

        # Create a connection to Hal driver mgr
        self.mgrConnection = HalTransport(
            HalTransport.HalTransportClientMgr,
            HalTransport.HalClientMode,
            disconnectHandlerCb=self.connectionDisconnectCb)
        self.mgrConnection.connects()

        self.HalMsgsHandler[self.mgrConnection.socket] = self.recvRegisterMsgCb

        self.HalMsgsHandler[self.mgrConnection.socket] = self.recvRegisterMsgCb

        # register the mgr socket
        self.dispatcher.fd_register(self.mgrConnection.socket, zmq.POLLIN,
                                    self.ptpdrv_hal_cb)
        self.dispatcher.fd_register(self.mgrConnection.monitor, zmq.POLLIN,
                                    self.ptpdrv_hal_cb)

    def connection_cleanup(self):
        """Close the connection to the mgr.

        :return:

        """
        if self.disconnected:
            self.logger.debug("A previous event has been processed, skip it!")
            return

        if self.mgrConnection is not None:
            self.dispatcher.fd_unregister(self.mgrConnection.socket)
            self.dispatcher.fd_unregister(self.mgrConnection.monitor)
            self.mgrConnection.socket.disable_monitor()
            self.mgrConnection.monitor.close()
            self.mgrConnection.socket.close()

        if self.pullSock is not None:
            self.dispatcher.fd_unregister(self.pullSock.socket)
            self.dispatcher.fd_unregister(self.pullSock.monitor)
            self.pullSock.socket.disable_monitor()
            self.pullSock.monitor.close()
            self.pullSock.socket.close()

        if self.pushSock is not None:
            self.dispatcher.fd_unregister(self.pushSock.monitor)
            self.pushSock.socket.disable_monitor()
            self.pushSock.monitor.close()
            self.pushSock.socket.close()

        self.disconnected = True

    def connectionDisconnectCb(self, msg):
        """TODO: confusing comment here. Need clarification.

        The connection has been detected disconnected , register it again
        We have reconenct, we have to assure the regiter message is received
        by the HAL

        :param msg:
        :return:

        """
        if self.disconnected:
            self.logger.info("A previous event has been processed, skip it!")
            return
        self.logger.info("Detected disconnected, register again")
        # clean up the push and pull socket
        # self.poller.unregister(self.pullSock.socket)

        self.dispatcher.fd_unregister(self.mgrConnection.socket)
        self.dispatcher.fd_unregister(self.mgrConnection.monitor)
        self.mgrConnection.monitor.close()
        self.mgrConnection.close()

        # re-register the message
        self.connectionSetup()
        self.register(self.drvID)
        # The zmq lower part will handle the reconnect

        self.disconnected = True

    def recvHelloRspMsgCb(self, hello):
        """Call back for Hello Message.

        :param hello:
        :return:

        """
        self.logger.debug("Recv a hello message")

    def recvCfgMsgCb(self, cfg):
        """Receive a configuration message from the Hal, processing it.

        :param cfg:
        :return:

        """
        try:
            handler = self.HalConfigMsgHandlers[cfg.msg.CfgMsgType]
            handler(cfg)
        except Exception as e:
            self.logger.error("Got an error:%s, the cfg msg:%s", str(e),
                              cfg.msg)

    def ptp_status_get(self, cfg):
        cfg.msg.CfgMsgPayload = self.SYNC
        self.sendCfgRspMsg(cfg)

    def config_rdti(self, cfg):
        rdti_config_data = t_RcpMessage()
        rdti_config_data.ParseFromString(cfg.msg.CfgMsgPayload)
        rdti_config_data.RcpDataResult = t_RcpMessage.RCP_RESULT_OK
        cfg.msg.CfgMsgPayload = rdti_config_data.SerializeToString()
        self.logger.debug("Recv ptp configuration message, %s" %
                          rdti_config_data)
        self.sendCfgRspMsg(cfg)

    def sendCfgRspMsg(self, cfg, rsp=None):
        """The configuration response routine, the driver implementor should
        fill sth into this function.

        :param cfg: The original configuration message
        :return:

        """
        cfgMsg = cfg.msg
        rsp = {"Status": HalCommon_pb2.SUCCESS, "ErrorDescription": ""}
        msg = HalMessage("HalConfigRsp",
                         SrcClientID=cfgMsg.SrcClientID,
                         SeqNum=cfgMsg.SeqNum,
                         Rsp=rsp,
                         CfgMsgType=cfgMsg.CfgMsgType,
                         CfgMsgPayload=cfgMsg.CfgMsgPayload)
        self.pushSock.send(msg.Serialize())