Basic ecp message handler added
authorchoisjin80 <jinhyung2.choi@samsung.com>
Wed, 20 Mar 2013 12:09:45 +0000 (21:09 +0900)
committerchoisjin80 <jinhyung2.choi@samsung.com>
Wed, 20 Mar 2013 12:09:45 +0000 (21:09 +0900)
Signed-off-by: choisjin80 <jinhyung2.choi@samsung.com>
tizen/src/carrier.c [new file with mode: 0644]
tizen/src/carrier.h [new file with mode: 0644]
tizen/src/qmp_handler.c [new file with mode: 0644]

diff --git a/tizen/src/carrier.c b/tizen/src/carrier.c
new file mode 100644 (file)
index 0000000..8e9bab4
--- /dev/null
@@ -0,0 +1,961 @@
+
+#include "hw/qdev.h"
+#include "net.h"
+#include "console.h"
+#include "migration.h"
+
+#ifndef _WIN32
+#include <sys/epoll.h>
+#endif
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "qemu-queue.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "qemu-timer.h"
+#include "main-loop.h"
+#include "ui/qemu-spice.h"
+#include "qemu-char.h"
+
+#include "qjson.h"
+#include "json-streamer.h"
+#include "json-parser.h"
+#include "monitor.h"
+#include "qmp-commands.h"
+
+#include "carrier.h"
+
+#define OUT_BUF_SIZE   1024
+#define READ_BUF_LEN   4096
+
+typedef struct mon_fd_t mon_fd_t;
+struct mon_fd_t {
+    char *name;
+    int fd;
+    QLIST_ENTRY(mon_fd_t) next;
+};
+
+struct Monitor {
+    int suspend_cnt;
+    uint8_t outbuf[OUT_BUF_SIZE];
+    int outbuf_index;
+    CPUArchState *mon_cpu;
+    void *password_opaque;
+    QError *error;
+    QLIST_HEAD(,mon_fd_t) fds;
+    QLIST_ENTRY(Monitor) entry;
+};
+
+#define MAX_CLIENT     10
+#define MAX_EVENTS     1000
+typedef struct CarrierState {
+       int listen_fd;
+       int epoll_fd;
+       struct epoll_event events[MAX_EVENTS];
+       int is_unix;
+       Monitor *mon;
+} CarrierState;
+
+typedef struct CarrierClientInfo {
+       int client_fd;
+       const char* target;
+       CarrierState *cs;
+       JSONMessageParser parser;
+    QTAILQ_ENTRY(CarrierClientInfo) next;
+} CarrierClientInfo;
+
+typedef struct mon_cmd_t {
+    const char *name;
+    const char *args_type;
+    const char *params;
+    const char *help;
+    void (*user_print)(Monitor *mon, const QObject *data);
+    union {
+        void (*info)(Monitor *mon);
+        void (*cmd)(Monitor *mon, const QDict *qdict);
+        int  (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+        int  (*cmd_async)(Monitor *mon, const QDict *params,
+                          MonitorCompletion *cb, void *opaque);
+    } mhandler;
+    int flags;
+} mon_cmd_t;
+
+static QTAILQ_HEAD(CarrierClientInfoHead, CarrierClientInfo) clients =
+    QTAILQ_HEAD_INITIALIZER(clients);
+
+static int carrier_write(int fd, const uint8_t *buf, int len);
+
+#define QMP_ACCEPT_UNKNOWNS 1
+static void carrier_flush(CarrierClientInfo *clii)
+{
+    if (clii && clii->cs && clii->cs->mon && clii->cs->mon->outbuf_index != 0) {
+        carrier_write(clii->client_fd, clii->cs->mon->outbuf, clii->cs->mon->outbuf_index);
+        clii->cs->mon->outbuf_index = 0;
+    }
+}
+
+/* flush at every end of line or if the buffer is full */
+static void carrier_puts(CarrierClientInfo *clii, const char *str)
+{
+    char c;
+
+    for(;;) {
+        c = *str++;
+        if (c == '\0')
+            break;
+        if (c == '\n')
+            clii->cs->mon->outbuf[clii->cs->mon->outbuf_index++] = '\r';
+        clii->cs->mon->outbuf[clii->cs->mon->outbuf_index++] = c;
+        if (clii->cs->mon->outbuf_index >= (sizeof(clii->cs->mon->outbuf) - 1)
+            || c == '\n')
+            carrier_flush(clii);
+    }
+}
+
+void carrier_vprintf(const char *target, const char *fmt, va_list ap)
+{
+    char buf[READ_BUF_LEN];
+       CarrierClientInfo *clii;
+
+    QTAILQ_FOREACH(clii, &clients, next) {
+        if (!strcmp(target, TARGET_ALL) || !strcmp(clii->target, target)) {
+                       vsnprintf(buf, sizeof(buf), fmt, ap);
+                       carrier_puts(clii, buf);
+               }
+    }
+}
+
+void carrier_printf(const char* target, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    carrier_vprintf(target, fmt, ap);
+    va_end(ap);
+}
+
+static inline int monitor_has_error(const Monitor *mon)
+{
+    return mon->error != NULL;
+}
+
+static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
+{
+    if (ret && !monitor_has_error(mon)) {
+        qerror_report(QERR_UNDEFINED_ERROR);
+    }
+}
+
+static QDict *build_qmp_error_dict(const QError *err)
+{
+    QObject *obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
+                             ErrorClass_lookup[err->err_class],
+                             qerror_human(err));
+
+    return qobject_to_qdict(obj);
+}
+
+static void monitor_json_emitter(CarrierClientInfo *clii, const QObject *data)
+{
+    QString *json;
+
+    json = qobject_to_json(data);
+
+    assert(json != NULL);
+
+    qstring_append_chr(json, '\n');
+    carrier_puts(clii, qstring_get_str(json));
+
+    QDECREF(json);
+}
+
+static void monitor_protocol_emitter(CarrierClientInfo *clii, QObject *data)
+{
+    QDict *qmp;
+
+    trace_monitor_protocol_emitter(clii->cs->mon);
+
+    if (!monitor_has_error(clii->cs->mon)) {
+        /* success response */
+        qmp = qdict_new();
+        if (data) {
+            qobject_incref(data);
+            qdict_put_obj(qmp, "return", data);
+        } else {
+            /* return an empty QDict by default */
+            qdict_put(qmp, "return", qdict_new());
+        }
+    } else {
+        /* error response */
+        qmp = build_qmp_error_dict(clii->cs->mon->error);
+        QDECREF(clii->cs->mon->error);
+        clii->cs->mon->error = NULL;
+    }
+
+    monitor_json_emitter(clii, QOBJECT(qmp));
+    QDECREF(qmp);
+}
+
+
+static void qmp_monitor_complete(void *opaque, QObject *ret_data)
+{
+    monitor_protocol_emitter(opaque, ret_data);
+}
+
+static int qmp_async_cmd_handler(CarrierClientInfo *clii, const mon_cmd_t *cmd,
+                                 const QDict *params)
+{
+    return cmd->mhandler.cmd_async(clii->cs->mon, params, qmp_monitor_complete, clii);
+}
+
+static void qmp_call_cmd(CarrierClientInfo *clii, const mon_cmd_t *cmd,
+                         const QDict *params)
+{
+    int ret;
+    QObject *data = NULL;
+
+    ret = cmd->mhandler.cmd_new(clii->cs->mon, params, &data);
+    handler_audit(clii->cs->mon, cmd, ret);
+    monitor_protocol_emitter(clii, data);
+    qobject_decref(data);
+}
+
+static inline bool handler_is_async(const mon_cmd_t *cmd)
+{
+    return cmd->flags & MONITOR_CMD_ASYNC;
+}
+
+static void monitor_user_noop(Monitor *mon, const QObject *data) 
+{ 
+}
+
+static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
+    return 0;
+}
+
+static int client_migrate_info(Monitor *mon, const QDict *qdict,
+                               MonitorCompletion cb, void *opaque)
+{
+    return 0;
+}
+
+static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    return 0;
+}
+
+static int do_qmp_capabilities(Monitor *mon, const QDict *params,
+                               QObject **ret_data)
+{
+    return 0;
+}
+
+static const mon_cmd_t qmp_cmds[] = {
+#include "qmp-commands-old.h"
+    { /* NULL */ },
+};
+
+static int check_mandatory_args(const QDict *cmd_args,
+                                const QDict *client_args, int *flags)
+{
+    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)) {
+            qerror_report(QERR_MISSING_PARAMETER, cmd_arg_name);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int check_client_args_type(const QDict *client_args,
+                                  const QDict *cmd_args, int flags)
+{
+    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;
+            }
+            qerror_report(QERR_INVALID_PARAMETER, client_arg_name);
+            return -1;
+        }
+
+        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) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "string");
+                return -1;
+            }
+        break;
+        case 'i':
+        case 'l':
+        case 'M':
+        case 'o':
+            if (qobject_type(client_arg) != QTYPE_QINT) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "int");
+                return -1; 
+            }
+            break;
+        case 'T':
+            if (qobject_type(client_arg) != QTYPE_QINT &&
+                qobject_type(client_arg) != QTYPE_QFLOAT) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "number");
+               return -1; 
+            }
+            break;
+        case 'b':
+        case '-':
+            if (qobject_type(client_arg) != QTYPE_QBOOL) {
+                qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
+                              "bool");
+               return -1; 
+            }
+            break;
+        case 'O':
+            assert(flags & QMP_ACCEPT_UNKNOWNS);
+            break;
+        case 'q':
+            break;
+        case '/':
+        case '.':
+        default:
+            abort();
+        }
+    }
+
+    return 0;
+}
+
+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 int qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args)
+{
+    int flags, err;
+    QDict *cmd_args;
+
+    cmd_args = qdict_from_args_type(cmd->args_type);
+
+    flags = 0;
+    err = check_mandatory_args(cmd_args, client_args, &flags);
+    if (err) {
+        goto out;
+    }
+
+    err = check_client_args_type(client_args, cmd_args, flags);
+
+out:
+    QDECREF(cmd_args);
+    return err;
+}
+
+static QDict *qmp_check_input_obj(QObject *input_obj)
+{
+    const QDictEntry *ent;
+    int has_exec_key = 0;
+    QDict *input_dict;
+
+    if (qobject_type(input_obj) != QTYPE_QDICT) {
+        qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
+        return NULL;
+    }
+
+    input_dict = qobject_to_qdict(input_obj);
+
+    for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
+        const char *arg_name = qdict_entry_key(ent);
+        const QObject *arg_obj = qdict_entry_value(ent);
+
+        if (!strcmp(arg_name, "execute")) {
+            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
+                qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
+                              "string");
+                return NULL;
+            }
+            has_exec_key = 1;
+        } else if (!strcmp(arg_name, "arguments")) {
+            if (qobject_type(arg_obj) != QTYPE_QDICT) {
+                qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "arguments",
+                              "object");
+                return NULL;
+            }
+        } else if (!strcmp(arg_name, "id")) {
+        } else {
+            qerror_report(QERR_QMP_EXTRA_MEMBER, arg_name);
+            return NULL;
+        }
+    }
+
+    if (!has_exec_key) {
+        qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
+        return NULL;
+    }
+
+    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);
+}
+
+static void handle_qmp_command(CarrierClientInfo *clii, QObject *obj)
+{
+    int err;
+    const mon_cmd_t *cmd;
+    const char *cmd_name;
+    QDict *input = NULL;
+       QDict *args = NULL;
+
+       input = qmp_check_input_obj(obj);
+    if (!input) {
+        qobject_decref(obj);
+        goto err_out;
+    }
+
+    cmd_name = qdict_get_str(input, "execute");
+
+    cmd = qmp_find_cmd(cmd_name);
+    if (!cmd) {
+        qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
+        goto err_out;
+    }
+       
+       obj = qdict_get(input, "arguments");
+    if (!obj) {
+        args = qdict_new();
+    } else {
+        args = qobject_to_qdict(obj);
+        QINCREF(args);
+    }
+
+    err = qmp_check_client_args(cmd, args);
+    if (err < 0) {
+        goto err_out;
+    }
+
+    if (handler_is_async(cmd)) {
+        err = qmp_async_cmd_handler(clii, cmd, args);
+        if (err) {
+            goto err_out;
+        }
+    } else {
+        qmp_call_cmd(clii, cmd, args);
+    }
+
+    goto out;
+
+err_out:
+    monitor_protocol_emitter(clii, NULL);
+out:
+    QDECREF(input);
+    QDECREF(args);
+
+}
+
+static int check_key(QObject *input_obj, const char *key)
+{
+    const QDictEntry *ent;
+    QDict *input_dict;
+
+    if (qobject_type(input_obj) != QTYPE_QDICT) {
+        qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
+        return -1;
+    }
+
+    input_dict = qobject_to_qdict(input_obj);
+
+    for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
+        const char *arg_name = qdict_entry_key(ent);
+        if (!strcmp(arg_name, key)) {
+               return 1;
+        }
+    }
+
+    return 0;
+}
+
+static QObject* get_data_object(QObject *input_obj)
+{
+    const QDictEntry *ent;
+    QDict *input_dict;
+
+    if (qobject_type(input_obj) != QTYPE_QDICT) {
+        qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
+        return NULL;
+    }
+
+    input_dict = qobject_to_qdict(input_obj);
+
+    for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
+        const char *arg_name = qdict_entry_key(ent);
+        QObject *arg_obj = qdict_entry_value(ent);
+        if (!strcmp(arg_name, COMMANDS_DATA)) {
+               return arg_obj;
+        }
+    }
+
+    return NULL;
+}
+
+static void handle_carrier_command(JSONMessageParser *parser, QList *tokens, void *opaque)
+{
+       const char *target_name;
+       const char *data_value;
+       int def_target = 0;
+       int def_data = 0;
+    QObject *obj;
+       CarrierClientInfo *clii = opaque;
+
+       if (NULL == clii) {
+               LOG("ClientInfo is null.");
+               return;
+       }
+       
+    obj = json_parser_parse(tokens, NULL);
+    if (!obj) {
+        qerror_report(QERR_JSON_PARSING);
+       monitor_protocol_emitter(clii, NULL);
+               return;
+    }
+
+       def_target = check_key(obj, COMMANDS_TARGET);
+       if (0 > def_target) {
+               LOG("def_target failed.");
+               return;
+       } else if (0 == def_target) {
+               handle_qmp_command(clii, obj);
+               return;
+       }
+
+       def_data = check_key(obj, COMMANDS_DATA);
+       if (0 > def_data) {
+               LOG("json format error: data.");
+               return;
+       } else if (0 == def_data) {
+               LOG("data key is not found.");
+               return;
+       }
+       
+       target_name = qdict_get_str(qobject_to_qdict(obj), COMMANDS_TARGET);
+               
+       if (!strcmp(target_name, TARGET_QMP)) {
+               handle_qmp_command(clii, get_data_object(obj));
+       } else {
+               data_value = qdict_get_str(qobject_to_qdict(obj), COMMANDS_DATA);
+               if (!strcmp(target_name, TARGET_SELF)) {
+                       clii->target = data_value;
+               monitor_protocol_emitter(clii, NULL);
+               }
+       }
+}
+
+static Monitor *monitor_create(void)
+{
+    Monitor *mon;
+
+       // TODO: event related work
+       //key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
+    //monitor_protocol_event_init();
+
+    mon = g_malloc0(sizeof(*mon));
+       memset(mon, 0, sizeof(*mon));
+
+       return mon;
+}
+
+static int device_initialize(void)
+{
+       // currently nothing to do with it.
+       return 1;
+}
+
+static void carrier_close(CarrierState *cs)
+{
+       if (cs->listen_fd >= 0) {
+               closesocket(cs->listen_fd);
+       }
+
+       if (cs->mon != NULL) {
+               g_free(cs->mon);
+       }
+       //TODO: device close
+
+       g_free(cs);
+}
+
+static int carrier_write(int fd, const uint8_t *buf, int len)
+{
+       return send_all(fd, buf, len);
+}
+
+#ifndef _WIN32
+static ssize_t carrier_recv(int fd, char *buf, size_t len)
+{
+       struct msghdr msg = { NULL, };
+    struct iovec iov[1];
+    union {
+        struct cmsghdr cmsg;
+        char control[CMSG_SPACE(sizeof(int))];
+    } msg_control;
+    int flags = 0;
+
+    iov[0].iov_base = buf;
+    iov[0].iov_len = len;
+
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+#ifdef MSG_CMSG_CLOEXEC
+    flags |= MSG_CMSG_CLOEXEC;
+#endif
+    return recvmsg(fd, &msg, flags);
+}
+
+#else
+static ssize_t carrier_recv(int fd, char *buf, size_t len)
+{
+    return qemu_recv(fd, buf, len, 0);
+}
+#endif
+
+static void carrier_read (CarrierClientInfo *clii)
+{
+       uint8_t buf[READ_BUF_LEN];
+       int len, size;
+       len = sizeof(buf);
+
+       if (!clii) {
+               LOG ("read client info is NULL.");
+               return;
+       }
+
+       size = carrier_recv(clii->client_fd, (void *)buf, len);
+       if (0 == size) {
+        closesocket(clii->client_fd);
+               QTAILQ_REMOVE(&clients, clii, next);
+               g_free(clii);
+       } else if (0 < size) {
+           json_message_parser_feed(&clii->parser, (const char *) buf, size);
+       }
+}
+
+static QObject *get_carrier_greeting(void)
+{
+    QObject *ver = NULL;
+
+    qmp_marshal_input_query_version(NULL, NULL, &ver);
+    return qobject_from_jsonf("{'Carrier':{'version': %p,'capabilities': [true]}}",ver);
+}
+
+static void epoll_cli_add(CarrierState *cs, int fd)
+{
+       struct epoll_event events;
+
+       /* event control set for read event */
+       events.events = EPOLLIN;
+       events.data.fd = fd; 
+
+       if( epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, fd, &events) < 0 )
+       {
+               LOG("Epoll control fails.in epoll_cli_add.");
+       }
+}
+
+static CarrierClientInfo *carrier_find_client(int fd)
+{
+       CarrierClientInfo *clii;
+
+    QTAILQ_FOREACH(clii, &clients, next) {
+        if (clii->client_fd == fd)
+               return clii;
+    }
+       return NULL;
+}
+
+static int carrier_add_client(CarrierState *cs, int fd) 
+{
+       QObject *data;
+       CarrierClientInfo *clii = g_malloc0(sizeof(CarrierClientInfo));
+
+       clii->client_fd = fd;
+       clii->cs = cs;
+    json_message_parser_init(&clii->parser, handle_carrier_command, clii);
+       epoll_cli_add(cs, fd);
+
+       QTAILQ_INSERT_TAIL(&clients, clii, next);
+
+       data = get_carrier_greeting();
+       monitor_json_emitter(clii, data);
+    qobject_decref(data);
+
+       return 0;
+}
+
+static void carrier_accept(CarrierState *cs)
+{
+    struct sockaddr_in saddr;
+#ifndef _WIN32
+    struct sockaddr_un uaddr;
+#endif
+    struct sockaddr *addr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+#ifndef _WIN32
+       if (cs->is_unix) {
+           len = sizeof(uaddr);
+           addr = (struct sockaddr *)&uaddr;
+       } else
+#endif
+       {
+           len = sizeof(saddr);
+           addr = (struct sockaddr *)&saddr;
+       }
+        fd = qemu_accept(cs->listen_fd, addr, &len);
+        if (0 > fd && EINTR != errno) {
+            return;
+        } else if (0 <= fd) {
+            break;
+        }
+    }
+       if (0 > carrier_add_client(cs, fd)) {
+               LOG("failed to add client.");
+       }
+}
+
+static void epoll_init(CarrierState *cs) 
+{
+       struct epoll_event events;
+
+       cs->epoll_fd = epoll_create(MAX_EVENTS);
+       if(cs->epoll_fd < 0)
+       {
+        closesocket(cs->listen_fd);
+       }
+
+       events.events = EPOLLIN;
+       events.data.fd = cs->listen_fd;
+
+       if( epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, cs->listen_fd, &events) < 0 )
+       {
+               close(cs->listen_fd);
+               close(cs->epoll_fd);
+       }
+}
+
+static int socket_initialize(CarrierState *cs, QemuOpts *opts)
+{
+       int fd = -1;
+
+    fd = inet_listen_opts(opts, 0, NULL);
+       if (0 > fd) {
+               return -1;
+       }
+
+    socket_set_nonblock(fd);
+
+       cs->listen_fd = fd;
+       epoll_init(cs);
+
+       return 0;
+}
+
+static void carrier_loop(CarrierState *cs)
+{
+       int i,nfds;
+
+       nfds = epoll_wait(cs->epoll_fd,cs->events,MAX_EVENTS,-1);
+       if (nfds == 0){
+               return;
+       }
+
+       if (nfds < 0) {
+               LOG("epoll wait error.");
+               return;
+       } 
+
+       for( i = 0 ; i < nfds ; i++ )
+       {
+               if (cs->events[i].data.fd == cs->listen_fd) {
+                       carrier_accept(cs);
+                       continue;
+               }
+               carrier_read(carrier_find_client(cs->events[i].data.fd));
+       }
+}
+
+static void* carrier_initialize(void* args) 
+{
+       char port[8];
+       int ret = 1;
+       CarrierState *cs = NULL;
+       QemuOpts *opts = NULL;
+       Error *local_err = NULL;
+       Monitor* mon = NULL;
+
+       opts = qemu_opts_create(qemu_find_opts("carrier"), "carrier", 1, &local_err);
+    if (error_is_set(&local_err)) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+        return NULL;
+    }
+
+       sprintf(port, "%d", (int)args);
+
+    qemu_opt_set(opts, "host", HOST_LISTEN_ADDR);
+    qemu_opt_set(opts, "port", port);
+
+       cs = g_malloc0(sizeof(CarrierState));
+
+       ret = socket_initialize(cs, opts);
+       if (0 > ret) {
+               LOG("socket initialization failed.");
+               return NULL;
+       }
+
+       mon = monitor_create();
+       if (NULL == mon) {
+               LOG("monitor initialization failed.");
+               carrier_close(cs);
+               return NULL;
+       }
+
+       cs->mon = mon;
+
+       ret = device_initialize();
+       if (0 > ret) {
+               LOG("device initialization failed.");
+               carrier_close(cs);
+               return NULL;
+       }
+
+       while(1) {
+               carrier_loop(cs);
+       }
+
+       return (void*)ret;
+}
+
+int stop_carrier(void)
+{
+       return 0;
+}
+
+int start_carrier(int server_port)
+{
+       pthread_t thread_id;
+
+       if (0 != pthread_create(&thread_id, NULL, carrier_initialize, (void*)server_port)) {
+               LOG("pthread creation failed.");
+               return -1;
+       }
+       return 0;
+}
diff --git a/tizen/src/carrier.h b/tizen/src/carrier.h
new file mode 100644 (file)
index 0000000..0a06484
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __CARRIER_H__
+#define __CARRIER_H__
+
+#include "qemu-common.h"
+
+#define LOG(fmt, arg...)       \
+       do {    \
+               fprintf(stderr,"[carrier:%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##arg);       \
+       } while (0)
+
+
+#define HOST_LISTEN_ADDR       "localhost"
+
+#define COMMANDS_TARGET                "target"
+#define COMMANDS_DATA          "data"
+
+
+#define TARGET_ALL                     "all"
+#define TARGET_ECP                     "ecp"
+#define TARGET_SELF                    "self"
+#define TARGET_QMP                     "qmp"
+#define TARGET_VIRTUAL         "virtual"
+
+int start_carrier(int server_port);
+int stop_carrier(void);
+
+void carrier_vprintf(const char *target, const char *fmt, va_list ap);
+void carrier_printf(const char *target, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+
+#endif /* __CARRIER_H__ */
diff --git a/tizen/src/qmp_handler.c b/tizen/src/qmp_handler.c
new file mode 100644 (file)
index 0000000..24c50f6
--- /dev/null
@@ -0,0 +1,14 @@
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "qmp-commands.h"
+
+AccelInfo *qmp_query_accel(Error **errp)
+{
+    AccelInfo *info = g_malloc0(sizeof(*info));
+    info->Xaxis = 1;
+    info->Yaxis = 2;
+    info->Zaxis = 3;
+       return info;
+}
+