These are basically a stripped-down, guest-side analogue to what's in qmp_core.c: definitions used by qmp-gen.py-generated marshalling code to handle dispatch and a registration of command->function mappings (minus all the bits related to Qmp sessions/server/events).
As a result of that, there is a little bit of code duplication here. It wouldn't be difficult to make the common bits shareable, but there isn't much. The guest agent will use these interfaces to handle dispatch/execution of requests it gets from the proxy. Signed-off-by: Michael Roth <mdr...@linux.vnet.ibm.com> --- guest-agent-core.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++ guest-agent-core.h | 21 ++++++++ 2 files changed, 164 insertions(+), 0 deletions(-) create mode 100644 guest-agent-core.c create mode 100644 guest-agent-core.h diff --git a/guest-agent-core.c b/guest-agent-core.c new file mode 100644 index 0000000..6c3b031 --- /dev/null +++ b/guest-agent-core.c @@ -0,0 +1,143 @@ +/* + * QEMU Guest Agent core functions + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Adam Litke <agli...@linux.vnet.ibm.com> + * Michael Roth <mdr...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "guest-agent-core.h" + +typedef enum QmpCommandType +{ + QCT_NORMAL, + QCT_ASYNC, +} QmpCommandType; + +typedef struct QmpCommand +{ + const char *name; + QmpCommandType type; + QmpCommandFunc *fn; + QmpAsyncCommandFunc *afn; + QTAILQ_ENTRY(QmpCommand) node; +} QmpCommand; + +static QTAILQ_HEAD(, QmpCommand) qmp_commands = + QTAILQ_HEAD_INITIALIZER(qmp_commands); + +QmpMarshalState *qmp_state_get_mstate(QmpState *sess) +{ + return NULL; +} + +void qga_register_command(const char *name, QmpCommandFunc *fn) +{ + QmpCommand *cmd = qemu_mallocz(sizeof(*cmd)); + + cmd->name = name; + cmd->type = QCT_NORMAL; + cmd->fn = fn; + QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node); +} + +static QmpCommand *qmp_find_command(const char *name) +{ + QmpCommand *i; + + QTAILQ_FOREACH(i, &qmp_commands, node) { + if (strcmp(i->name, name) == 0) { + return i; + } + } + return NULL; +} + +static QObject *qga_dispatch_err(QObject *request, Error **errp) +{ + const char *command; + QDict *args, *dict; + QmpCommand *cmd; + QObject *ret = NULL; + + if (qobject_type(request) != QTYPE_QDICT) { + error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary"); + goto out; + } + + dict = qobject_to_qdict(request); + if (!qdict_haskey(dict, "execute")) { + error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key"); + goto out; + } + + command = qdict_get_str(dict, "execute"); + cmd = qmp_find_command(command); + if (cmd == NULL) { + error_set(errp, QERR_COMMAND_NOT_FOUND, command); + goto out; + } + + if (!qdict_haskey(dict, "arguments")) { + args = qdict_new(); + } else { + args = qdict_get_qdict(dict, "arguments"); + QINCREF(args); + } + + switch (cmd->type) { + case QCT_NORMAL: + cmd->fn(NULL, args, &ret, errp); + if (ret == NULL) { + ret = QOBJECT(qdict_new()); + } + break; + case QCT_ASYNC: { + QmpCommandState *s = qemu_mallocz(sizeof(*s)); + // FIXME save async commands and do something + // smart if disconnect occurs before completion + //s->state = state; + s->tag = NULL; + if (qdict_haskey(dict, "tag")) { + s->tag = qdict_get(dict, "tag"); + qobject_incref(s->tag); + } + cmd->afn(args, errp, s); + ret = NULL; + } + break; + } + + QDECREF(args); + +out: + qobject_decref(request); + + return ret; +} + +QObject *qga_dispatch(QObject *request, Error **errp) +{ + Error *err = NULL; + QObject *ret; + QDict *rsp; + + ret = qga_dispatch_err(request, &err); + + rsp = qdict_new(); + if (err) { + qdict_put_obj(rsp, "error", error_get_qobject(err)); + error_free(err); + } else if (ret) { + qdict_put_obj(rsp, "return", ret); + } else { + QDECREF(rsp); + return NULL; + } + + return QOBJECT(rsp); +} diff --git a/guest-agent-core.h b/guest-agent-core.h new file mode 100644 index 0000000..18126b0 --- /dev/null +++ b/guest-agent-core.h @@ -0,0 +1,21 @@ +/* + * QEMU Guest Agent core declarations + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Adam Litke <agli...@linux.vnet.ibm.com> + * Michael Roth <mdr...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qmp-core.h" +#include "qapi-types-core.h" +#include "qmp-marshal-types-core.h" +#include "qemu-common.h" +#include "qdict.h" + +QObject *qga_dispatch(QObject *obj, Error **errp); +void qga_register_command(const char *name, QmpCommandFunc *fn); +void qga_init_marshal(void); -- 1.7.0.4