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())
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)
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())