3f935366f80425e5d4e88868d0335c6c1941afc0
[sdk/emulator/qemu.git] / tizen / src / ecs / ecs_mon.c
1 /*
2  * Emulator Control Server
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
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>
11  *
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.
16  *
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.
21  *
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.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include "qemu-common.h"
32 #include "qemu/queue.h"
33 #include "qemu/sockets.h"
34 #include "qemu/option.h"
35
36 #include <monitor/monitor.h>
37 #include "qmp-commands.h"
38 #include "qapi/qmp/qjson.h"
39 #include "qapi/qmp/json-parser.h"
40
41 #include "ecs.h"
42 #include "hw/maru_virtio_evdi.h"
43 #include "hw/maru_virtio_sensor.h"
44 #include "hw/maru_virtio_nfc.h"
45
46 #include "debug_ch.h"
47 MULTI_DEBUG_CHANNEL(qemu, ecs);
48
49 typedef struct mon_fd_t mon_fd_t;
50 struct mon_fd_t {
51     char *name;
52     int fd;
53     QLIST_ENTRY(mon_fd_t)
54     next;
55 };
56
57 typedef struct mon_cmd_t {
58     const char *name;
59     const char *args_type;
60     const char *params;
61     const char *help;
62     void (*user_print)(Monitor *mon, const QObject *data);
63     union {
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);
69     } mhandler;
70     int flags;
71 } mon_cmd_t;
72
73 /*
74 void send_to_client(int fd, const char* data, const int len)
75 {
76     char c;
77     uint8_t outbuf[OUT_BUF_SIZE];
78     int outbuf_index = 0;
79
80     for (;;) {
81         c = *data++;
82         if (outbuf_index >= OUT_BUF_SIZE - 1) {
83             INFO("string is too long: overflow buffer.");
84             return;
85         }
86 #ifndef _WIN32
87         if (c == '\n') {
88             outbuf[outbuf_index++] = '\r';
89         }
90 #endif
91         outbuf[outbuf_index++] = c;
92         if (c == '\0') {
93             break;
94         }
95     }
96     ecs_write(fd, outbuf, outbuf_index);
97 }
98 */
99
100 #define QMP_ACCEPT_UNKNOWNS 1
101
102 bool send_monitor_ntf(const char* data, int size)
103 {
104     ECS__Master master = ECS__MASTER__INIT;
105     ECS__MonitorNtf ntf = ECS__MONITOR_NTF__INIT;
106
107     TRACE("data size : %d, data : %s", size, data);
108
109     ntf.command = (char*) g_malloc(size + 1);
110     memcpy(ntf.command, data, size);
111
112     master.type = ECS__MASTER__TYPE__MONITOR_NTF;
113     master.monitor_ntf = &ntf;
114
115     send_to_ecp(&master);
116
117     if (ntf.command)
118         g_free(ntf.command);
119
120     return true;
121 }
122
123 static void ecs_monitor_flush(ECS_Client *clii, Monitor *mon) {
124     int ret;
125
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;
130         if (ret < -1) {
131             ecs_client_close(clii);
132         }
133     }
134 }
135
136 static void ecs_monitor_puts(ECS_Client *clii, Monitor *mon, const char *str) {
137     char c;
138
139     if (!clii || !mon) {
140         return;
141     }
142
143     for (;;) {
144         c = *str++;
145         if (c == '\0')
146             break;
147 #ifndef _WIN32
148         if (c == '\n')
149             mon->outbuf[mon->outbuf_index++] = '\r';
150 #endif
151         mon->outbuf[mon->outbuf_index++] = c;
152         if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1) || c == '\n')
153             ecs_monitor_flush(clii, mon);
154     }
155 }
156
157 static inline int monitor_has_error(const Monitor *mon) {
158     return mon->error != NULL;
159 }
160
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));
165
166     return qobject_to_qdict(obj);
167 }
168
169 static void ecs_json_emitter(ECS_Client *clii, const QObject *data) {
170     QString *json;
171
172     json = qobject_to_json(data);
173
174     assert(json != NULL);
175
176     qstring_append_chr(json, '\n');
177     ecs_monitor_puts(clii, clii->cs->mon, qstring_get_str(json));
178
179     QDECREF(json);
180 }
181
182 static void ecs_protocol_emitter(ECS_Client *clii, const char* type,
183         QObject *data) {
184     QDict *qmp;
185     QObject *obj;
186
187     TRACE("ecs_protocol_emitter called.");
188     //trace_monitor_protocol_emitter(clii->cs->mon);
189
190     if (!monitor_has_error(clii->cs->mon)) {
191         /* success response */
192         qmp = qdict_new();
193         if (data) {
194             qobject_incref(data);
195             qdict_put_obj(qmp, "return", data);
196         } else {
197             /* return an empty QDict by default */
198             qdict_put(qmp, "return", qdict_new());
199         }
200
201         if (type == NULL) {
202             obj = qobject_from_jsonf("%s", "unknown");
203         } else {
204             obj = qobject_from_jsonf("%s", type);
205         }
206         qdict_put_obj(qmp, "type", obj);
207
208     } else {
209         /* error response */
210         qmp = build_qmp_error_dict(clii->cs->mon->error);
211         QDECREF(clii->cs->mon->error);
212         clii->cs->mon->error = NULL;
213     }
214
215     ecs_json_emitter(clii, QOBJECT(qmp));
216     QDECREF(qmp);
217 }
218
219 static void qmp_monitor_complete(void *opaque, QObject *ret_data) {
220     //   ecs_protocol_emitter(opaque, ret_data);
221 }
222
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,
226             clii);
227 }
228
229 static void ecs_qmp_call_cmd(ECS_Client *clii, Monitor *mon, const char* type,
230         const mon_cmd_t *cmd, const QDict *params) {
231     int ret;
232     QObject *data = NULL;
233
234     ret = cmd->mhandler.cmd_new(mon, params, &data);
235     if (ret && !monitor_has_error(mon)) {
236         qerror_report(QERR_UNDEFINED_ERROR);
237     }
238     ecs_protocol_emitter(clii, type, data);
239     qobject_decref(data);
240 }
241
242 static inline bool handler_is_async(const mon_cmd_t *cmd) {
243     return cmd->flags & MONITOR_CMD_ASYNC;
244 }
245
246 static void monitor_user_noop(Monitor *mon, const QObject *data) {
247 }
248
249 static int client_migrate_info(Monitor *mon, const QDict *qdict,
250         MonitorCompletion cb, void *opaque) {
251     return 0;
252 }
253
254 static int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) {
255     return 0;
256 }
257
258 static int do_qmp_capabilities(Monitor *mon, const QDict *params,
259         QObject **ret_data) {
260     return 0;
261 }
262
263 static const mon_cmd_t qmp_cmds[] = {
264 #include "qmp-commands-old.h"
265         { /* NULL */}, };
266
267 static int check_mandatory_args(const QDict *cmd_args, const QDict *client_args,
268         int *flags) {
269     const QDictEntry *ent;
270
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);
275
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);
283             return -1;
284         }
285     }
286
287     return 0;
288 }
289
290 static int check_client_args_type(const QDict *client_args,
291         const QDict *cmd_args, int flags) {
292     const QDictEntry *ent;
293
294     for (ent = qdict_first(client_args); ent;
295             ent = qdict_next(client_args, ent)) {
296         QObject *obj;
297         QString *arg_type;
298         const QObject *client_arg = qdict_entry_value(ent);
299         const char *client_arg_name = qdict_entry_key(ent);
300
301         obj = qdict_get(cmd_args, client_arg_name);
302         if (!obj) {
303             if (flags & QMP_ACCEPT_UNKNOWNS) {
304                 continue;
305             }
306             qerror_report(QERR_INVALID_PARAMETER, client_arg_name);
307             return -1;
308         }
309
310         arg_type = qobject_to_qstring(obj);
311         assert(arg_type != NULL);
312
313         switch (qstring_get_str(arg_type)[0]) {
314         case 'F':
315         case 'B':
316         case 's':
317             if (qobject_type(client_arg) != QTYPE_QSTRING) {
318                 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
319                         "string");
320                 return -1;
321             }
322             break;
323         case 'i':
324         case 'l':
325         case 'M':
326         case 'o':
327             if (qobject_type(client_arg) != QTYPE_QINT) {
328                 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
329                         "int");
330                 return -1;
331             }
332             break;
333         case 'T':
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,
337                         "number");
338                 return -1;
339             }
340             break;
341         case 'b':
342         case '-':
343             if (qobject_type(client_arg) != QTYPE_QBOOL) {
344                 qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
345                         "bool");
346                 return -1;
347             }
348             break;
349         case 'O':
350             assert(flags & QMP_ACCEPT_UNKNOWNS);
351             break;
352         case 'q':
353             break;
354         case '/':
355         case '.':
356         default:
357             abort();
358         }
359     }
360
361     return 0;
362 }
363
364 static QDict *qdict_from_args_type(const char *args_type) {
365     int i;
366     QDict *qdict;
367     QString *key, *type, *cur_qs;
368
369     assert(args_type != NULL);
370
371     qdict = qdict_new();
372
373     if (args_type == NULL || args_type[0] == '\0') {
374         goto out;
375     }
376
377     key = qstring_new();
378     type = qstring_new();
379
380     cur_qs = key;
381
382     for (i = 0;; i++) {
383         switch (args_type[i]) {
384         case ',':
385         case '\0':
386             qdict_put(qdict, qstring_get_str(key), type);
387             QDECREF(key);
388             if (args_type[i] == '\0') {
389                 goto out;
390             }
391             type = qstring_new();
392             cur_qs = key = qstring_new();
393             break;
394         case ':':
395             cur_qs = type;
396             break;
397         default:
398             qstring_append_chr(cur_qs, args_type[i]);
399             break;
400         }
401     }
402
403     out: return qdict;
404 }
405
406 static int qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args) {
407     int flags, err;
408     QDict *cmd_args;
409
410     cmd_args = qdict_from_args_type(cmd->args_type);
411
412     flags = 0;
413     err = check_mandatory_args(cmd_args, client_args, &flags);
414     if (err) {
415         goto out;
416     }
417
418     err = check_client_args_type(client_args, cmd_args, flags);
419
420     out:
421     QDECREF(cmd_args);
422     return err;
423 }
424
425 static QDict *qmp_check_input_obj(QObject *input_obj) {
426     const QDictEntry *ent;
427     int has_exec_key = 0;
428     QDict *input_dict;
429
430     if (qobject_type(input_obj) != QTYPE_QDICT) {
431         qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
432         return NULL;
433     }
434
435     input_dict = qobject_to_qdict(input_obj);
436
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);
441
442         if (!strcmp(arg_name, "execute")) {
443             if (qobject_type(arg_obj) != QTYPE_QSTRING) {
444                 qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
445                         "string");
446                 return NULL;
447             }
448             has_exec_key = 1;
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",
452                         "object");
453                 return NULL;
454             }
455         } else if (!strcmp(arg_name, "id")) {
456         } else if (!strcmp(arg_name, "type")) {
457         } else {
458             qerror_report(QERR_QMP_EXTRA_MEMBER, arg_name);
459             return NULL;
460         }
461     }
462
463     if (!has_exec_key) {
464         qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
465         return NULL;
466     }
467
468     return input_dict;
469 }
470
471 static int compare_cmd(const char *name, const char *list) {
472     const char *p, *pstart;
473     int len;
474     len = strlen(name);
475     p = list;
476     for (;;) {
477         pstart = p;
478         p = strchr(p, '|');
479         if (!p)
480             p = pstart + strlen(pstart);
481         if ((p - pstart) == len && !memcmp(pstart, name, len))
482             return 1;
483         if (*p == '\0')
484             break;
485         p++;
486     }
487     return 0;
488 }
489
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;
493
494     for (cmd = disp_table; cmd->name != NULL; cmd++) {
495         if (compare_cmd(cmdname, cmd->name)) {
496             return cmd;
497         }
498     }
499
500     return NULL;
501 }
502
503 static const mon_cmd_t *qmp_find_cmd(const char *cmdname) {
504     return search_dispatch_table(qmp_cmds, cmdname);
505 }
506
507 void handle_qmp_command(JSONMessageParser *parser, QList *tokens,
508         void *opaque) {
509     int err;
510     QObject *obj;
511     QDict *input, *args;
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;
517
518     args = input = NULL;
519
520     obj = json_parser_parse(tokens, NULL);
521     if (!obj) {
522         // FIXME: should be triggered in json_parser_parse()
523         qerror_report(QERR_JSON_PARSING);
524         goto err_out;
525     }
526
527     input = qmp_check_input_obj(obj);
528     if (!input) {
529         qobject_decref(obj);
530         goto err_out;
531     }
532
533     cmd_name = qdict_get_str(input, "execute");
534     //trace_handle_qmp_command(mon, cmd_name);
535
536     cmd = qmp_find_cmd(cmd_name);
537     if (!cmd) {
538         qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
539         goto err_out;
540     }
541
542     type_name = qdict_get_str(qobject_to_qdict(obj), COMMANDS_TYPE);
543
544     obj = qdict_get(input, "arguments");
545     if (!obj) {
546         args = qdict_new();
547     } else {
548         args = qobject_to_qdict(obj);
549         QINCREF(args);
550     }
551
552     err = qmp_check_client_args(cmd, args);
553     if (err < 0) {
554         goto err_out;
555     }
556
557     if (handler_is_async(cmd)) {
558         err = ecs_qmp_async_cmd_handler(clii, cmd, args);
559         if (err) {
560             /* emit the error response */
561             goto err_out;
562         }
563     } else {
564         ecs_qmp_call_cmd(clii, mon, type_name, cmd, args);
565     }
566
567     goto out;
568
569 err_out:
570     ecs_protocol_emitter(clii, NULL, NULL);
571 out:
572     QDECREF(input);
573     QDECREF(args);
574 }
575
576 bool msgproc_monitor_req(ECS_Client *ccli, ECS__MonitorReq* msg)
577 {
578     TRACE(">> monitor req: data = %s", msg->command);
579     ecs_json_message_parser_feed(&(ccli->parser), (const char *) msg->command, strlen(msg->command));
580     return true;
581 }
582