All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marc-André Lureau" <mlureau@redhat.com>
To: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org, eblake@redhat.com, armbru@redhat.com
Subject: Re: [Qemu-devel] [PATCH v5 17/20] monitor: use qmp_dispatch()
Date: Wed, 17 Aug 2016 13:04:40 -0400 (EDT)	[thread overview]
Message-ID: <2142569659.532979.1471453480950.JavaMail.zimbra@redhat.com> (raw)
In-Reply-To: <20160817165757.23486-18-marcandre.lureau@redhat.com>

Hi

----- Original Message -----
> Replace the old manual dispatch and validation code by the generic one
> provided by qapi common code.
> 
> Note that it is now possible to call the following commands that used to
> be disabled by compile-time conditionals:
> - dump-skeys
> - query-spice
> - rtc-reset-reinjection
> - query-gic-capabilities
> 
> Their fallback functions return an appropriate "feature disabled" error.

This is no longer valid, I dropped that comment.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  monitor.c    | 326
>  +++++++----------------------------------------------------
>  trace-events |   1 -
>  2 files changed, 34 insertions(+), 293 deletions(-)
> 
> diff --git a/monitor.c b/monitor.c
> index f07fc31..81926c7 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -166,7 +166,6 @@ struct MonFdset {
>  };
>  
>  typedef struct {
> -    QObject *id;
>      JSONMessageParser parser;
>      /*
>       * When a client connects, we're in capabilities negotiation mode.
> @@ -229,8 +228,6 @@ static int mon_refcount;
>  static mon_cmd_t mon_cmds[];
>  static mon_cmd_t info_cmds[];
>  
> -static const mon_cmd_t qmp_cmds[];
> -
>  Monitor *cur_mon;
>  
>  static QEMUClockType event_clock_type = QEMU_CLOCK_REALTIME;
> @@ -401,49 +398,6 @@ static void monitor_json_emitter(Monitor *mon, const
> QObject *data)
>      QDECREF(json);
>  }
>  
> -static QDict *build_qmp_error_dict(Error *err)
> -{
> -    QObject *obj;
> -
> -    obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
> -                             QapiErrorClass_lookup[error_get_class(err)],
> -                             error_get_pretty(err));
> -
> -    return qobject_to_qdict(obj);
> -}
> -
> -static void monitor_protocol_emitter(Monitor *mon, QObject *data,
> -                                     Error *err)
> -{
> -    QDict *qmp;
> -
> -    trace_monitor_protocol_emitter(mon);
> -
> -    if (!err) {
> -        /* success response */
> -        qmp = qdict_new();
> -        if (data) {
> -            qobject_incref(data);
> -            qdict_put_obj(qmp, "return", data);
> -        } else {
> -            /* return an empty QDict by default */
> -            qdict_put(qmp, "return", qdict_new());
> -        }
> -    } else {
> -        /* error response */
> -        qmp = build_qmp_error_dict(err);
> -    }
> -
> -    if (mon->qmp.id) {
> -        qdict_put_obj(qmp, "id", mon->qmp.id);
> -        mon->qmp.id = NULL;
> -    }
> -
> -    monitor_json_emitter(mon, QOBJECT(qmp));
> -    QDECREF(qmp);
> -}
> -
> -
>  static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
>      /* Limit guest-triggerable events to 1 per second */
>      [QAPI_EVENT_RTC_CHANGE]        = { 1000 * SCALE_MS },
> @@ -2180,11 +2134,6 @@ static mon_cmd_t mon_cmds[] = {
>      { NULL, NULL, },
>  };
>  
> -static const mon_cmd_t qmp_cmds[] = {
> -#include "qmp-commands-old.h"
> -    { /* NULL */ },
> -};
> -
>  /*******************************************************************/
>  
>  static const char *pch;
> @@ -2535,11 +2484,6 @@ static const mon_cmd_t *search_dispatch_table(const
> mon_cmd_t *disp_table,
>      return NULL;
>  }
>  
> -static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
> -{
> -    return search_dispatch_table(qmp_cmds, cmdname);
> -}
> -
>  /*
>   * Parse command name from @cmdp according to command table @table.
>   * If blank, return NULL.
> @@ -3690,199 +3634,6 @@ static bool invalid_qmp_mode(const Monitor *mon,
> const char *cmd,
>      return false;
>  }
>  
> -/*
> - * Argument validation rules:
> - *
> - * 1. The argument must exist in cmd_args qdict
> - * 2. The argument type must be the expected one
> - *
> - * Special case: If the argument doesn't exist in cmd_args and
> - *               the QMP_ACCEPT_UNKNOWNS flag is set, then the
> - *               checking is skipped for it.
> - */
> -static void check_client_args_type(const QDict *client_args,
> -                                   const QDict *cmd_args, int flags,
> -                                   Error **errp)
> -{
> -    const QDictEntry *ent;
> -
> -    for (ent = qdict_first(client_args); ent;ent =
> qdict_next(client_args,ent)){
> -        QObject *obj;
> -        QString *arg_type;
> -        const QObject *client_arg = qdict_entry_value(ent);
> -        const char *client_arg_name = qdict_entry_key(ent);
> -
> -        obj = qdict_get(cmd_args, client_arg_name);
> -        if (!obj) {
> -            if (flags & QMP_ACCEPT_UNKNOWNS) {
> -                /* handler accepts unknowns */
> -                continue;
> -            }
> -            /* client arg doesn't exist */
> -            error_setg(errp, QERR_INVALID_PARAMETER, client_arg_name);
> -            return;
> -        }
> -
> -        arg_type = qobject_to_qstring(obj);
> -        assert(arg_type != NULL);
> -
> -        /* check if argument's type is correct */
> -        switch (qstring_get_str(arg_type)[0]) {
> -        case 'F':
> -        case 'B':
> -        case 's':
> -            if (qobject_type(client_arg) != QTYPE_QSTRING) {
> -                error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> -                           client_arg_name, "string");
> -                return;
> -            }
> -        break;
> -        case 'i':
> -        case 'l':
> -        case 'M':
> -        case 'o':
> -            if (qobject_type(client_arg) != QTYPE_QINT) {
> -                error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> -                           client_arg_name, "int");
> -                return;
> -            }
> -            break;
> -        case 'T':
> -            if (qobject_type(client_arg) != QTYPE_QINT &&
> -                qobject_type(client_arg) != QTYPE_QFLOAT) {
> -                error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> -                           client_arg_name, "number");
> -                return;
> -            }
> -            break;
> -        case 'b':
> -        case '-':
> -            if (qobject_type(client_arg) != QTYPE_QBOOL) {
> -                error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> -                           client_arg_name, "bool");
> -                return;
> -            }
> -            break;
> -        case 'O':
> -            assert(flags & QMP_ACCEPT_UNKNOWNS);
> -            break;
> -        case 'q':
> -            /* Any QObject can be passed.  */
> -            break;
> -        case '/':
> -        case '.':
> -            /*
> -             * These types are not supported by QMP and thus are not
> -             * handled here. Fall through.
> -             */
> -        default:
> -            abort();
> -        }
> -    }
> -}
> -
> -/*
> - * - Check if the client has passed all mandatory args
> - * - Set special flags for argument validation
> - */
> -static void check_mandatory_args(const QDict *cmd_args,
> -                                 const QDict *client_args, int *flags,
> -                                 Error **errp)
> -{
> -    const QDictEntry *ent;
> -
> -    for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent))
> {
> -        const char *cmd_arg_name = qdict_entry_key(ent);
> -        QString *type = qobject_to_qstring(qdict_entry_value(ent));
> -        assert(type != NULL);
> -
> -        if (qstring_get_str(type)[0] == 'O') {
> -            assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0);
> -            *flags |= QMP_ACCEPT_UNKNOWNS;
> -        } else if (qstring_get_str(type)[0] != '-' &&
> -                   qstring_get_str(type)[1] != '?' &&
> -                   !qdict_haskey(client_args, cmd_arg_name)) {
> -            error_setg(errp, QERR_MISSING_PARAMETER, cmd_arg_name);
> -            return;
> -        }
> -    }
> -}
> -
> -static QDict *qdict_from_args_type(const char *args_type)
> -{
> -    int i;
> -    QDict *qdict;
> -    QString *key, *type, *cur_qs;
> -
> -    assert(args_type != NULL);
> -
> -    qdict = qdict_new();
> -
> -    if (args_type == NULL || args_type[0] == '\0') {
> -        /* no args, empty qdict */
> -        goto out;
> -    }
> -
> -    key = qstring_new();
> -    type = qstring_new();
> -
> -    cur_qs = key;
> -
> -    for (i = 0;; i++) {
> -        switch (args_type[i]) {
> -            case ',':
> -            case '\0':
> -                qdict_put(qdict, qstring_get_str(key), type);
> -                QDECREF(key);
> -                if (args_type[i] == '\0') {
> -                    goto out;
> -                }
> -                type = qstring_new(); /* qdict has ref */
> -                cur_qs = key = qstring_new();
> -                break;
> -            case ':':
> -                cur_qs = type;
> -                break;
> -            default:
> -                qstring_append_chr(cur_qs, args_type[i]);
> -                break;
> -        }
> -    }
> -
> -out:
> -    return qdict;
> -}
> -
> -/*
> - * Client argument checking rules:
> - *
> - * 1. Client must provide all mandatory arguments
> - * 2. Each argument provided by the client must be expected
> - * 3. Each argument provided by the client must have the type expected
> - *    by the command
> - */
> -static void qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args,
> -                                  Error **errp)
> -{
> -    Error *err = NULL;
> -    int flags;
> -    QDict *cmd_args;
> -
> -    cmd_args = qdict_from_args_type(cmd->args_type);
> -
> -    flags = 0;
> -    check_mandatory_args(cmd_args, client_args, &flags, &err);
> -    if (err) {
> -        goto out;
> -    }
> -
> -    check_client_args_type(client_args, cmd_args, flags, &err);
> -
> -out:
> -    error_propagate(errp, err);
> -    QDECREF(cmd_args);
> -}
> -
>  /*
>   * Input object checking rules
>   *
> @@ -3941,67 +3692,58 @@ static QDict *qmp_check_input_obj(QObject *input_obj,
> Error **errp)
>  
>  static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
>  {
> -    Error *local_err = NULL;
> -    QObject *obj, *data;
> -    QDict *input, *args;
> -    const mon_cmd_t *cmd;
> -    QmpCommand *qcmd;
> +    QObject *req, *rsp = NULL, *id = NULL;
> +    QDict *qdict = NULL;
>      const char *cmd_name;
>      Monitor *mon = cur_mon;
> +    Error *err = NULL;
>  
> -    args = input = NULL;
> -    data = NULL;
> -
> -    obj = json_parser_parse(tokens, NULL);
> -    if (!obj) {
> -        // FIXME: should be triggered in json_parser_parse()
> -        error_setg(&local_err, QERR_JSON_PARSING);
> +    req = json_parser_parse_err(tokens, NULL, &err);
> +    if (err || !req || qobject_type(req) != QTYPE_QDICT) {
> +        if (!err) {
> +            error_setg(&err, QERR_JSON_PARSING);
> +        }
>          goto err_out;
>      }
>  
> -    input = qmp_check_input_obj(obj, &local_err);
> -    if (!input) {
> -        qobject_decref(obj);
> +    qdict = qmp_check_input_obj(req, &err);
> +    if (!qdict) {
>          goto err_out;
>      }
>  
> -    mon->qmp.id = qdict_get(input, "id");
> -    qobject_incref(mon->qmp.id);
> +    id = qdict_get(qdict, "id");
> +    qobject_incref(id);
> +    qdict_del(qdict, "id");
>  
> -    cmd_name = qdict_get_str(input, "execute");
> +    cmd_name = qdict_get_str(qdict, "execute");
>      trace_handle_qmp_command(mon, cmd_name);
> -    cmd = qmp_find_cmd(cmd_name);
> -    qcmd = qmp_find_command(cmd_name);
> -    if (!qcmd || !cmd) {
> -        error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND,
> -                  "The command %s has not been found", cmd_name);
> -        goto err_out;
> -    }
> -    if (invalid_qmp_mode(mon, cmd_name, &local_err)) {
> +
> +    if (invalid_qmp_mode(mon, cmd_name, &err)) {
>          goto err_out;
>      }
>  
> -    obj = qdict_get(input, "arguments");
> -    if (!obj) {
> -        args = qdict_new();
> -    } else {
> -        args = qobject_to_qdict(obj);
> -        QINCREF(args);
> -    }
> +    rsp = qmp_dispatch(req);
>  
> -    qmp_check_client_args(cmd, args, &local_err);
> -    if (local_err) {
> -        goto err_out;
> +err_out:
> +    if (err) {
> +        qdict = qdict_new();
> +        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
> +        error_free(err);
> +        rsp = QOBJECT(qdict);
>      }
>  
> -    qcmd->fn(args, &data, &local_err);
> +    if (rsp) {
> +        if (id) {
> +            qdict_put_obj(qobject_to_qdict(rsp), "id", id);
> +            id = NULL;
> +        }
>  
> -err_out:
> -    monitor_protocol_emitter(mon, data, local_err);
> -    qobject_decref(data);
> -    error_free(local_err);
> -    QDECREF(input);
> -    QDECREF(args);
> +        monitor_json_emitter(mon, rsp);
> +    }
> +
> +    qobject_decref(id);
> +    qobject_decref(rsp);
> +    qobject_decref(req);
>  }
>  
>  static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
> diff --git a/trace-events b/trace-events
> index 616cc52..8d59631 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -98,7 +98,6 @@ qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex
> %p self %p"
>  
>  # monitor.c
>  handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
> -monitor_protocol_emitter(void *mon) "mon %p"
>  monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d
>  data=%p"
>  monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
>  monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate)
>  "event=%d data=%p rate=%" PRId64
> --
> 2.9.0
> 
> 

  reply	other threads:[~2016-08-17 17:04 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-17 16:57 [Qemu-devel] [PATCH v5 00/20] qapi: remove the 'middle' mode Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 01/20] tests: do qmp introspect validation per target Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 02/20] qapi.py: add a simple #ifdef conditional Marc-André Lureau
2016-09-06 12:35   ` Markus Armbruster
2016-09-06 13:17     ` Marc-André Lureau
2016-09-06 15:58       ` Markus Armbruster
2016-09-06 16:44         ` Marc-André Lureau
2016-09-07  8:44           ` Markus Armbruster
2016-09-07 13:40             ` Markus Armbruster
2016-09-07 14:23               ` Marc-André Lureau
2016-09-07 18:49               ` Eric Blake
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 03/20] build-sys: make qemu qapi per-target Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 04/20] build-sys: use config headers to generate qapi Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 05/20] qapi: configure the schema Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 06/20] build-sys: define QEMU_VERSION_{MAJOR, MINOR, MICRO} Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 07/20] qapi-schema: use generated marshaller for 'qmp_capabilities' Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 08/20] qapi-schema: add 'device_add' Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 09/20] monitor: simplify invalid_qmp_mode() Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 10/20] monitor: register gen:false commands manually Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 11/20] qapi: export the marshallers Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 12/20] monitor: use qmp_find_command() (using generated qapi code) Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 13/20] monitor: implement 'qmp_query_commands' without qmp_cmds Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 14/20] monitor: remove mhandler.cmd_new Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 15/20] qapi: remove the "middle" mode Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 16/20] qapi: check invalid arguments on no-args commands Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 17/20] monitor: use qmp_dispatch() Marc-André Lureau
2016-08-17 17:04   ` Marc-André Lureau [this message]
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 18/20] build-sys: remove qmp-commands-old.h Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 19/20] qmp-commands.hx: fix some styling Marc-André Lureau
2016-08-17 16:57 ` [Qemu-devel] [PATCH v5 20/20] Replace qmp-commands.hx by doc/qmp-commands.txt Marc-André Lureau
2016-09-09 12:43   ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2142569659.532979.1471453480950.JavaMail.zimbra@redhat.com \
    --to=mlureau@redhat.com \
    --cc=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.