2 * Emulator Control Server
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * Jinhyung choi <jinhyung2.choi@samsung.com>
8 * MunKyu Im <munkyu.im@samsung.com>
9 * Daiyoung Kim <daiyoung777.kim@samsung.com>
10 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "qemu-common.h"
32 #include "qemu/queue.h"
33 #include "qemu/sockets.h"
34 #include "qemu/option.h"
36 #include <monitor/monitor.h>
37 #include "qmp-commands.h"
38 #include "qapi/qmp/qjson.h"
39 #include "qapi/qmp/json-parser.h"
42 #include "hw/maru_virtio_evdi.h"
43 #include "hw/maru_virtio_sensor.h"
44 #include "hw/maru_virtio_nfc.h"
47 MULTI_DEBUG_CHANNEL(qemu, ecs);
49 typedef struct mon_fd_t mon_fd_t;
57 typedef struct mon_cmd_t {
59 const char *args_type;
62 void (*user_print)(Monitor *mon, const QObject *data);
64 void (*info)(Monitor *mon);
65 void (*cmd)(Monitor *mon, const QDict *qdict);
66 int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
67 int (*cmd_async)(Monitor *mon, const QDict *params,
68 MonitorCompletion *cb, void *opaque);
74 void send_to_client(int fd, const char* data, const int len)
77 uint8_t outbuf[OUT_BUF_SIZE];
82 if (outbuf_index >= OUT_BUF_SIZE - 1) {
83 INFO("string is too long: overflow buffer.");
88 outbuf[outbuf_index++] = '\r';
91 outbuf[outbuf_index++] = c;
96 ecs_write(fd, outbuf, outbuf_index);
100 #define QMP_ACCEPT_UNKNOWNS 1
102 bool send_monitor_ntf(const char* data, int size)
104 ECS__Master master = ECS__MASTER__INIT;
105 ECS__MonitorNtf ntf = ECS__MONITOR_NTF__INIT;
107 TRACE("data size : %d, data : %s", size, data);
109 ntf.command = (char*) g_malloc(size + 1);
110 memcpy(ntf.command, data, size);
112 master.type = ECS__MASTER__TYPE__MONITOR_NTF;
113 master.monitor_ntf = &ntf;
115 send_to_ecp(&master);
123 static void ecs_monitor_flush(ECS_Client *clii, Monitor *mon) {
126 if (clii && 0 < clii->client_fd && mon && mon->outbuf_index != 0) {
127 //ret = ecs_write(clii->client_fd, mon->outbuf, mon->outbuf_index);
128 ret = send_monitor_ntf((char*)mon->outbuf, mon->outbuf_index);
129 mon->outbuf_index = 0;
131 ecs_client_close(clii);
136 static void ecs_monitor_puts(ECS_Client *clii, Monitor *mon, const char *str) {
149 mon->outbuf[mon->outbuf_index++] = '\r';
151 mon->outbuf[mon->outbuf_index++] = c;
152 if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1) || c == '\n')
153 ecs_monitor_flush(clii, mon);
157 static inline int monitor_has_error(const Monitor *mon) {
158 return mon->error != NULL;
161 static QDict *build_qmp_error_dict(const QError *err) {
162 QObject *obj = qobject_from_jsonf(
163 "{ 'error': { 'class': %s, 'desc': %p } }",
164 ErrorClass_lookup[err->err_class], qerror_human(err));
166 return qobject_to_qdict(obj);
169 static void ecs_json_emitter(ECS_Client *clii, const QObject *data) {
172 json = qobject_to_json(data);
174 assert(json != NULL);
176 qstring_append_chr(json, '\n');
177 ecs_monitor_puts(clii, clii->cs->mon, qstring_get_str(json));
182 static void ecs_protocol_emitter(ECS_Client *clii, const char* type,
187 TRACE("ecs_protocol_emitter called.");
188 //trace_monitor_protocol_emitter(clii->cs->mon);
190 if (!monitor_has_error(clii->cs->mon)) {
191 /* success response */
194 qobject_incref(data);
195 qdict_put_obj(qmp, "return", data);
197 /* return an empty QDict by default */
198 qdict_put(qmp, "return", qdict_new());
202 obj = qobject_from_jsonf("%s", "unknown");
204 obj = qobject_from_jsonf("%s", type);
206 qdict_put_obj(qmp, "type", obj);
210 qmp = build_qmp_error_dict(clii->cs->mon->error);
211 QDECREF(clii->cs->mon->error);
212 clii->cs->mon->error = NULL;
215 ecs_json_emitter(clii, QOBJECT(qmp));
219 static void qmp_monitor_complete(void *opaque, QObject *ret_data) {
220 // ecs_protocol_emitter(opaque, ret_data);
223 static int ecs_qmp_async_cmd_handler(ECS_Client *clii, const mon_cmd_t *cmd,
224 const QDict *params) {
225 return cmd->mhandler.cmd_async(clii->cs->mon, params, qmp_monitor_complete,
229 static void ecs_qmp_call_cmd(ECS_Client *clii, Monitor *mon, const char* type,
230 const mon_cmd_t *cmd, const QDict *params) {
232 QObject *data = NULL;
234 ret = cmd->mhandler.cmd_new(mon, params, &data);
235 if (ret && !monitor_has_error(mon)) {
236 qerror_report(QERR_UNDEFINED_ERROR);
238 ecs_protocol_emitter(clii, type, data);
239 qobject_decref(data);
242 static inline bool handler_is_async(const mon_cmd_t *cmd) {
243 return cmd->flags & MONITOR_CMD_ASYNC;
246 static void monitor_user_noop(Monitor *mon, const QObject *data) {
249 static int client_migrate_info(Monitor *mon, const QDict *qdict,
250 MonitorCompletion cb, void *opaque) {
254 static int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) {
258 static int do_qmp_capabilities(Monitor *mon, const QDict *params,
259 QObject **ret_data) {
263 static const mon_cmd_t qmp_cmds[] = {
264 #include "qmp-commands-old.h"
267 static int check_mandatory_args(const QDict *cmd_args, const QDict *client_args,
269 const QDictEntry *ent;
271 for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent)) {
272 const char *cmd_arg_name = qdict_entry_key(ent);
273 QString *type = qobject_to_qstring(qdict_entry_value(ent));
274 assert(type != NULL);
276 if (qstring_get_str(type)[0] == 'O') {
277 assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0);
278 *flags |= QMP_ACCEPT_UNKNOWNS;
279 } else if (qstring_get_str(type)[0] != '-'
280 && qstring_get_str(type)[1] != '?'
281 && !qdict_haskey(client_args, cmd_arg_name)) {
282 qerror_report(QERR_MISSING_PARAMETER, cmd_arg_name);
290 static int check_client_args_type(const QDict *client_args,
291 const QDict *cmd_args, int flags) {
292 const QDictEntry *ent;
294 for (ent = qdict_first(client_args); ent;
295 ent = qdict_next(client_args, ent)) {
298 const QObject *client_arg = qdict_entry_value(ent);
299 const char *client_arg_name = qdict_entry_key(ent);
301 obj = qdict_get(cmd_args, client_arg_name);
303 if (flags & QMP_ACCEPT_UNKNOWNS) {
306 qerror_report(QERR_INVALID_PARAMETER, client_arg_name);
310 arg_type = qobject_to_qstring(obj);
311 assert(arg_type != NULL);
313 switch (qstring_get_str(arg_type)[0]) {
317 if (qobject_type(client_arg) != QTYPE_QSTRING) {
318 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
327 if (qobject_type(client_arg) != QTYPE_QINT) {
328 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
334 if (qobject_type(client_arg) != QTYPE_QINT
335 && qobject_type(client_arg) != QTYPE_QFLOAT) {
336 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
343 if (qobject_type(client_arg) != QTYPE_QBOOL) {
344 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
350 assert(flags & QMP_ACCEPT_UNKNOWNS);
364 static QDict *qdict_from_args_type(const char *args_type) {
367 QString *key, *type, *cur_qs;
369 assert(args_type != NULL);
373 if (args_type == NULL || args_type[0] == '\0') {
378 type = qstring_new();
383 switch (args_type[i]) {
386 qdict_put(qdict, qstring_get_str(key), type);
388 if (args_type[i] == '\0') {
391 type = qstring_new();
392 cur_qs = key = qstring_new();
398 qstring_append_chr(cur_qs, args_type[i]);
406 static int qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args) {
410 cmd_args = qdict_from_args_type(cmd->args_type);
413 err = check_mandatory_args(cmd_args, client_args, &flags);
418 err = check_client_args_type(client_args, cmd_args, flags);
425 static QDict *qmp_check_input_obj(QObject *input_obj) {
426 const QDictEntry *ent;
427 int has_exec_key = 0;
430 if (qobject_type(input_obj) != QTYPE_QDICT) {
431 qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
435 input_dict = qobject_to_qdict(input_obj);
437 for (ent = qdict_first(input_dict); ent;
438 ent = qdict_next(input_dict, ent)) {
439 const char *arg_name = qdict_entry_key(ent);
440 const QObject *arg_obj = qdict_entry_value(ent);
442 if (!strcmp(arg_name, "execute")) {
443 if (qobject_type(arg_obj) != QTYPE_QSTRING) {
444 qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
449 } else if (!strcmp(arg_name, "arguments")) {
450 if (qobject_type(arg_obj) != QTYPE_QDICT) {
451 qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "arguments",
455 } else if (!strcmp(arg_name, "id")) {
456 } else if (!strcmp(arg_name, "type")) {
458 qerror_report(QERR_QMP_EXTRA_MEMBER, arg_name);
464 qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
471 static int compare_cmd(const char *name, const char *list) {
472 const char *p, *pstart;
480 p = pstart + strlen(pstart);
481 if ((p - pstart) == len && !memcmp(pstart, name, len))
490 static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
491 const char *cmdname) {
492 const mon_cmd_t *cmd;
494 for (cmd = disp_table; cmd->name != NULL; cmd++) {
495 if (compare_cmd(cmdname, cmd->name)) {
503 static const mon_cmd_t *qmp_find_cmd(const char *cmdname) {
504 return search_dispatch_table(qmp_cmds, cmdname);
507 void handle_qmp_command(JSONMessageParser *parser, QList *tokens,
512 const mon_cmd_t *cmd;
513 const char *cmd_name;
514 const char *type_name;
515 Monitor *mon = cur_mon;
516 ECS_Client *clii = opaque;
520 obj = json_parser_parse(tokens, NULL);
522 // FIXME: should be triggered in json_parser_parse()
523 qerror_report(QERR_JSON_PARSING);
527 input = qmp_check_input_obj(obj);
533 cmd_name = qdict_get_str(input, "execute");
534 //trace_handle_qmp_command(mon, cmd_name);
536 cmd = qmp_find_cmd(cmd_name);
538 qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
542 type_name = qdict_get_str(qobject_to_qdict(obj), COMMANDS_TYPE);
544 obj = qdict_get(input, "arguments");
548 args = qobject_to_qdict(obj);
552 err = qmp_check_client_args(cmd, args);
557 if (handler_is_async(cmd)) {
558 err = ecs_qmp_async_cmd_handler(clii, cmd, args);
560 /* emit the error response */
564 ecs_qmp_call_cmd(clii, mon, type_name, cmd, args);
570 ecs_protocol_emitter(clii, NULL, NULL);
576 bool msgproc_monitor_req(ECS_Client *ccli, ECS__MonitorReq* msg)
578 TRACE(">> monitor req: data = %s", msg->command);
579 ecs_json_message_parser_feed(&(ccli->parser), (const char *) msg->command, strlen(msg->command));