#include "qapi/qmp/qjson.h"
#include "qapi/qmp/json-parser.h"
#include "qmp-introspect.h"
+#include "qapi/qmp/dispatch.h"
#include "ecs.h"
#include "hw/virtio/maru_virtio_evdi.h"
struct mon_fd_t {
char *name;
int fd;
- QLIST_ENTRY(mon_fd_t)
- next;
+ QLIST_ENTRY(mon_fd_t) next;
};
typedef struct mon_cmd_t {
const char *args_type;
const char *params;
const char *help;
- union {
- void (*cmd)(Monitor *mon, const QDict *qdict);
- void (*cmd_new)(QDict *params, QObject **ret_data, Error **errp);
- } mhandler;
+ void (*cmd)(Monitor *mon, const QDict *qdict);
/* @sub_table is a list of 2nd level of commands. If it do not exist,
* mhandler should be used. If it exist, sub_table[?].mhandler should be
* used, and mhandler of 1st level plays the role of help function.
void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
} mon_cmd_t;
-/*
-void send_to_client(int fd, const char *data, const int len)
-{
- char c;
- uint8_t outbuf[OUT_BUF_SIZE];
- int outbuf_index = 0;
-
- for (;;) {
- c = *data++;
- if (outbuf_index >= OUT_BUF_SIZE - 1) {
- INFO("string is too long: overflow buffer.");
- return;
- }
-#ifndef _WIN32
- if (c == '\n') {
- outbuf[outbuf_index++] = '\r';
- }
-#endif
- outbuf[outbuf_index++] = c;
- if (c == '\0') {
- break;
- }
- }
- ecs_write(fd, outbuf, outbuf_index);
-}
-*/
-
#define QMP_ACCEPT_UNKNOWNS 1
bool send_monitor_ntf(const char *data, int size)
if (!err) {
/* success response */
- qmp = qdict_new();
if (data) {
qobject_incref(data);
- qdict_put_obj(qmp, "return", data);
+ qmp = qobject_to_qdict(data);
} else {
/* return an empty QDict by default */
+ qmp = qdict_new();
qdict_put(qmp, "return", qdict_new());
}
QDECREF(qmp);
}
-static void ecs_qmp_call_cmd(ECS_Client *clii, Monitor *mon, const char *type,
- const mon_cmd_t *cmd, QDict *params)
-{
- QObject *data = NULL;
- Error *local_err = NULL;
-
- cmd->mhandler.cmd_new(params, &data, &local_err);
- ecs_protocol_emitter(clii, type, data, local_err);
- qobject_decref(data);
-}
-
-static void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
-{
-}
-
-static void qmp_capabilities(QDict *params, QObject **ret_data, Error **errp)
-{
-}
-
-static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
- Error **errp)
-{
- *ret_data = qobject_from_json(qmp_schema_json);
-}
-
-static const mon_cmd_t qmp_cmds[] = {
-#include "qmp-commands-old.h"
- { /* NULL */}, };
-
-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 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) {
- continue;
- }
- error_setg(errp, QERR_INVALID_PARAMETER, client_arg_name);
- return;
- }
-
- arg_type = qobject_to_qstring(obj);
- assert(arg_type != NULL);
-
- 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':
- break;
- case '/':
- case '.':
- default:
- abort();
- }
- }
-}
-
-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') {
- 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();
- cur_qs = key = qstring_new();
- break;
- case ':':
- cur_qs = type;
- break;
- default:
- qstring_append_chr(cur_qs, args_type[i]);
- break;
- }
- }
-
- out: return qdict;
-}
-
-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);
-}
-
static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
{
const QDictEntry *ent;
return input_dict;
}
-static int compare_cmd(const char *name, const char *list)
-{
- const char *p, *pstart;
- int len;
- len = strlen(name);
- p = list;
- for (;;) {
- pstart = p;
- p = strchr(p, '|');
- if (!p) {
- p = pstart + strlen(pstart);
- }
- if ((p - pstart) == len && !memcmp(pstart, name, len)) {
- return 1;
- }
- if (*p == '\0') {
- break;
- }
- p++;
- }
- return 0;
-}
-
-static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
- const char *cmdname)
-{
- const mon_cmd_t *cmd;
-
- for (cmd = disp_table; cmd->name != NULL; cmd++) {
- if (compare_cmd(cmdname, cmd->name)) {
- return cmd;
- }
- }
-
- return NULL;
-}
-
-static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
-{
- return search_dispatch_table(qmp_cmds, cmdname);
-}
-
void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens,
void *opaque)
{
- Error *local_err = NULL;
- QObject *obj;
- QDict *input, *args;
- const mon_cmd_t *cmd;
- const char *cmd_name;
- const char *type_name;
- Monitor *mon = cur_mon;
+ QObject *req, *rsp = NULL, *id = NULL;
+ QDict *qdict = NULL;
ECS_Client *clii = opaque;
+ Error *err = NULL;
+ char* type = NULL;
- args = input = 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;
}
- cmd_name = qdict_get_str(input, "execute");
-#if 0
- trace_handle_qmp_command(mon, cmd_name);
-#endif
+ id = qdict_get(qdict, "id");
+ qobject_incref(id);
+ qdict_del(qdict, "id");
- cmd = qmp_find_cmd(cmd_name);
- if (!cmd) {
- error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND,
- "The command %s has not been found", cmd_name);
- goto err_out;
+ if (qdict_haskey(qdict, "type")) {
+ type = g_strdup(qdict_get_str(qdict, "type"));
+ qdict_del(qdict, "type");
}
- type_name = qdict_get_str(qobject_to_qdict(obj), COMMANDS_TYPE);
+ req = QOBJECT(qdict);
- 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;
- }
+ ecs_protocol_emitter(clii, (const char*)type, rsp, err);
- ecs_qmp_call_cmd(clii, mon, type_name, cmd, args);
+ g_free(type);
+err_out:
+ if (err) {
+ qdict = qdict_new();
+ qdict_put_obj(qdict, "error", qmp_build_error_object(err));
+ error_free(err);
+ rsp = QOBJECT(qdict);
+ }
- goto out;
+ if (rsp) {
+ if (id) {
+ qdict_put_obj(qobject_to_qdict(rsp), "id", id);
+ id = NULL;
+ }
+ }
-err_out:
- ecs_protocol_emitter(clii, NULL, NULL, local_err);
-out:
- error_free(local_err);
- QDECREF(input);
- QDECREF(args);
+ qobject_decref(id);
+ qobject_decref(rsp);
+ qobject_decref(req);
}
bool msgproc_monitor_req(ECS_Client *ccli, ECS__MonitorReq *msg)
ecs_json_message_parser_feed(&(ccli->parser), (const char *) msg->command, strlen(msg->command));
return true;
}
+