Exemple #1
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()
Exemple #2
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")
Exemple #3
0
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import zmq
import hexdump
from rpd.hal.src.transport.HalTransport import HalTransport
from rpd.hal.src.msg.HalMessage import HalMessage
from rpd.hal.src.msg import HalCommon_pb2
from rpd.hal.src.msg.HalOperation_pb2 import HalNotification
from rpd.hal.src.msg.ClientProvision_pb2 import HalClientRegister

if __name__ == "__main__":
    trans = HalTransport(HalTransport.HalTransportClientMgr,
                         HalTransport.HalClientMode)
    trans.connects()

    registerMsg = HalClientRegister()
    registerMsg.MsgType = "HalClientRegister"
    registerMsg.ClientName = "Test"
    registerMsg.ClientDescription = "This is a test msg"
    registerMsg.ClientVersion = "1.0"
    registerMsg.ClientSupportedMessages.append(1)
    registerMsg.ClientSupportedMessages.append(123)
    registerMsg.ClientSupportedNotificationMessages.append(11)
    registerMsg.ClientSupportedNotificationMessages.append(12)

    strMsg = registerMsg.SerializeToString()

    # dump the message
    hexdump.hexdump(strMsg)
Exemple #4
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())