[7/8] QMP: Enable feature negotiation support

Submitted by Luiz Capitulino on Jan. 28, 2010, 1:42 p.m.

Details

Message ID 1264686180-29845-8-git-send-email-lcapitulino@redhat.com
State New
Headers show

Commit Message

Luiz Capitulino Jan. 28, 2010, 1:42 p.m.
It's done by starting QMP in handshake mode, where (apart from a
few exceptions) only commands to query/enable/disable protocol
capabilities are allowed. Asynchronous messages are also disabled
in this mode.

Clients can change to the operational mode (where capabilities'
changes take effect and most commands are allowed) at any time.

When the issued command is not allowed to be executed on the
running mode, QMP will return the CommandNotFound error, as
suggested by Markus.

All these changes should have no effect in the user Monitor.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 monitor.c |   41 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 40 insertions(+), 1 deletions(-)

Patch hide | download patch | download mbox

diff --git a/monitor.c b/monitor.c
index 5851b6d..28a8c32 100644
--- a/monitor.c
+++ b/monitor.c
@@ -403,10 +403,12 @@  void monitor_protocol_event(MonitorEvent event, QObject *data)
     }
 
     QLIST_FOREACH(mon, &mon_list, entry) {
-        if (monitor_ctrl_mode(mon)) {
+        if (monitor_ctrl_mode(mon) &&
+            mon->mc->mode == QMODE_OPERATIONAL) {
             monitor_json_emitter(mon, QOBJECT(qmp));
         }
     }
+
     QDECREF(qmp);
 }
 
@@ -4242,12 +4244,34 @@  static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args)
     return err;
 }
 
+static int qmp_invalid_mode(const Monitor *mon, unsigned int cmd_flags)
+{
+    switch (mon->mc->mode) {
+        case QMODE_OPERATIONAL:
+            if (cmd_flags & HANDLER_HANDSHAKE_ONLY) {
+                return 1;
+            }
+            break;
+        case QMODE_HANDSHAKE:
+            if (!((cmd_flags & HANDLER_HANDSHAKE) ||
+                (cmd_flags & HANDLER_HANDSHAKE_ONLY))) {
+                return 1;
+            }
+            break;
+        default:
+            abort();
+    }
+
+    return 0;
+}
+
 static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
 {
     int err;
     QObject *obj;
     QDict *input, *args;
     const mon_cmd_t *cmd;
+    unsigned int cmd_flags;
     Monitor *mon = cur_mon;
     const char *cmd_name, *info_item;
 
@@ -4289,6 +4313,15 @@  static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
         qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
         goto err_input;
     } else if (strstart(cmd_name, "query-", &info_item)) {
+        /* check if it exists and get its flags */
+        cmd = monitor_find_info_command(info_item);
+        if (!cmd) {
+            qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+            goto err_input;
+        }
+        cmd_flags = cmd->flags;
+
+        /* setup 'info' to call it */
         cmd = monitor_find_command("info");
         qdict_put_obj(input, "arguments",
                       qobject_from_jsonf("{ 'item': %s }", info_item));
@@ -4298,6 +4331,12 @@  static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
             qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
             goto err_input;
         }
+        cmd_flags = cmd->flags;
+    }
+
+    if (qmp_invalid_mode(mon, cmd_flags)) {
+        qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+        goto err_input;
     }
 
     obj = qdict_get(input, "arguments");