def test_send(self): """test HalTransport#send. check whether none message can be send, if can't catch the specific exception case fail check whether hello message can be send, if the returned value is false case fail. :keyword:HalTransport#send :exception:assertRegexpMatches(str(e), "Cannot send the msg since the msg is None, agent.*"), assertEqual(pushSock.send("hello"), True) :parameter: :return: """ transport = HalTransport( HalTransport.HalTransportClientMgr, HalTransport.HalServerMode, disconnectHandlerCb=self._disconnectCb) try: transport.send(None) except Exception as e: self.assertRegexpMatches( str(e), "Cannot send the msg since the msg is None, agent.*") transport.socket.disable_monitor() transport.monitor.close() transport.close() pushSock = HalTransport( HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode, index=19, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=None) self.assertEqual(pushSock.send("hello"), True) pushSock.socket.disable_monitor() pushSock.monitor.close() pushSock.close()
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()
class CliHalIpc(object): """ The Client for Hal """ __metaclass__ = AddLoggerToClass def __init__(self, appName, appDesc, appVer, interestedNotification, logConfigurePath=None): """ :param appName: The application name, such as RPD CLI :param appDesc: A brief description about this application, such as the functionality description :param appVer: Driver specific version, such as 1.0.1 :param interestedNotification: a tuple or list for the application interested msg types, the form will be (1, 2, 456, 10) :return: HalClient object """ # sanity check the input args if not isinstance(appName, str) or not isinstance(appDesc, str) or not isinstance(appVer, str): raise HalClientError("Driver name/desc/version should be a str type") if not isinstance(interestedNotification, tuple) and not isinstance(interestedNotification, list): raise HalClientError("supportedMsgType should be a tuple or list") self.appName = appName self.appDesc = appDesc self.appVer = appVer self.interestedNotification = list(interestedNotification) # setup the logging # self.logger = log self.pollTimeout = 2000 # update the supported messages self.HalMsgsHandler = { "HalClientRegisterRsp": self.recvRegisterMsgCb, "HalClientHelloRsp": self.recvHelloRspMsgCb, "HalClientInterestNotificationCfgRsp": self.sendInterestedNotificationsRspCb, } self.clientID = None self.mgrConnection = None self.pushSock = None self.pullSock = None self.disconnected = True self.seqNum = 0 self.index = -1 self.CfgMsgId_dict = dict(CLI_TO_HAL_MSG_TYPE.items()) def start(self): """ start poll the transport socket :return: """ self.logger.debug("Start connect to hal...") self.connectionSetup() self.register(self.clientID) def connectionSetup(self): """ Create the connection to the mgr and setup the poller :return: """ self.logger.debug("Create the connection to the mgr....") # Create a connection to Hal driver mgr self.mgrConnection = HalTransport(HalTransport.HalTransportClientMgr, HalTransport.HalClientMode, disconnectHandlerCb=self.connectionDisconnectCb) def register(self, clientID): """ send a register message to Hal and get the device ID from the Hal. :return: """ if clientID is None: registerMsg = HalMessage("HalClientRegister", ClientName=self.appName, ClientDescription=self.appDesc, ClientVersion=self.appVer) else: registerMsg = HalMessage("HalClientRegister", ClientName=self.appName, ClientDescription=self.appDesc, ClientVersion=self.appVer, ClientID=clientID) if self.mgrConnection is None: errMsg = "Cannot send the register since the mgr connection is not setup" self.logger.error(errMsg) raise HalClientError(errMsg) self.logger.debug("Send the register msg to Hal...") self.mgrConnection.send(registerMsg.Serialize()) bin = self.mgrConnection.recv() rsp = HalMessage.DeSerialize(bin) self.recvRegisterMsgCb(rsp) def _send(self, msg): if self.pushSock: self.pushSock.send(msg) else: self.logger.error("Cannot send the msg since the push socket is NULL") def sendMsg(self, cfgMsg): """ The configutaion response routine, the driver implementor should fill sth into this function :param cfg: The original configutaion message :return: """ if self.disconnected: self.logger.error("The client is on disconencted state," " skip to send the message.") return if cfgMsg is None or not isinstance(cfgMsg, t_CliMessage): self.logger.error("Cannot send a None or incorrect type to HAL") return for desc, value in cfgMsg.CliData.ListFields(): if desc.name not in self.CfgMsgId_dict: self.logger.error("Cannot not find %s" % desc.name) return msg = HalMessage("HalConfig", SrcClientID=self.clientID, SeqNum=self.seqNum, CfgMsgType=self.CfgMsgId_dict[desc.name], CfgMsgPayload=cfgMsg.SerializeToString()) self._send(msg.Serialize()) seq = self.seqNum self.seqNum += 1 return seq def recvMsg(self, timeout=None): if self.pullSock: try: bin = self.pullSock.recv() except Exception as e: print("Got exception when receiving the msg, reason:%s" % str(e)) return None rsp = HalMessage.DeSerialize(bin) if rsp.msg.Rsp.Status != HalCommon_pb2.SUCCESS: self.logger.error("Get rsp msg fail, reason[%s]" % rsp.msg.Rsp.ErrorDescription) return None cli_msg = t_CliMessage() cli_msg.ParseFromString(rsp.msg.CfgMsgPayload) return cli_msg else: self.logger.error("Cannot receive msg since the pull socket is NULL") return None def sayHelloToHal(self): """ Send a hello message to verify the agent path is correct :return: """ self.logger.debug("Send a Hello message to Hal") helloMsg = HalMessage("HalClientHello", ClientID=self.clientID) self._send(helloMsg.Serialize()) def sendInterestedNotifications(self, notifications): """ Send the notifications to the HAL :param notifications: :return: """ self.logger.debug("Send a Interested notification configuration msg to HAL") if notifications is not None and not isinstance(notifications, tuple) and not isinstance(notifications, list): self.logger.error("Cannot set an notification with wrong type, you can pass a tuple or list to it ") return configMsg = HalMessage("HalClientInterestNotificationCfg", ClientID=self.clientID, ClientNotificationMessages=notifications) self.mgrConnection.send(configMsg.Serialize()) # REQ/RSP bin = self.mgrConnection.recv() return bin def sendInterestedNotificationsRspCb(self, rsp): """ Receive a response message from the HAL for the notification rsp callback :param rsp: :return: """ self.logger.debug("Receive a interest notification response message:" + str(rsp.msg)) def recvHelloRspMsgCb(self, hello): """ Call back for Hello Message :param hello: :return: """ self.logger.debug("Recv a hello message:" + str(hello.msg)) def connectionDisconnectCb(self, msg): """ the connection has been detected disconnected , register it again We have reconenct, we have to assure the regiter message is received by the HAL :param msg: :return: """ if self.disconnected: self.logger.debug("A previous event has been processed, skip it!") return self.logger.debug("Detected disconnected, register again") # clean up the push and pull socket if 0: self.pushSock.close() self.pullSock.close() self.pushSock = None self.pullSock = None self.mgrConnection = None # self.clientID = None #will not set it to none since self.connectionSetup() self.mgrConnection.monitor.close() self.mgrConnection.close() # create the connection again self.connectionSetup() self.register(self.clientID) # The zmq lower part will handle the reconnect self.disconnected = True def recvRegisterMsgCb(self, cfg): """ the callback handler for the configuration message :param cfg: the configuration message received frm the Hal :return: """ # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg)) if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS: self.logger.error("Cannot register to Hal, reason[%s]" % cfg.msg.Rsp.ErrorDescription) return self.clientID = cfg.msg.ClientID # Setup the push and pull connection self.pullPath = cfg.msg.PathFromHalToClient self.pushPath = cfg.msg.PathFromClientToHal # get the index of the path index = self._getIndexFromPath() if index == -1: self.logger.error("Cannot get index from the path [%s]" % self.pushPath) return if self.index == -1: self.index = index self.pushSock = HalTransport(HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode, index=index, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=self.connectionDisconnectCb) self.pullSock = HalTransport(HalTransport.HalTransportClientAgentPush, HalTransport.HalClientMode, index=index, socketMode=HalTransport.HalSocketPullMode, disconnectHandlerCb=self.connectionDisconnectCb) self.sendInterestedNotifications(self.interestedNotification) self.disconnected = False return def clientQuery(self): """ Send a client query message to get all registered client info :return: """ if self.disconnected: self.logger.error("The client is on disconencted state," " skip to send the message.") return None self.logger.debug("Send a client query message to Hal") clientQueryMsg = HalMessage("HalClientQuery", ClientID=self.clientID) self.mgrConnection.send(clientQueryMsg.Serialize()) try: bin = self.mgrConnection.recv() except Exception as e: print("Got exception when receiving the msg, reason:%s" % str(e)) return None rsp = HalMessage.DeSerialize(bin) if rsp.msg.MsgType != "HalClientQueryRsp": self.logger.error("Cannot Query client, " "reason[msgType mismatch:%s]" % rsp.msg.MsgType) return None return rsp def getClientstats(self, clientId): """ Send a client statistics request message :return: """ if self.disconnected: self.logger.error("The client is on disconencted state," " skip to send the message.") return None self.logger.debug("Send a client statistics message to Hal") statsQueryMsg = HalMessage("HalAgentStatsReq", ClientID=clientId) self.mgrConnection.send(statsQueryMsg.Serialize()) try: bin = self.mgrConnection.recv() except Exception as e: print("Got exception when receiving the msg, reason:%s" % str(e)) return None rsp = HalMessage.DeSerialize(bin) if rsp.msg.MsgType != "HalAgentStatsRsp": self.logger.error("Cannot Query client statistics, " "reason[msgType mismatch:%s]" % rsp.msg.MsgType) return None return rsp def _getIndexFromPath(self): rePattern = r"/(\d+)/" ret = re.search(rePattern, self.pushPath) if ret is not None: digitStr = ret.group(1) return int(digitStr) return -1
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) trans.send(strMsg) bin = trans.recv() rsp = HalMessage.DeSerialize(bin) ClientID = rsp.msg.ClientID push = rsp.msg.PathFromHalToClient pull = rsp.msg.PathFromClientToHal print ClientID print pull print push # Create the Pull interface context = HalTransport.context
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")
class HalPtpClient(HalClient): """The PTP Client for Hal.""" SYNC = "ALIGNED" LOS = "LOSS OF SYNC" __metaclass__ = AddLoggerToClass def __init__(self, appName, appDesc, appVer, supportedNotification, supportedMsgsTypes, dispatcher, notifyCb, logConfigurePath=None): # sanity check the input args super(HalPtpClient, self).__init__(appName, appDesc, appVer, supportedNotification, logConfigurePath, supportedMsgsTypes) if not isinstance(supportedNotification, tuple) and not isinstance( supportedNotification, list): raise HalClientError( "supportedMsgsTypes should be a tuple or list") self.HalMsgsHandler = { "HalClientRegisterRsp": self.recvRegisterMsgCb, "HalSetLoggingLevelRsp": self.recvHalSetLoggingLevelRspCb, "HalClientHelloRsp": self.recvHelloRspMsgCb, "HalConfigRsp": self.recvCfgMsgRspCb, "HalClientInterestNotificationCfgRsp": self.sendInterestedNotificationsRspCb, "HalNotification": self.recvNotificationCb, "HalConfig": self.recvCfgMsgCb, } self.notifyHandler = notifyCb self.dispatcher = dispatcher self.supportedNotificationMsgs = list(supportedNotification) self.dispatcher.timer_register(1, self.checkPtpStatus, timer_type=1) self.ptp_result = t_GeneralNotification.PTPACQUIRE def checkPtpStatus(self, fd): self.sendCfgMsg(MsgTypePtpStatusGet, "GetPtpStatus") def start(self): """Start polling the transport socket.""" self.logger.debug("Start the client poll...") self.connectionSetup(self.dispatcher) self.register(self.clientID) def connectionSetup(self, disp=None): """Create the connection to the mgr and setup the poller.""" self.logger.debug("Create the connection to the mgr....") # Create a connection to Hal driver mgr self.mgrConnection = HalTransport( HalTransport.HalTransportClientMgr, HalTransport.HalClientMode, disconnectHandlerCb=self.connectionDisconnectCb) # register the mgr socket disp.fd_register(self.mgrConnection.socket, zmq.POLLIN, self.ptp_hal_cb) disp.fd_register(self.mgrConnection.monitor, zmq.POLLIN, self.ptp_hal_cb) def connectionDisconnectCb(self, msg): """The connection has been detected disconnected , register it again We have reconenct, we have to assure the regiter message is received by the HAL. :param msg: :return: """ if self.disconnected: self.logger.debug("A previous event has been processed, skip it!") return self.logger.debug("Detected disconnected, register again") # clean up the push and pull socket if 1: self.pushSock.close() self.pullSock.close() self.dispatcher.fd_unregister(self.pullSock.socket) self.dispatcher.fd_unregister(self.pullSock.monitor) self.dispatcher.fd_unregister(self.pullSock.monitor) self.pushSock = None self.pullSock = None self.mgrConnection = None # self.clientID = None #will not set it to none since self.connectionSetup(self.dispatcher) def recvRegisterMsgCb(self, cfg): """The callback handler for the configuration message. :param cfg: the configuration message received frm the Hal :return: """ # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg)) if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS: self.logger.error("Cannot register to Hal, reason[%s]" % cfg.msg.Rsp.ErrorDescription) return self.clientID = cfg.msg.ClientID # Setup the push and pull connection self.pullPath = cfg.msg.PathFromHalToClient self.pushPath = cfg.msg.PathFromClientToHal # get the index of the path index = self._getIndexFromPath() if index == -1: self.logger.error("Cannot get index from the path [%s]" % self.pushPath) return if self.index == -1: self.index = index self.pushSock = HalTransport( HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode, index=index, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=self.connectionDisconnectCb) self.pullSock = HalTransport( HalTransport.HalTransportClientAgentPush, HalTransport.HalClientMode, index=index, socketMode=HalTransport.HalSocketPullMode, disconnectHandlerCb=self.connectionDisconnectCb) # register to the poller self.dispatcher.fd_register(self.pullSock.socket, zmq.POLLIN, self.ptp_hal_cb) self.dispatcher.fd_register(self.pushSock.monitor, zmq.POLLIN, self.ptp_hal_cb) self.dispatcher.fd_register(self.pullSock.monitor, zmq.POLLIN, self.ptp_hal_cb) # send Hello To Hal self.sayHelloToHal() self.sendInterestedNotifications(self.interestedNotification) self.disconnected = False return def recvCfgMsgCb(self, cfgMsg): """Receive a configuration message from the Hal, processing it. :param cfgMsg: :return: """ try: msgType = cfgMsg.msg.CfgMsgType if msgType == MsgTypeRpdState: self.getRpdPtpState(cfgMsg) except Exception as e: # pragma: no cover self.logger.error("Got an error:%s, the cfg msg:%s", str(e), cfgMsg) rsp = { "Status": HalCommon_pb2.FAILED, "ErrorDescription": "Process configuration failed, reason:%s" % str(e) } self.sendCfgRspMsg(cfgMsg, rsp) def recvCfgMsgRspCb(self, cfg): """Receive a configuration response message from the Hal, processing it. :param cfg: :return: """ self.logger.debug("Recv a ptp configuration response message:" + str(cfg.msg)) if cfg.msg.CfgMsgType == MsgTypePtpStatusGet: if cfg.msg.CfgMsgPayload in [self.LOS, self.SYNC]: self.notifyHandler(cfg.msg.CfgMsgPayload) self.logger.debug("send %s notification to provision", cfg.msg.CfgMsgPayload) def ptp_hal_cb(self, sock, mask): if self.pushSock is not None and sock == self.pushSock.monitor: self.pushSock.monitorHandler(recv_monitor_message(sock)) return if self.pullSock is not None and sock == self.pullSock.monitor: self.pullSock.monitorHandler(recv_monitor_message(sock)) return if self.mgrConnection is not None and sock == self.mgrConnection.monitor: self.mgrConnection.monitorHandler(recv_monitor_message(sock)) return while sock.getsockopt(zmq.EVENTS) and zmq.POLLIN: try: bin = sock.recv(flags=zmq.NOBLOCK) msg = HalMessage.DeSerialize(bin) self.logger.debug("###########Got a zmq msg:%s" % msg.msg) if msg.type in self.HalMsgsHandler: handler = self.HalMsgsHandler[msg.type] handler(msg) except zmq.ZMQError as e: self.logger.debug( "Geting an error when trying with nonblock read:" + str(e)) break except Exception as e: self.logger.error("Error happens, reason:%s" % str(e)) break def recvNotificationCb(self, msg): """Receive the notification from ptp hal driver. :param msg: :return: """ self.logger.info("recv the notification from ptp driver") print msg.msg.HalNotificationType print msg.msg.HalNotificationPayLoad if msg.msg.HalNotificationType == MsgTypePtpClockStatus: if msg.msg.HalNotificationPayLoad in [self.LOS, self.SYNC]: self.notifyHandler(msg.msg.HalNotificationPayLoad) print "send %s notification to provision" % msg.msg.HalNotificationPayLoad def getRpdPtpState(self, cfg): rsp = t_RcpMessage() rsp.ParseFromString(cfg.msg.CfgMsgPayload) config = rsp.RpdDataMessage.RpdData try: config.RpdState.LocalPtpSyncStatus = \ True if self.ptp_result == t_GeneralNotification.PTPSYNCHRONIZED else False cfg.CfgMsgPayload = config.SerializeToString() rsp.RpdDataMessage.RpdData.CopyFrom(config) rsp.RcpDataResult = t_RcpMessage.RCP_RESULT_OK payload = rsp.SerializeToString() self.logger.info("Send rpd state LocalPtpSyncStatus response, %s" % rsp) msg = HalMessage("HalConfigRsp", SrcClientID=cfg.msg.SrcClientID, SeqNum=cfg.msg.SeqNum, Rsp={ "Status": HalCommon_pb2.SUCCESS, "ErrorDescription": "PTP LOCALPTPSYNCSTATUS query success" }, CfgMsgType=cfg.msg.CfgMsgType, CfgMsgPayload=payload) self.pushSock.send(msg.Serialize()) except Exception as e: self.logger.error("excpetipn:%s", str(e)) return
class HalClient(object): """The Client for Hal.""" __metaclass__ = AddLoggerToClass def __init__(self, appName, appDesc, appVer, interestedNotification, logConfigurePath=None, supportedMsgType=[]): """ :param appName: The application name, such as RPD CLI :param appDesc: A brief description about this application, such as the functionality description :param appVer: Driver specific version, such as 1.0.1 :param interestedNotification: a tuple or list for the application interested msg types, the form will be (1, 2, 456, 10) :param supportedMsgType: a tuple or list of HalConfig message types, the form will be (5000,) :return: HalClient object """ # sanity check the input args if not isinstance(appName, str) or not isinstance( appDesc, str) or not isinstance(appVer, str): raise HalClientError( "Driver name/desc/version should be a str type") if not isinstance(interestedNotification, tuple) and not isinstance( interestedNotification, list): raise HalClientError( "interestedNotification should be a tuple or list") if not isinstance(supportedMsgType, list): raise HalClientError("supportedMsgType should be a list") self.appName = appName self.appDesc = appDesc self.appVer = appVer self.interestedNotification = list(interestedNotification) self.supportedMsgType = list(supportedMsgType) self.pollTimeout = 2000 # update the supported messages self.HalMsgsHandler = { "HalClientRegisterRsp": self.recvRegisterMsgCb, "HalSetLoggingLevelRsp": self.recvHalSetLoggingLevelRspCb, "HalClientHelloRsp": self.recvHelloRspMsgCb, "HalConfigRsp": self.recvCfgMsgRspCb, "HalClientInterestNotificationCfgRsp": self.sendInterestedNotificationsRspCb, } self.clientID = None self.mgrConnection = None self.pushSock = None self.pullSock = None self.disconnected = True self.poller = None self.seqNum = 0 self.index = -1 def start(self): """Start polling the transport socket. :return: """ self.logger.debug("Start the client poll...") self.connectionSetup() self.register(self.clientID) lastTimeout = time() sendOnce = False while True: # Todo we should support quit flag? socks = self.poller.poll(self.pollTimeout) if time() - lastTimeout > self.pollTimeout / 1000: lastTimeout = time() self.logger.debug("Got a timeout event") if not sendOnce: # self.sendCfgMsg(100, "hello") self.setHalDebugLevel("HalMain", logging.INFO) sendOnce = True if not socks: continue for sock in socks: # FIXME do we need to continue recv from the monitor interface? if self.pushSock is not None and sock == self.pushSock.monitor: self.pushSock.monitorHandler(recv_monitor_message(sock)) continue if self.pullSock is not None and sock == self.pullSock.monitor: self.pullSock.monitorHandler(recv_monitor_message(sock)) continue if self.mgrConnection is not None and sock == self.mgrConnection.monitor: self.mgrConnection.monitorHandler( recv_monitor_message(sock)) continue if socks[sock] == HalPoller.POLLIN: try: bin = sock.recv(flags=zmq.NOBLOCK) msg = HalMessage.DeSerialize(bin) self.logger.debug("Got a zmq msg:%s" % msg.msg) if msg.type in self.HalMsgsHandler: handler = self.HalMsgsHandler[msg.type] handler(msg) else: self.logger.warn("Unsupported msg type:%s" % msg.type) except zmq.ZMQError as e: self.logger.debug( "Got an error when trying with non-block read:" + str(e)) except Exception as e: self.logger.error("Error happens, reason:%s" % str(e)) continue # self.logger.error("Cannot handle the event, No handler for # it") def connectionSetup(self): """Create the connection to the mgr and setup the poller. :return: """ self.logger.debug("Create the connection to the mgr....") # Create a connection to Hal driver mgr self.mgrConnection = HalTransport( HalTransport.HalTransportClientMgr, HalTransport.HalClientMode, disconnectHandlerCb=self.connectionDisconnectCb) self.HalMsgsHandler[self.mgrConnection.socket] = self.recvRegisterMsgCb # create the poller if self.poller is None: self.poller = HalPoller() # register the mgr socket self.poller.register(self.mgrConnection.socket) self.poller.register(self.mgrConnection.monitor) def register(self, clientID): """Send a register message to Hal and get the client ID from the Hal. :return: """ if clientID is None: if len(self.supportedMsgType) > 0: registerMsg = HalMessage( "HalClientRegister", ClientName=self.appName, ClientDescription=self.appDesc, ClientVersion=self.appVer, ClientSupportedMessages=self.supportedMsgType) else: registerMsg = HalMessage("HalClientRegister", ClientName=self.appName, ClientDescription=self.appDesc, ClientVersion=self.appVer) else: if len(self.supportedMsgType) > 0: registerMsg = HalMessage( "HalClientRegister", ClientName=self.appName, ClientDescription=self.appDesc, ClientVersion=self.appVer, ClientSupportedMessages=self.supportedMsgType, ClientID=clientID) else: registerMsg = HalMessage("HalClientRegister", ClientName=self.appName, ClientDescription=self.appDesc, ClientVersion=self.appVer, ClientID=clientID) if self.mgrConnection is None: errMsg = "Cannot send the register since the mgr connection is not setup" self.logger.error(errMsg) raise HalClientError(errMsg) self.logger.debug("Send the register msg to Hal...") self.mgrConnection.send(registerMsg.Serialize()) def _sendMsg(self, msg): if self.pushSock: self.pushSock.send(msg) else: self.logger.error( "Cannot send the msg since the push socket is None, msg:%s", str(msg)) def sayHelloToHal(self): """Send a hello message to verify the agent path is correct. :return: """ self.logger.debug(" ".join([ str(self.appName), str(self.clientID), ":Send a Hello message to Hal" ])) helloMsg = HalMessage("HalClientHello", ClientID=self.clientID) self._sendMsg(helloMsg.Serialize()) def sendNotificationMsg(self, notificationType, notificationPayload): """Send a notification to Hal. :param notificationType: The notification type, the client must declare the notification type to Hal first :param notificationPayload: the string payload, Hal will not touch this part :return: """ self.logger.debug("send a notification message to Hal") notfication = HalMessage("HalNotification", ClientID=self.clientID, HalNotificationType=notificationType, HalNotificationPayLoad=notificationPayload) self.pushSock.send(notfication.Serialize()) def sendInterestedNotifications(self, notifications): """Send the notifications to the HAL. :param notifications: :return: """ self.logger.debug( "Send a Interested notification configuration msg to HAL") if notifications is not None and not isinstance( notifications, tuple) and not isinstance(notifications, list): self.logger.error( "Cannot set an notification with wrong type, you can pass a tuple or list to it " ) return configMsg = HalMessage("HalClientInterestNotificationCfg", ClientID=self.clientID, ClientNotificationMessages=notifications) self.mgrConnection.send(configMsg.Serialize()) def sendInterestedNotificationsRspCb(self, rsp): """Receive a response message from the HAL for the notification rsp callback. :param rsp: :return: """ self.logger.debug("Receive a interest notification response message:" + str(rsp.msg)) def recvHelloRspMsgCb(self, hello): """Call back for Hello Message. :param hello: :return: """ self.logger.debug("Recv a hello message:" + str(hello.msg)) def recvCfgMsgRspCb(self, cfg): """Receive a configuration response message from the Hal, processing it. :param cfg: :return: """ self.logger.debug("Recv a configuration response message:" + str(cfg.msg)) def connectionSetupCb(self): pass def connectionDisconnectCb(self, msg): """TODO: This comment is confusing. Need to be cleaned up. The connection has been detected disconnected , register it again We have reconenct, we have to assure the regiter message is received by the HAL :param msg: :return: """ if self.disconnected: self.logger.debug("A previous event has been processed, skip it!") return self.logger.debug("Detected disconnected, register again") # clean up the push and pull socket if 0: self.pushSock.close() self.pullSock.close() self.poller.unregister(self.pullSock.socket) self.poller.unregister(self.pullSock.monitor) self.poller.unregister(self.pullSock.monitor) self.pushSock = None self.pullSock = None self.mgrConnection = None # self.clientID = None #will not set it to none since self.connectionSetup() self.poller.unregister(self.mgrConnection.socket) self.poller.unregister(self.mgrConnection.monitor) self.mgrConnection.socket.disable_monitor() self.mgrConnection.monitor.close() self.mgrConnection.close() # create the connection again self.connectionSetup() self.register(self.clientID) # The zmq lower part will handle the reconnect self.disconnected = True def sendCfgMsg(self, cfgMsgType, cfgMsgContent): """The configutaion response routine, the driver implementor should fill sth into this function. :param cfg: The original configutaion message :return: """ self.logger.debug("Send a config message to HAL: %r", cfgMsgContent) if self.disconnected: self.logger.warn( "The client is on disconnected state, skip to send the message." ) return if cfgMsgContent is None or not isinstance(cfgMsgContent, str): self.logger.error( "Cannot send a None or incorrect type to HAL, str is required for msg" ) return msg = HalMessage("HalConfig", SrcClientID=self.clientID, SeqNum=self.seqNum, CfgMsgType=cfgMsgType, CfgMsgPayload=cfgMsgContent) self._sendMsg(msg.Serialize()) seq = self.seqNum self.seqNum += 1 return seq def sendCfgRspMsg(self, cfg, rsp=None): """The configuration response routine, the driver implementor should fill sth into this function. :param cfg: The original configuration message :param rsp: respond :return: """ cfgMsg = cfg.msg msg = HalMessage("HalConfigRsp", SrcClientID=cfgMsg.SrcClientID, SeqNum=cfgMsg.SeqNum, Rsp=rsp, CfgMsgType=cfgMsg.CfgMsgType, CfgMsgPayload=cfgMsg.CfgMsgPayload) if None is not self.pushSock: self.pushSock.send(msg.Serialize()) def setHalDebugLevel(self, module, level): """Set the HAl debug level. :param module: the Hal module name :param level: the logging level :return: """ self.logger.info("Set hal module[%s] to level [%s]" % (module, logging.getLevelName(level))) if self.disconnected: self.logger.warn("Cannot send the HAL debug configuration to HAL" " since the client is in disconnected state.") return msg = HalMessage("HalSetLoggingLevel", ClientID=self.clientID, Module=module, LoggingLevel=level) self.mgrConnection.send(msg.Serialize()) def recvHalSetLoggingLevelRspCb(self, rsp): self.logger.debug(str(rsp.msg)) def recvRegisterMsgCb(self, cfg): """The callback handler for the configuration message. :param cfg: the configuration message received frm the Hal :return: """ # self.logger.debug("Recv a Message from the Hal:" % str(cfg.msg)) if cfg.msg.Rsp.Status != HalCommon_pb2.SUCCESS: self.logger.error("Cannot register to Hal, reason[%s]" % cfg.msg.Rsp.ErrorDescription) return self.clientID = cfg.msg.ClientID # Setup the push and pull connection self.pullPath = cfg.msg.PathFromHalToClient self.pushPath = cfg.msg.PathFromClientToHal # get the index of the path index = self._getIndexFromPath() if index == -1: self.logger.error("Cannot get index from the path [%s]" % self.pushPath) return if self.index == -1: self.index = index self.pushSock = HalTransport( HalTransport.HalTransportClientAgentPull, HalTransport.HalClientMode, index=index, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=self.connectionDisconnectCb) self.pullSock = HalTransport( HalTransport.HalTransportClientAgentPush, HalTransport.HalClientMode, index=index, socketMode=HalTransport.HalSocketPullMode, disconnectHandlerCb=self.connectionDisconnectCb) # register to the poller self.poller.register(self.pullSock.socket) self.poller.register(self.pushSock.monitor) self.poller.register(self.pullSock.monitor) # send Hello To Hal self.sayHelloToHal() self.sendInterestedNotifications(self.interestedNotification) self.disconnected = False return def _getIndexFromPath(self): rePattern = r"/(\d+)/" ret = re.search(rePattern, self.pushPath) if ret is not None: digitStr = ret.group(1) return int(digitStr) return -1
class HalAgentClient(HalAgent): """This class is the client agent class. the class will have the following API: * disconnectHandler: the handler will be invoked when the transport layer get a disconnect event, the function will clean the agent resources, including the socket resource, remove it from the global runtime DB. * sendMsg: This API will send message via Agent's pushsock channel. * handleClientHello: The API will handle the Hello message * handleConfigRsp: This API will handle the configuration response HalMessage from client * handleNotification: This API will handle the notification HalMessage """ ClientIndex = 0 # self handle table HalGlobal.gHandleTable["HalClientHello"] = "handleClientHello" HalGlobal.gHandleTable["HalConfig"] = "handleConfig" HalGlobal.gHandleTable["HalConfigRsp"] = "handleConfigRsp" HalGlobal.gHandleTable["HalNotification"] = "handleNotification" __metaclass__ = AddLoggerToClass def __init__(self, poller, clientID, disconnectHandler, reuseIndex=None): """The function will generate the client agent object. the main function is to create the socket channel. for Hal the sock channel works at the server mode, it will listen at these sockets. :param poller: a global poller, the transport socket and the monitor socket will register into it. :param ClientID: a client UUID :param disconnectHandler: the manager disconnect handler, will be called with agent gets a disconnect event. :param reuseIndex: for the client restart, it will provide it's previous ID, the agent will reuse these ID and use the same transport path. :return: agent obj """ super(HalAgentClient, self).__init__() if reuseIndex is None: # Generate the client index while True: index = HalAgentClient.ClientIndex HalAgentClient.ClientIndex += 1 if str(index) not in HalGlobal.gClientIndex.values(): break else: index = reuseIndex self.index = index if clientID not in HalGlobal.gClientIndex: HalGlobal.gHalClientDbConnection.addMsgtoDB( "ClientIndex", {clientID: index}, expired=False) # Start the transport self.transportPush = HalTransport( HalTransport.HalTransportClientAgentPush, HalTransport.HalServerMode, index=index, socketMode=HalTransport.HalSocketPushMode, disconnectHandlerCb=self.disconnectHandler) # for the push, we don't need to register to the poller if self.transportPush.monitor: poller.register(self.transportPush.monitor) HalGlobal.gMonitorSocketMappingTable[ self.transportPush.monitor] = self.transportPush # start the pull transport self.transportPull = HalTransport( HalTransport.HalTransportClientAgentPull, HalTransport.HalServerMode, index=index, socketMode=HalTransport.HalSocketPullMode, disconnectHandlerCb=self.disconnectHandler) poller.register(self.transportPull.socket) # add the pull socket to the socket agent mapping table HalGlobal.gSocketAgentMappingTable[self.transportPull.socket] = self # process the monitor if self.transportPull.monitor: poller.register(self.transportPull.monitor) HalGlobal.gMonitorSocketMappingTable[ self.transportPull.monitor] = self.transportPull # For other variables self.mgrDisconnectCb = disconnectHandler self.disconnectProcessed = False self.poller = poller self.clientID = clientID # put the message into the resend list self.logger.debug("Check the last unsuccessful message.%s for client[%s]" % ( HalGlobal.gRestartResendMsg, self.clientID)) if self.clientID: for key in HalGlobal.gRestartResendMsg: if key.startswith(self.clientID): self.logger.debug("Add message[%s] to resend list" % key) cfg = HalGlobal.gRestartResendMsg[key] seqNum = cfg.msg.SeqNum if cfg.msg.HasField( "SeqNum") else 0 self.addToResendList(seq=seqNum, sendagent=self, msg=cfg) def disconnectHandler(self, transport): """the function will be invoked when the transport layer get a disconnect event, the fucntion will clean the agent resources, including the socket resource, remove it from the global runtime DB. :param transport: the transport object, pull/push :return: """ self.logger.info( "Got a client[%s] disconnect event, process it in client agent" % self.clientID) # we have two transport layer can trigger this handler, we only need one time to process, # this flag is used for this if self.disconnectProcessed: self.logger.info( "client disconnect event has been processed") return # unregister/close the monitor socket if self.transportPull.monitor: HalGlobal.gMonitorSocketMappingTable.pop( self.transportPull.monitor) self.poller.unregister(self.transportPull.monitor) self.transportPull.socket.disable_monitor() self.transportPull.monitor.close() if self.transportPush.monitor: HalGlobal.gMonitorSocketMappingTable.pop( self.transportPush.monitor) self.poller.unregister(self.transportPush.monitor) self.transportPush.socket.disable_monitor() self.transportPush.monitor.close() # call the mgr callback to process the disconnect event self.mgrDisconnectCb(self) # remove the transportPull from the poller self.poller.unregister(self.transportPull.socket) # remove from the socket agent mapping table HalGlobal.gSocketAgentMappingTable.pop(self.transportPull.socket) # Remove from the global Agent DB self.removeFromAgentDB() # close the push and pull, monitor socket self.transportPull.close() self.transportPush.close() self.disconnectProcessed = True def sendMsg(self, msg): """Send a message via the transport push socket. :param msg: a stringlized msg, not the HAlMessage :return: """ if msg is None: self.logger.error( "The msg is None, skip invoking the low level function") return self.transportPush.send(msg) def handleClientHello(self, hello): """The Hello message handler. :param hello: which is a HalMessage, hold all the info about the hello message :return: NA """ self.logger.debug("Send out the hello rsp message") # update the stats self.stats.NrMsgs += 1 self.stats.NrHelloMsgs += 1 if hello is None: msg = "Cannot handle a none client hello message" self.logger.error(msg) self.stats.NrErrorMsgs += 1 raise Exception(msg) rsp = HalMessage("HalClientHelloRsp", ClientID=hello.msg.ClientID) # send out self.transportPush.send(rsp.Serialize()) self.stats.NrHelloRspMsgs += 1 def handleConfigRsp(self, cfgRsp): """This API will handle the configuration response HalMessage from client. :param cfgRsp: :return: """ if cfgRsp is None: msg = "Cannot handle a none config response message" self.logger.error(msg) raise Exception(msg) HalGlobal.gHalMsgDbConnection.removeMsgFromDB( cfgRsp.msg.SrcClientID + "-" + str(cfgRsp.msg.SeqNum)) HalGlobal.gDispatcher.dispatchCfgRspMessage(self, cfgRsp) self.stats.NrCfgRspMsgs += 1 def handleNotification(self, notification): """This API will handle the notification HalMessage. :param notification: the notification HalMessage :return: """ if notification is None: msg = "Cannot handle the notification since the msg is None" self.logger.error(msg) raise Exception(msg) # update the stats self.stats.NrNotifyMsgs += 1 self.stats.NrMsgs += 1 HalGlobal.gDispatcher.dispatchNotificationMsg(self, notification) def handleConfig(self, cfg): """The configuration HalMessage handler. :param cfg: The Config message from the client :return: """ if cfg is None: msg = "Cannot handle a none config message" self.logger.error(msg) raise Exception(msg) # Add the message to the DB seqNum = cfg.msg.SeqNum if cfg.msg.HasField("SeqNum") else 0 msgBinary = cfg.originalBinary \ if cfg.originalBinary else cfg.Serialize() # add the msg to DB HalGlobal.gHalMsgDbConnection.addMsgtoDB( msgKey=cfg.msg.SrcClientID + "-" + str(seqNum), msg={ "ClientID": cfg.msg.SrcClientID, "Msg": msgBinary } ) # Update the stats self.stats.NrMsgs += 1 self.stats.NrCfgMsgs += 1 # first, process the resendList self.processResendList() # Dispatch this message to the correct client ret = HalGlobal.gDispatcher.dispatchCfgMessage(self, cfg) if ret == -1: self.addToResendList(seq=seqNum, sendagent=self, msg=cfg)
class RpdResHalClient(HalDriverClient): __metaclass__ = AddLoggerToClass def __init__(self, appName, appDesc, appVer, disp, supportedMsgType, supportedNotificationMsgs, interestedNotification=None, send_cb=None): super(RpdResHalClient, self).__init__(appName, appDesc, appVer, supportedMsgType, supportedNotificationMsgs, interestedNotification) self.operational = False self.dispatcher = disp self.HalConfigMsgHandlers = { MsgTypeHostResources: self.processHostCfgMsg, MsgTypeRpdCtrl: self.processRpdCtrlCfgMsg, } self.crashFileCtrlHandler = CrashFileCtrlHandler() self.hostResourceHandler = HostResourceHandler() def processRpdCtrlCfgMsg(self, cfgMsg): rcp_msg = t_RcpMessage() rcp_msg.ParseFromString(cfgMsg.msg.CfgMsgPayload) status = HalCommon_pb2.SUCCESS_IGNORE_RESULT recv_rcp_msg = rcp_msg.RpdDataMessage.RpdData if recv_rcp_msg.HasField("RpdCtrl"): rpdCtrl = recv_rcp_msg.RpdCtrl op = rcp_msg.RpdDataMessage.RpdDataOperation rcp_msg.RcpDataResult = t_RcpMessage.RCP_RESULT_OK flag = False if rpdCtrl.HasField("CrashDataServerCtrl"): status = HalCommon_pb2.SUCCESS self.logger.debug("Recv an RpdCtrlCfgMsg op %d, %s:" % (op, rpdCtrl)) if op == t_RpdDataMessage.RPD_CFG_WRITE: self.crashFileCtrlHandler.save_crash_data_server( rpdCtrl.CrashDataServerCtrl) flag = True if op == t_RpdDataMessage.RPD_CFG_READ: self.crashFileCtrlHandler.get_crash_data_server( rpdCtrl.CrashDataServerCtrl) flag = True if len(rpdCtrl.CrashDataFileCtrl ) > 0 and op == t_RpdDataMessage.RPD_CFG_WRITE: flag = True index = 0 for crashDataCtrl in rpdCtrl.CrashDataFileCtrl: if crashDataCtrl.HasField("Index"): index = crashDataCtrl.Index else: rcp_msg.RcpDataResult = t_RcpMessage.RCP_RESULT_GENERAL_ERROR if crashDataCtrl.HasField("FileControl"): fileControl = crashDataCtrl.FileControl if not self.crashFileCtrlHandler.update_pending_file_idx_list( index, fileControl): status = HalCommon_pb2.FAILED rcp_msg.RcpDataResult = t_RcpMessage.RCP_RESULT_GENERAL_ERROR if not flag: status = HalCommon_pb2.SUCCESS_IGNORE_RESULT else: status = HalCommon_pb2.SUCCESS elif rcp_msg.RpdDataMessage.RpdDataOperation == t_RpdDataMessage.RPD_CFG_READ: status = HalCommon_pb2.SUCCESS_IGNORE_RESULT else: status = HalCommon_pb2.FAILED payload = rcp_msg.SerializeToString() msg = HalMessage("HalConfigRsp", SrcClientID=cfgMsg.msg.SrcClientID, SeqNum=cfgMsg.msg.SeqNum, Rsp={ "Status": status, "ErrorDescription": "Get Rpd Control rsp" }, CfgMsgType=cfgMsg.msg.CfgMsgType, CfgMsgPayload=payload) return msg def processHostCfgMsg(self, cfgMsg): rsp = t_RcpMessage() # rsp.ParseFromString(cfgMsg.CfgMsgPayload) req = t_RcpMessage() req.ParseFromString(cfgMsg.msg.CfgMsgPayload) rsp.RpdDataMessage.RpdDataOperation = req.RpdDataMessage.RpdDataOperation rsp.RcpMessageType = req.RcpMessageType # load the rpd host resources information hr = rsp.RpdDataMessage.RpdData.HostResources hr.hrMemorySize = self.hostResourceHandler.getMemorySize() hr.hrProcessorLoad = self.hostResourceHandler.getProcessorLoad() self.hostResourceHandler.getStorages(hr.hrStorages) self.hostResourceHandler.getProcesses(hr.hrProcesses) rsp.RcpDataResult = t_RcpMessage.RCP_RESULT_OK payload = rsp.SerializeToString() msg = HalMessage("HalConfigRsp", SrcClientID=cfgMsg.msg.SrcClientID, SeqNum=cfgMsg.msg.SeqNum, Rsp={ "Status": HalCommon_pb2.SUCCESS, "ErrorDescription": "Host Resource" }, CfgMsgType=cfgMsg.msg.CfgMsgType, CfgMsgPayload=payload) return msg def start(self): """Connection setup. :return: """ self.logger.debug("Start the client setup...") self.connection_setup() self.register(self.drvID) def connection_setup(self): """Create the connection to the mgr and setup the poller. :return: """ self.logger.debug("Create the connection to the mgr....") # Create a connection to Hal driver mgr self.mgrConnection = HalTransport( HalTransport.HalTransportClientMgr, HalTransport.HalClientMode, disconnectHandlerCb=self.connectionDisconnectCb) # create the poller if self.poller is None: self.poller = self.dispatcher.get_poll() # register the mgr socket self.dispatcher.fd_register(self.mgrConnection.socket, self.dispatcher.EV_FD_IN, self.host_management_cb) self.dispatcher.fd_register(self.mgrConnection.monitor, self.dispatcher.EV_FD_IN, self.host_management_cb) def recvRegisterMsgCb(self, cfg): """The callback handler for the configuration message. :param cfg: the configuration message received frm the Hal :return: """ 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 self.pullPath = cfg.msg.PathFromHalToClient self.pushPath = cfg.msg.PathFromClientToHal 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.host_management_cb) self.dispatcher.fd_register(self.pushSock.monitor, zmq.POLLIN, self.host_management_cb) self.dispatcher.fd_register(self.pullSock.monitor, zmq.POLLIN, self.host_management_cb) # send Hello To Hal self.sayHelloToHal() if self.interestedNotification is not None: self.sendInterestedNotifications(self.interestedNotification) self.disconnected = False return def host_management_cb(self, sock, mask): """ :param sock: zmq socket :param mask: event mask :return: """ if self.pushSock is not None and sock == self.pushSock.monitor: self.pushSock.monitorHandler(recv_monitor_message(sock)) return if self.pullSock is not None and sock == self.pullSock.monitor: self.pullSock.monitorHandler(recv_monitor_message(sock)) return if self.mgrConnection is not None and sock == self.mgrConnection.monitor: self.mgrConnection.monitorHandler(recv_monitor_message(sock)) return while sock.getsockopt(zmq.EVENTS) and zmq.POLLIN: if not self.hal_message_cb(sock): break def hal_message_cb(self, sock): 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) except zmq.ZMQError as e: self.logger.debug( "Getting an error when trying with nonblock read:" + str(e)) return False except Exception as e: self.logger.error("Error happens, reason:%s" % str(e)) return False return True def recvCfgMsgCb(self, cfg): """Receive a configuration message from the Hal, processing it. :param cfg: :return: """ try: handler = self.HalConfigMsgHandlers[cfg.msg.CfgMsgType] msg = handler(cfg) if self.pushSock: self.pushSock.send(msg.Serialize()) self.logger.debug( "Recv a configuration message, send the rsp to it") except Exception as e: self.logger.error("Got an error:%s, the cfg msg:%s", str(e), cfg.msg)
if __name__ == "__main__": (ClientID, pullSock, pushSock) = ClientRegisterRandom() # generate many clients # for i in xrange(1): # ClientRegisterRandom() # send out the query issue queryMsg = HalMessage("HalClientQuery", ClientID=ClientID) binQueryMsg = queryMsg.Serialize() hexdump.hexdump(binQueryMsg) trans.send(binQueryMsg) bin = trans.recv() rsp = HalMessage.DeSerialize(bin) print rsp.msg # send out the driver query queryMsg = HalMessage("HalClientQuery", ClientID=ClientID) binQueryMsg = queryMsg.Serialize() hexdump.hexdump(binQueryMsg) trans.send(binQueryMsg) bin = trans.recv() rsp = HalMessage.DeSerialize(bin)
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())