Ejemplo n.º 1
0
    def test_fd_sock(self):
        d = Dispatcher()
        self.disp = d  # for _test_fd_sock_helper()

        import socket
        s = socket.socket()
        s.setblocking(0)
        s.bind(('', 65000))
        s.listen(10)

        d.fd_register(s.fileno(), d.EV_FD_IN, self._test_fd_sock_helper)
        d.fd_modify(s.fileno(), 0)
        d.fd_unregister(s.fileno())

        c = socket.socket()
        c.setblocking(0)
        ret = c.connect_ex(('localhost', 65000))
        self.assertEqual(ret, 115, 'async connect failed')

        d.fd_register(s.fileno(), d.EV_FD_IN, self._test_fd_sock_helper)
        d.loop()
        self.assertEqual(self.got_fd, s.fileno())
        self.assertEqual(self.got_eventmask, Dispatcher.EV_FD_IN)

        del d
        del s
        del c
Ejemplo n.º 2
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.º 3
0
class ProcessAgent(object):
    __metaclass__ = AddLoggerToClass

    PROCESSSTATE_ALIVE = 0
    PROCESSSTATE_DEAD = -1

    AGENTTYPE_INTERFACE_STATUS = provision_pb2.AGENTTYPE_INTERFACE_STATUS
    AGENTTYPE_8021X = provision_pb2.AGENTTYPE_8021X
    AGENTTYPE_DHCP = provision_pb2.AGENTTYPE_DHCP
    AGENTTYPE_TOD = provision_pb2.AGENTTYPE_TOD
    AGENTTYPE_IPSEC = provision_pb2.AGENTTYPE_IPSEC
    AGENTTYPE_GCP = provision_pb2.AGENTTYPE_GCP
    AGENTTYPE_PTP = provision_pb2.AGENTTYPE_PTP
    AGENTTYPE_L2TP = provision_pb2.AGENTTYPE_L2TP
    AgentName = {
        AGENTTYPE_INTERFACE_STATUS: "AGENTTYPE_INTERFACE_STATUS",
        AGENTTYPE_8021X: "AGENTTYPE_8021X",
        AGENTTYPE_DHCP: "AGENTTYPE_DHCP",
        AGENTTYPE_TOD: "AGENTTYPE_TOD",
        AGENTTYPE_IPSEC: "AGENTTYPE_IPSEC",
        AGENTTYPE_GCP: "AGENTTYPE_GCP",
        AGENTTYPE_PTP: "AGENTTYPE_PTP",
        AGENTTYPE_L2TP: "AGENTTYPE_L2TP",
    }

    SockPathMapping = {
        AGENTTYPE_INTERFACE_STATUS: {
            "api": "ipc:///tmp/rpd_provision_agent_interface_status_api.sock",
            "push":
            "ipc:///tmp/rpd_provision_agent_interface_status_push.sock",
            "pull":
            "ipc:///tmp/rpd_provision_agent_interface_status_pull.sock",
            "cli": "ipc:///tmp/zmq-interface.ipc"
        },
        AGENTTYPE_8021X: {
            "api": "ipc:///tmp/rpd_provision_agent_8021x_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_8021x_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_8021x_pull.sock",
            "cli": "ipc:///tmp/zmq-8021x.ipc"
        },
        AGENTTYPE_DHCP: {
            "api": "ipc:///tmp/rpd_provision_agent_dhcp_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_dhcp_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_dhcp_pull.sock",
            "cli": "ipc:///tmp/zmq-dhcp.ipc"
        },
        AGENTTYPE_TOD: {
            "api": "ipc:///tmp/rpd_provision_agent_tod_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_tod_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_tod_pull.sock",
            "cli": "ipc:///tmp/zmq-tod.ipc"
        },
        AGENTTYPE_IPSEC: {
            "api": "ipc:///tmp/rpd_provision_agent_ipsec_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_ipsec_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_ipsec_pull.sock",
            "cli": "ipc:///tmp/zmq-ikev2.ipc"
        },
        AGENTTYPE_GCP: {
            "api": "ipc:///tmp/rpd_provision_agent_gcp_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_gcp_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_gcp_pull.sock",
            "cli": "ipc:///tmp/zmq-gcp.ipc"
        },
        AGENTTYPE_PTP: {
            "api": "ipc:///tmp/rpd_provision_agent_ptp_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_ptp_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_ptp_pull.sock",
            "cli": "ipc:///tmp/zmq-ptp.ipc"
        },
        AGENTTYPE_L2TP: {
            "api": "ipc:///tmp/rpd_provision_agent_l2tp_api.sock",
            "push": "ipc:///tmp/rpd_provision_agent_l2tp_push.sock",
            "pull": "ipc:///tmp/rpd_provision_agent_l2tp_pull.sock",
            "cli": "ipc:///tmp/zmq-l2tp.ipc"
        },
    }

    def __init__(self, agent_type):
        if agent_type not in self.AgentName:
            self.logger.error("Cannot setup the process agent for type:%d" %
                              agent_type)
            raise ProcessAgentError("Unknown Type:%d" % agent_type)

        if self._process_is_running(agent_type):
            self.logger.error(
                "Cannot setup the process agent for %s since a same agent has been up",
                agent_type)
            raise ProcessAgentError("Cannot setup a duplicated %s" %
                                    self.AgentName[agent_type])

        event_path = self.SockPathMapping[agent_type]["pull"]
        api_path = self.SockPathMapping[agent_type]["api"]
        cli_path = self.SockPathMapping[agent_type]["cli"]

        # Create the pull and api sock to handle the request
        self.event_transport = Transport(event_path, Transport.PULLSOCK)
        self.api_transport = Transport(api_path, Transport.REPSOCK)
        self.cli_transport = Transport(cli_path, Transport.REPSOCK)

        # create a dispatcher
        self.dispatcher = Dispatcher()

        # register the event
        self.register_transport(self.event_transport,
                                self._process_event_callback, None)
        self.register_transport(self.api_transport, self.api_event_callback,
                                None)
        self.register_transport(self.cli_transport, self._process_cli_callback,
                                None)

        # the region to hold all the process obj
        self.processes = {}

        # the region to hold all the ccap cores
        self.ccap_cores = {}
        self.mgrs = {}

        # agent information maintain
        self.name = self.AgentName[agent_type]
        self.id = agent_type  # we will generate  uuid

    def __str__(self):
        """Encoding this process agent to a string."""
        return ProcessAgentEncoder().encode(self)

    @staticmethod
    def is_all_agent_started():
        """Check if all agents are started."""
        for agent_type in ProcessAgent.AgentName:
            checked = False
            # will retry 10 times in 1 second
            for i in range(10):
                file_name = "/tmp/ProcessAgent_" + ProcessAgent.AgentName[
                    agent_type]
                try:
                    process_file = open(file_name, "r")
                    # get the pid
                    pidbuff = process_file.read()
                    process_file.close()

                    if pidbuff:
                        pid = int(pidbuff)
                        # check if the pid is alive
                        if psutil.pid_exists(pid):
                            checked = True
                            break
                except IOError:
                    pass
                time.sleep(0.1)
            if not checked:
                return checked

        return True

    @staticmethod
    def _process_is_running(agent_type):
        # Check if we have setup a agent for this type
        file_name = "/tmp/ProcessAgent_" + ProcessAgent.AgentName[agent_type]

        try:
            process_file = open(file_name, "r")

            # get the pid
            pid = int(process_file.read())

            # check if the pid is alive
            if psutil.pid_exists(pid):
                return True
            else:
                process_file.close()
        except IOError:
            pass
        finally:
            process_file = open(file_name, "w")
            process_file.write(str(os.getpid()))

        return False

    def api_event_callback(self, fd, eventmask):
        """Call back functions, the subclass should implement this function.

        :param fd: passed from the register. the arg should contains the
         transport information.
        :param eventmask: passed from the dispatcher, which indicates the
         event type.
        :return: None

        """
        # Receive the msg from the remote
        if eventmask == 0 or self.api_transport.sock != fd:
            self.logger.warn("Got a fake process event[%x], ignore it." %
                             eventmask)
            return

        if eventmask & self.dispatcher.EV_FD_ERR:
            self.logger.error("Got an error event, handle the failure.")
            # FixMe: may need more action to handle the failure
            return

        if self.api_transport.sock.getsockopt(zmq.EVENTS) != zmq.POLLIN:
            self.logger.debug("Got a fake event, the receive is not ready!")
            return

        try:
            data = self.api_transport.sock.recv(flags=zmq.NOBLOCK)

            msg = process_agent_pb2.api_request()
            msg.ParseFromString(data)

            self.logger.debug("Receive an api message from the FSM:%s" %
                              str(msg))

            # check the fields, we only processing the register fields
            fields = msg.ListFields()

            for field in fields:
                desc, value = field

                if desc.name == "mgr_reg":
                    self._handle_mgr_register(value)

                elif desc.name == "core_reg":
                    self._handle_core_register(value)

                else:
                    self.logger.error(
                        "Cannot handle the request since no handler for this, msg:%s.",
                        msg)
        except zmq.Again:
            pass
        except Exception as e:
            self.logger.error("Cannot process the event, reason:%s" % str(e))
            rsp = process_agent_pb2.msg_register_rsp()
            rsp.id = ""
            rsp.agent_id = self.id
            rsp.status = process_agent_pb2.msg_register_rsp.FAIL
            rsp.reason = "Exception happens"
            api_rsp = process_agent_pb2.api_rsp()
            api_rsp.reg_rsp.CopyFrom(rsp)
            data = api_rsp.SerializeToString()
            self.send_reg_rsp(data)

    def _handle_core_register(self, reg):
        self.logger.info("%s Processing the core register request:%s" %
                         (self.AgentName[self.id], reg))
        id = reg.ccap_core_id
        action = reg.action
        mgr_id = reg.mgr_id

        if action == process_agent_pb2.msg_core_register.REG:

            # check is the client has been registered
            if id in self.ccap_cores:
                self.logger.info(
                    "The ccap core[%s] has been registered, ignore this request."
                    % id)

                rsp = process_agent_pb2.msg_register_rsp()
                rsp.id = id
                rsp.agent_id = self.id
                rsp.status = process_agent_pb2.msg_register_rsp.OK
                rsp.reason = "Core [%s] has been registered, ignore this register request." % id
                api_rsp = process_agent_pb2.api_rsp()
                api_rsp.reg_rsp.CopyFrom(rsp)
                self.send_reg_rsp(api_rsp)
                return

            if mgr_id not in self.mgrs:
                self.logger.info("Cannot find the mgr[%s],  core id is [%s]" %
                                 (mgr_id, id))
                rsp = process_agent_pb2.msg_register_rsp()
                rsp.id = id
                rsp.agent_id = self.id
                rsp.status = process_agent_pb2.msg_register_rsp.FAIL
                rsp.reason = "Cannot find the mgr:%s." % mgr_id
                api_rsp = process_agent_pb2.api_rsp()
                api_rsp.reg_rsp.CopyFrom(rsp)
                self.send_reg_rsp(api_rsp)
                return

            # Add the fsm to our internal database
            self.ccap_cores[id] = {
                "mgr": mgr_id,
            }

            # send the feed back
            self.logger.info("CCap core [%s] registered successfully" % id)
            rsp = process_agent_pb2.msg_register_rsp()
            rsp.id = id
            rsp.agent_id = self.id
            rsp.status = process_agent_pb2.msg_register_rsp.OK
            rsp.reason = "Register successfully"
            api_rsp = process_agent_pb2.api_rsp()
            api_rsp.reg_rsp.CopyFrom(rsp)
            self.send_reg_rsp(api_rsp)
            return

        elif action == process_agent_pb2.msg_manager_register.UNREG:
            # check if the requester has been registered
            if id not in self.ccap_cores:
                self.logger.error(
                    "Cannot process unregister request since we cannot find the id[%s] in local db",
                    id)
                rsp = process_agent_pb2.msg_register_rsp()
                rsp.id = id
                rsp.agent_id = self.id
                rsp.status = process_agent_pb2.msg_register_rsp.FAIL
                rsp.reason = "Cannot process the unregister request since cannot find the id[%s] in local db" % id
                api_rsp = process_agent_pb2.api_rsp()
                api_rsp.reg_rsp.CopyFrom(rsp)
                self.send_reg_rsp(api_rsp)
                return

            # process the requester
            self.ccap_cores.pop(id)

            # send the feed back
            self.logger.info("CCAP core [%s] unregistered successfully" % id)
            rsp = process_agent_pb2.msg_register_rsp()
            rsp.id = id
            rsp.agent_id = self.id
            rsp.status = process_agent_pb2.msg_register_rsp.OK
            rsp.reason = "Unregistered successfully"
            api_rsp = process_agent_pb2.api_rsp()
            api_rsp.reg_rsp.CopyFrom(rsp)
            self.send_reg_rsp(api_rsp)
            return

        else:
            pass

    def _handle_mgr_register(self, reg):
        self.logger.info("%s Processing the mgr register request:%s" %
                         (self.AgentName[self.id], reg))
        id = reg.id
        action = reg.action

        if action == process_agent_pb2.msg_manager_register.REG:
            path = module_name = parameter = None
            if reg.HasField("path_info"):
                path = reg.path_info
            if reg.HasField("module_name"):
                module_name = reg.module_name
            if reg.HasField("parameter"):
                parameter = reg.parameter

            # check is the client has been registered
            if id in self.mgrs:
                self.logger.info(
                    "The mgr[%s] has been registered, ignore this request." %
                    id)
                rsp = process_agent_pb2.msg_register_rsp()
                rsp.id = id
                rsp.agent_id = self.id
                rsp.status = process_agent_pb2.msg_register_rsp.OK
                rsp.reason = "Mgr has been registered, ignore this register request."
                api_rsp = process_agent_pb2.api_rsp()
                api_rsp.reg_rsp.CopyFrom(rsp)
                self.send_reg_rsp(api_rsp)
                return

            if path is None:
                self.logger.error(
                    "Cannot process the register request since the pull sock is none."
                )
                rsp = process_agent_pb2.msg_register_rsp()
                rsp.id = id
                rsp.agent_id = self.id
                rsp.status = process_agent_pb2.msg_register_rsp.FAIL
                rsp.reason = "Path is not included in request message"
                api_rsp = process_agent_pb2.api_rsp()
                api_rsp.reg_rsp.CopyFrom(rsp)
                self.send_reg_rsp(api_rsp)
                return

            # Create the pull, will not register to dispatcher, since we will
            # use the non-block send
            transport = Transport(path, Transport.PUSHSOCK,
                                  Transport.TRANSPORT_CLIENT)

            # Add the fsm to our internal database
            self.mgrs[id] = {
                "transport": transport,
                "name": module_name,
                "para": parameter,
                "path": path,
            }

            # send the feed back
            self.logger.info("Mgr[%s] registered successfully" % id)
            rsp = process_agent_pb2.msg_register_rsp()
            rsp.id = id
            rsp.agent_id = self.id
            rsp.status = process_agent_pb2.msg_register_rsp.OK
            rsp.reason = "Register successfully"
            api_rsp = process_agent_pb2.api_rsp()
            api_rsp.reg_rsp.CopyFrom(rsp)
            self.send_reg_rsp(api_rsp)
            return

        elif action == process_agent_pb2.msg_manager_register.UNREG:
            # check if the requester has been registered
            if id not in self.mgrs:
                self.logger.error(
                    "Cannot process the mgr unregister request since cannot find the id[%s] in local db"
                    % id)
                rsp = process_agent_pb2.msg_register_rsp()
                rsp.id = id
                rsp.agent_id = self.id
                rsp.status = process_agent_pb2.msg_register_rsp.FAIL
                rsp.reason = "Cannot process mgr unregister request since cannot find the id[%s] in local db" % id
                api_rsp = process_agent_pb2.api_rsp()
                api_rsp.reg_rsp.CopyFrom(rsp)
                self.send_reg_rsp(api_rsp)
                return

            # process the requester
            requester = self.mgrs[id]
            transport = requester["transport"]
            if transport and transport.sock:
                transport.sock.close()

            self.mgrs.pop(id)
            # send the feed back
            self.logger.info("Id[%s] unregistered successfully" % id)
            rsp = process_agent_pb2.msg_register_rsp()
            rsp.id = id
            rsp.agent_id = self.id
            rsp.status = process_agent_pb2.msg_register_rsp.OK
            rsp.reason = "Unregistered successfully"
            api_rsp = process_agent_pb2.api_rsp()
            api_rsp.reg_rsp.CopyFrom(rsp)
            self.send_reg_rsp(api_rsp)
            return

        else:
            pass

    def _send_event_notification(self, ccap_id, status, reason, result="DOWN"):
        """This is a private function, used to send the event notification.

        :param ccap_id: ccap core ID
        :param status: FAIL/OK
        :param reason: The fail reason
        :param result: The success result.
        :return: Node

        """
        msg_event_notification = process_agent_pb2.msg_event_notification()
        msg_event_notification.core_event.id = ccap_id
        msg_event_notification.core_event.ccap_core_id = ccap_id
        msg_event_notification.core_event.status = status
        msg_event_notification.core_event.reason = reason
        msg_event_notification.core_event.event_id = self.id
        msg_event_notification.core_event.result = result

        # Get the transport
        if ccap_id in self.ccap_cores:
            ccap_core = self.ccap_cores[ccap_id]
            transport = self.mgrs[ccap_core["mgr"]]['transport']
            transport.sock.send(msg_event_notification.SerializeToString(),
                                flags=zmq.NOBLOCK)
            self.logger.debug("Process an event action for id %s, return:%s" %
                              (ccap_id, msg_event_notification))
        else:
            self.logger.warn(
                "ccap id %s is not in core db of process agent %s " %
                (ccap_id, self.__class__))
        return

    def _send_ka_notification(self, mgr_id, status, reason):
        """This is a private function, used to send the event notification.
        TODO paramaters dont match

        :param ccap_id: ccap core ID
        :param status: FAIL/OK
        :param reason: The fail reason
        :param result: The success result.
        :return: Node

        """
        msg_event_notification = process_agent_pb2.msg_event_notification()
        msg_ka_rsp = process_agent_pb2.msg_ka_rsp()
        msg_ka_rsp.id = mgr_id
        msg_ka_rsp.status = status
        msg_ka_rsp.reason = reason
        msg_ka_rsp.agent_id = self.id
        msg_event_notification.ka_rsp.CopyFrom(msg_ka_rsp)

        # Get the transport
        if mgr_id in self.mgrs:
            transport = self.mgrs[mgr_id]['transport']
            transport.sock.send(msg_event_notification.SerializeToString(),
                                flags=zmq.NOBLOCK)
            self.logger.debug("Process an event action for id %s, return:%s" %
                              (mgr_id, msg_ka_rsp))
        else:
            self.logger.warn(
                "mgr id %s is not in mgr db of process agent %s " %
                (mgr_id, self.__class__))
        return

    def process_event_action(self, action):
        """The subclass should overwrite this function.

        :param action:
        :return:

        """
        raise NotImplementedError

    def process_ka_action(self, action):
        """Process the request from the client.

        :param action:
        :return:

        """
        mgr_id = action.id
        event_action = action.action

        if event_action == process_agent_pb2.msg_manager_ka.KA:
            self._send_ka_notification(mgr_id,
                                       process_agent_pb2.msg_ka_rsp.OK,
                                       reason="KA successfully")
        else:
            self._send_ka_notification(
                mgr_id,
                process_agent_pb2.msg_ka_rsp.FAIL,
                reason="{} not supported".format(event_action))

    def _process_event_callback(self, fd, eventmask):
        """Callback function for API socket.

        :param fd: passed from the dispatcher, the fd should contains the
         transport information
        :param eventmask: passed from the dispatcher, which indicates the
         event type.
        :return: None

        """
        # Receive the msg from the remote
        if eventmask == 0 or self.event_transport.sock != fd:
            self.logger.warn("Got a fake process event, ignore it")
            return

        if eventmask & self.dispatcher.EV_FD_ERR:
            self.logger.error("Got an error event.")
            # FixMe: may need more action
            return

        if self.event_transport.sock.getsockopt(zmq.EVENTS) != zmq.POLLIN:
            self.logger.debug("Got a fake event, the receive is not ready!")
            return

        try:
            data = self.event_transport.sock.recv(flags=zmq.NOBLOCK)

            msg = process_agent_pb2.msg_event_request()
            msg.ParseFromString(data)

            self.logger.debug("Receive an event message from the FSM:%s" %
                              str(msg))

            # check the fields, we only processing the register fields
            fields = msg.ListFields()

            for field in fields:
                desc, value = field

                if desc.name == "action":
                    self.process_event_action(value)
                elif desc.name == "ka_msg":
                    self.process_ka_action(value)
        except zmq.Again:
            pass
        except Exception as e:
            self.logger.error("%s:Cannot process the event, reason:%s",
                              self.name, str(e))

    def process_cli_action(self, msg):
        """The subclass should overwrite this function.

        :param msg: t_CliMessage
        :return:

        """
        raise NotImplementedError

    def _process_cli_callback(self, fd, eventmask):
        """Callback function for API socket.

        :param fd: passed from the dispatcher, the fd should contains the
         transport information
        :param eventmask: passed from the dispatcher, which indicates the
         event type.
        :return: None

        """
        # Receive the msg from the remote
        if eventmask == 0 or self.cli_transport.sock != fd:
            self.logger.warn("Got a fake cli message, ignore it")
            return
        # FixMe: may need more action
        if eventmask & self.dispatcher.EV_FD_ERR:
            self.logger.error("Got an error when receiving the msg.")
            return

        if self.cli_transport.sock.getsockopt(zmq.EVENTS) != zmq.POLLIN:
            self.logger.debug(
                "Got a fake cli message, the receive is not ready!")
            return

        try:
            data = self.cli_transport.sock.recv(flags=zmq.NOBLOCK)

            msg = t_CliMessage()
            msg.ParseFromString(data)

            self.logger.debug("Receive an CLI message: %s" % str(msg))
            self.process_cli_action(msg)
        except zmq.Again as e:
            pass
        except Exception as e:
            self.logger.error("Cannot process the CLI message, reason:%s" %
                              str(e))

    def send_reg_rsp(self, ipc_msg):
        """Send register response message via api sock.

        :param ipc_msg: message information

        """
        if not isinstance(
                ipc_msg,
                process_agent_pb2.api_rsp) or not ipc_msg.IsInitialized():
            self.logger.error('Invalid IPC message provided.')
            return False

        try:
            self.api_transport.sock.send(ipc_msg.SerializeToString(),
                                         flags=zmq.NOBLOCK)
        except Exception:  # as e:
            self.logger.error(
                "Got error when send register response message: {}".format(
                    ipc_msg))

    def send_cli_rsp(self, rsp_msg):
        """Send cli response message via cli sock.

        :param rsp_msg: message information

        """

        try:
            self.cli_transport.sock.send(rsp_msg.SerializeToString(),
                                         flags=zmq.NOBLOCK)
        except Exception:  # as e:
            self.logger.error(
                "Got error when send CLI response message: {}".format(rsp_msg))

    def start(self):
        """The start function will make the process into a endless loop.

        :return: Never return

        """
        self.dispatcher.loop()

    def register_poll_timer(self, timeout, callback, args=None):
        """Register a timer to dispatcher.

        :param timeout: the timeout value, the unit is second
        :param callback: Call back function, the format is
         {"function": func, "args": args}
        :return:

        """
        self.logger.info("Register a timer into dispatcher, timeout:%d" %
                         timeout)
        return self.dispatcher.timer_register(
            timeout,
            callback,
            arg=args,
            timer_type=DpTimerManager.TIMER_REPEATED)

    def unregister_poll_timer(self, timer):
        """Unregister a timer.

        :param timer: a timer returned by register_poll_timer.
        :return:

        """
        self.dispatcher.timer_unregister(timer)

    def register_transport(self, transport, callback, arg=None):
        """Register transport to dispatcher, the dispatcher will call the
        function when some events happens, currently, we will the use the
        PULLIN event.

        :param transport: one transport class, represents a socket, with
         a fileno.
        :param callback: the callback function, which will called when we
         received sth.
        :param arg: the args we passed into callback
        :return: None

        """
        if not isinstance(transport, Transport):
            self.logger.error(
                "Cannot register the transport, parameter transport type is not correct, expect: "
                "Transport, real:%s" % type(transport))
            return False

        self.logger.info("Register a transport into dispatcher, path=%s" %
                         transport.path)
        self.dispatcher.fd_register(transport.sock,
                                    Dispatcher.EV_FD_IN | Dispatcher.EV_FD_ERR,
                                    callback)

    def unregister_transport(self, transport):
        """Remove the transport from the dispatcher.

        :param transport: one transport class, represents a socket, with
         a fileno.
        :return: None

        """
        if not isinstance(transport, Transport):
            self.logger.error(
                "Cannot unregister the transport, parameter transport type is not correct, expect: "
                "Transport, real:%s" % type(transport))
            return False

        self.logger.info("UnRegister a transport into dispatcher, path=%s" %
                         transport.path)
        self.dispatcher.fd_unregister(transport.fileno)

    def start_process(self, args):
        """
        :param args: The args includes the command, and the it should be
         a tuple or a list.
        :return: popen process class

        """
        try:
            popenObj = subprocess.Popen(args, cwd="/tmp/")
            return popenObj
        except Exception as e:
            self.logger.error(str(e))
            return None

    def terminate_process(self, popenObj):
        """Terminate a process.

        :param popenObj: this is a obj returned by the start process
        :return: True for execute cmd successfully, false for arg error

        """
        if not isinstance(popenObj, subprocess.Popen):
            self.logger.warn(
                "Cannot terminate a process since the arg is %s, not Popen object.",
                type(popenObj))
            return False

        self.logger.info("Terminate process %d", popenObj.pid)
        popenObj.terminate()

        return True

    def kill_process(self, popenObj):
        """kill a process.

        :param popenObj: this is a obj returned by the start process
        :return: True for execute cmd successfully, false for arg error

        """

        if not isinstance(popenObj, subprocess.Popen):
            self.logger.warn(
                "Cannot kill a process since the arg is %s, not Popen object.",
                type(popenObj))
            return False

        self.logger.info("kill process %d", popenObj.pid)
        popenObj.kill()

        return True

    def check_process_status(self, popenObj):
        """Check the status of the process.

        :param popenObj: this is a obj returned by the start process
        :return: Terminated/Alive

        """
        if not isinstance(popenObj, subprocess.Popen):
            self.logger.warn(
                "Cannot terminate a process since the arg is %s, not Popen object.",
                type(popenObj))
            return False, -1

        popenObj.poll()
        retcode = popenObj.returncode

        if retcode is None:
            return self.PROCESSSTATE_ALIVE
        return self.PROCESSSTATE_DEAD

    def set_logging_level(self, level):
        """Set module logger level for system logging.

        :param level:

        """
        try:
            self.logger.setLevel(level)
            return True, 'success'
        except (ValueError, TypeError) as e:
            return False, str(e)

    def cleanup_db(self, ccap_core_id):
        """cleanup the remain requester if exist."""
        raise NotImplementedError()
Ejemplo n.º 4
0
 def test_fd_reg(self):
     d = Dispatcher()
     d.fd_register(0, Dispatcher.EV_FD_ALL, None)
     d.fd_modify(0, 0)
     d.fd_unregister(0)
     del d
Ejemplo n.º 5
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())