예제 #1
0
    def _handle_message(self, msg):
        '''
        'Handle a message, lock is already held
        '''
        if not self.session_open:
            return

        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            GlobalModule.EM_LOGGER.warning(
                "202010 Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get('message-id')
                if self.debug:
                    GlobalModule.EM_LOGGER.debug(
                        "%s: Received rpc message-id: %s", str(self), msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(
                    msg, "No valid message-id attribute found")

            try:
                rpc_method = rpc.getchildren()
                if len(rpc_method) != 1:
                    if self.debug:
                        GlobalModule.EM_LOGGER.debug("%s: Bad Msg: msg-id: %s",
                                                     str(self), msg_id)
                    raise ncerror.RPCSvrErrBadMsg(rpc)
                rpc_method = rpc_method[0]

                rpcname = rpc_method.tag.replace(qmap('nc'), "")
                params = rpc_method.getchildren()
                paramslen = len(params)

                if rpcname == "close-session":
                    if self.debug:
                        GlobalModule.EM_LOGGER.debug(
                            "%s: Received close-session msg-id: %s", str(self),
                            msg_id)
                    GlobalModule.EM_LOGGER.info("102007 Connection Closed: %s",
                                                str(self))
                    EmNetconfSessionDate.del_session_date(self.session_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    return
                elif rpcname == "kill-session":
                    if self.debug:
                        GlobalModule.EM_LOGGER.debug(
                            "%s: Received kill-session msg-id: %s", str(self),
                            msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    return
                elif rpcname == "get":

                    if paramslen > 1:
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    if params and not util.filter_tag_match(
                            params[0], "nc:filter"):
                        raise ncerror.RPCSvrUnknownElement(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":

                    GlobalModule.EM_LOGGER.info("102004 Receiving get-config")

                    if paramslen > 2:
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    source_param = rpc_method.find("nc:source",
                                                   namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.RPCSvrMissingElement(
                            rpc, util.elm("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter",
                                                       namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[
                                0] if params[0] != source_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(
                                rpc, unknown_elm)
                    params = [source_param, filter_param]

                elif rpcname == "edit-config":
                    GlobalModule.EM_LOGGER.info("102008 Receiving edit-config")

                    if paramslen > 2:
                        raise ncerror.RPCSvrErrBadMsg(rpc)

                    target_param = rpc_method.find("nc:target",
                                                   namespaces=NSMAP)
                    if target_param is None:
                        raise ncerror.RPCSvrMissingElement(
                            rpc, util.elm("nc:target"))

                    config_param = None
                    if paramslen == 2:
                        config_param = rpc_method.find("nc:config",
                                                       namespaces=NSMAP)
                        if config_param is None:
                            unknown_elm = params[
                                0] if params[0] != config_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(
                                rpc, unknown_elm)
                    params = [target_param, config_param]

                try:
                    rpcname = rpcname.rpartition("}")[-1]
                    method_name = "rpc_" + rpcname.replace('-', '_')
                    method = getattr(self.methods, method_name,
                                     self._rpc_not_implemented)
                    result, reply = method(self.session_id, rpc, *params)

                    if result is not True:
                        self.send_rpc_reply(reply, rpc)

                except NotImplementedError:
                    raise ncerror.RPCSvrErrNotImpl(rpc)
            except ncerror.RPCSvrErrBadMsg as msgerr:
                if self.new_framing:
                    self.send_message(msgerr.get_reply_msg())
                else:
                    GlobalModule.EM_LOGGER.warning(
                        "Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                self.send_message(error.get_reply_msg())
            except Exception as exception:
                GlobalModule.EM_LOGGER.debug(traceback.format_exc())
                error = ncerror.RPCSvrException(rpc, exception)
                self.send_message(error.get_reply_msg())
예제 #2
0
파일: server.py 프로젝트: kicoliu/netconf
    def _reader_handle_message(self, msg):
        if not self.session_open:
            return

        msg = msg.replace('\n', '').replace('\r', '').replace('\t', '')

        # Any error with XML encoding here is going to cause a session close
        # Technically we should be able to return malformed message I think.
        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            logger.warning("Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        if self.debug and msg.find('message-id="-1"') == -1:
            logger.debug("%s: Recieved RPC message:\n%s", str(self),
                         str(etree.tounicode(tree, pretty_print=True)))

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get('message-id')
                if self.debug:
                    logger.debug("%s: Received rpc message-id: %s", str(self),
                                 msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(
                    msg, "No valid message-id attribute found")

            try:
                # Get the first child of rpc as the method name
                rpc_method = rpc.getchildren()
                if len(rpc_method) != 1:
                    if self.debug:
                        logger.debug("%s: Bad Msg: msg-id: %s", str(self),
                                     msg_id)
                    raise ncerror.MalformedMessageRPCError(rpc)
                rpc_method = rpc_method[0]

                rpcname = rpc_method.tag.replace(qmap('nc'), "")
                params = rpc_method.getchildren()
                paramslen = len(params)
                lock_target = None

                if self.debug:
                    logger.debug("%s: RPC: %s: paramslen: %s", str(self),
                                 rpcname, str(paramslen))

                if rpcname == "close-session":
                    # XXX should be RPC-unlocking if need be
                    if self.debug:
                        logger.debug("%s: Received close-session msg-id: %s",
                                     str(self), msg_id)
                    self._send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "kill-session":
                    # XXX we are supposed to cleanly abort anything underway
                    if self.debug:
                        logger.debug("%s: Received kill-session msg-id: %s",
                                     str(self), msg_id)
                    self._send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "get":
                    # Validate GET parameters

                    if paramslen > 1:
                        # XXX need to specify all elements not known
                        raise ncerror.MalformedMessageRPCError(rpc)
                    if params and not util.filter_tag_match(
                            params[0], "nc:filter"):
                        raise ncerror.UnknownElementProtoError(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":
                    # Validate GET-CONFIG parameters

                    if paramslen > 2:
                        # XXX Should be ncerror.UnknownElementProtoError? for each?
                        raise ncerror.MalformedMessageRPCError(rpc)
                    source_param = rpc_method.find("nc:source",
                                                   namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.MissingElementProtoError(
                            rpc, util.qname("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter",
                                                       namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[
                                0] if params[0] != source_param else params[1]
                            raise ncerror.UnknownElementProtoError(
                                rpc, unknown_elm)
                    params = [source_param, filter_param]
                elif rpcname == "lock" or rpcname == "unlock":
                    if paramslen != 1:
                        raise ncerror.MalformedMessageRPCError(rpc)
                    target_param = rpc_method.find("nc:target",
                                                   namespaces=NSMAP)
                    if target_param is None:
                        raise ncerror.MissingElementProtoError(
                            rpc, util.qname("nc:target"))
                    elms = target_param.getchildren()
                    if len(elms) != 1:
                        raise ncerror.MissingElementProtoError(
                            rpc, util.qname("nc:target"))
                    lock_target = elms[0].tag.replace(qmap('nc'), "")
                    if lock_target not in ["running", "candidate"]:
                        raise ncerror.BadElementProtoError(
                            rpc, util.qname("nc:target"))
                    params = [lock_target]

                    if rpcname == "lock":
                        logger.error("%s: Lock Target: %s", str(self),
                                     lock_target)
                        # Try and obtain the lock.
                        locksid = self.server.lock_target(self, lock_target)
                        if locksid:
                            raise ncerror.LockDeniedProtoError(rpc, locksid)
                    elif rpcname == "unlock":
                        logger.error("%s: Unlock Target: %s", str(self),
                                     lock_target)
                        # Make sure we have the lock.
                        locksid = self.server.is_target_locked(lock_target)
                        if locksid != self.session_id:
                            # An odd error to return
                            raise ncerror.LockDeniedProtoError(rpc, locksid)

                #------------------
                # Call the method.
                #------------------

                try:
                    # Handle any namespaces or prefixes in the tag, other than
                    # "nc" which was removed above. Of course, this does not handle
                    # namespace collisions, but that seems reasonable for now.
                    rpcname = rpcname.rpartition("}")[-1]
                    method_name = "rpc_" + rpcname.replace('-', '_')
                    method = getattr(self.methods, method_name, None)

                    if method is None:
                        if rpcname in self.handled_rpc_methods:
                            self._send_rpc_reply(etree.Element("ok"), rpc)
                            method = None
                        else:
                            method = self._rpc_not_implemented

                    if method is not None:
                        if self.debug:
                            logger.debug("%s: Calling method: %s", str(self),
                                         method_name)
                        reply = method(self, rpc, *params)
                        self._send_rpc_reply(reply, rpc)
                except Exception:
                    # If user raised error unlock if this was lock
                    if rpcname == "lock" and lock_target:
                        self.server.unlock_target(self, lock_target)
                    raise

                # If this was unlock and we're OK, release the lock.
                if rpcname == "unlock":
                    self.server.unlock_target(self, lock_target)

            except ncerror.MalformedMessageRPCError as msgerr:
                if self.new_framing:
                    if self.debug:
                        logger.debug("%s: MalformedMessageRPCError: %s",
                                     str(self), str(msgerr))
                    self.send_message(msgerr.get_reply_msg())
                else:
                    # If we are 1.0 we have to simply close the connection
                    # as we are not allowed to send this error
                    logger.warning(
                        "Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                if self.debug:
                    logger.debug("%s: RPCServerError: %s", str(self),
                                 str(error))
                self._send_rpc_reply_error(error)
            except EOFError:
                if self.debug:
                    logger.debug("%s: Got EOF in reader_handle_message",
                                 str(self))
                error = ncerror.RPCSvrException(rpc, EOFError("EOF"))
                self._send_rpc_reply_error(error)
            except Exception as exception:
                if self.debug:
                    logger.debug(
                        "%s: Got unexpected exception in reader_handle_message: %s",
                        str(self), str(exception))
                error = ncerror.RPCSvrException(rpc, exception)
                self._send_rpc_reply_error(error)
예제 #3
0
파일: server.py 프로젝트: bonald/vim_cfg
    def reader_handle_message(self, msg):
        """Handle a message, lock is already held"""
        print('stpe 1')
        print(msg)
        if not self.session_open:
            return

        # Any error with XML encoding here is going to cause a session close
        # Technically we should be able to return malformed message I think.
        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            print('step 1.5')
            print(etree.tostring(tree, pretty_print=True))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            logger.warning("Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        print('step 2')
        print(rpcs)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get('message-id')
                print('step 3')
                print(msg_id)
                if self.debug:
                    logger.debug("%s: Received rpc message-id: %s", str(self),
                                 msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(
                    msg, "No valid message-id attribute found")

            try:
                # Get the first child of rpc as the method name
                rpc_method = rpc.getchildren()
                print('step 4')
                print(rpc_method)

                if len(rpc_method) != 1:
                    if self.debug:
                        logger.debug("%s: Bad Msg: msg-id: %s", str(self),
                                     msg_id)
                    raise ncerror.RPCSvrErrBadMsg(rpc)
                rpc_method = rpc_method[0]
                print('step 5')
                print(rpc_method)

                rpcname = rpc_method.tag.replace(qmap('nc'), "")
                print('stpe 6')
                print(rpcname)
                params = rpc_method.getchildren()
                print('stpe 7')
                print(params)
                paramslen = len(params)

                if self.debug:
                    logger.debug("%s: RPC: %s: paramslen: %s", str(self),
                                 rpcname, str(paramslen))

                if rpcname == "close-session":
                    # XXX should be RPC-unlocking if need be
                    if self.debug:
                        logger.debug("%s: Received close-session msg-id: %s",
                                     str(self), msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "kill-session":
                    # XXX we are supposed to cleanly abort anything underway
                    if self.debug:
                        logger.debug("%s: Received kill-session msg-id: %s",
                                     str(self), msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "get":
                    # Validate GET parameters

                    if paramslen > 1:
                        # XXX need to specify all elements not known
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    if params and not util.filter_tag_match(
                            params[0], "nc:filter"):
                        raise ncerror.RPCSvrUnknownElement(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":
                    # Validate GET-CONFIG parameters

                    # XXX verify that the source parameter is present
                    if paramslen > 2:
                        # XXX need to specify all elements not known
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    source_param = rpc_method.find("nc:source",
                                                   namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.RPCSvrMissingElement(
                            rpc, util.elm("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter",
                                                       namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[
                                0] if params[0] != source_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(
                                rpc, unknown_elm)
                    params = [source_param, filter_param]

                #------------------
                # Call the method.
                #------------------

                try:
                    # Handle any namespaces or prefixes in the tag, other than
                    # "nc" which was removed above. Of course, this does not handle
                    # namespace collisions, but that seems reasonable for now.
                    rpcname = rpcname.rpartition("}")[-1]
                    print('step 8')
                    print(rpcname)
                    method_name = "rpc_" + rpcname.replace('-', '_')
                    method = getattr(self.methods, method_name,
                                     self._rpc_not_implemented)
                    if self.debug:
                        logger.debug("%s: Calling method: %s", str(self),
                                     method_name)
                    reply = method(self, rpc, *params)
                    print('stpe 9')
                    print(reply)
                    self.send_rpc_reply(reply, rpc)
                except NotImplementedError:
                    raise ncerror.RPCSvrErrNotImpl(rpc)
            except ncerror.RPCSvrErrBadMsg as msgerr:
                if self.new_framing:
                    if self.debug:
                        logger.debug("%s: RPCSvrErrBadMsg: %s", str(self),
                                     str(msgerr))
                    self.send_message(msgerr.get_reply_msg())
                else:
                    # If we are 1.0 we have to simply close the connection
                    # as we are not allowed to send this error
                    logger.warning(
                        "Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                if self.debug:
                    logger.debug("%s: RPCServerError: %s", str(self),
                                 str(error))
                self.send_message(error.get_reply_msg())
            except EOFError:
                if self.debug:
                    logger.debug("%s: Got EOF in reader_handle_message",
                                 str(self))
                error = ncerror.RPCSvrException(rpc, EOFError("EOF"))
                self.send_message(error.get_reply_msg())
            except EOFError:
                if self.debug:
                    logger.debug("Got EOF in reader_handle_message")
            except Exception as exception:
                if self.debug:
                    logger.debug(
                        "%s: Got unexpected exception in reader_handle_message: %s",
                        str(self), str(exception))
                error = ncerror.RPCSvrException(rpc, exception)
                self.send_message(error.get_reply_msg())