[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v6 15/18] monitor: use qmp_dispatch()
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH v6 15/18] monitor: use qmp_dispatch() |
Date: |
Mon, 12 Sep 2016 13:19:10 +0400 |
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.
Signed-off-by: Marc-André Lureau <address@hidden>
---
monitor.c | 326 +++++++----------------------------------------------------
trace-events | 1 -
2 files changed, 34 insertions(+), 293 deletions(-)
diff --git a/monitor.c b/monitor.c
index d5d6e95..8bb8bbf 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 },
@@ -2211,11 +2165,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;
@@ -2566,11 +2515,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.
@@ -3721,199 +3665,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
*
@@ -3972,67 +3723,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.10.0
- [Qemu-devel] [PATCH v6 07/18] qmp: Hack to keep commands configuration-specific, (continued)
- [Qemu-devel] [PATCH v6 07/18] qmp: Hack to keep commands configuration-specific, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 08/18] qapi: export the marshallers, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 10/18] monitor: implement 'qmp_query_commands' without qmp_cmds, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 09/18] monitor: use qmp_find_command() (using generated qapi code), Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 12/18] qapi: remove the "middle" mode, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 11/18] monitor: remove mhandler.cmd_new, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 13/18] qapi: check invalid arguments on no-args commands, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 14/18] tests: add a test to check invalid args, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 16/18] build-sys: remove qmp-commands-old.h, Marc-André Lureau, 2016/09/12
- [Qemu-devel] [PATCH v6 15/18] monitor: use qmp_dispatch(),
Marc-André Lureau <=
[Qemu-devel] [PATCH v6 17/18] qmp-commands.hx: fix some styling, Marc-André Lureau, 2016/09/12
[Qemu-devel] [PATCH v6 18/18] Replace qmp-commands.hx by docs/qmp-commands.txt, Marc-André Lureau, 2016/09/12