qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC][PATCH v7 05/16] virtagent: common helpers and init ro


From: Michael Roth
Subject: [Qemu-devel] [RFC][PATCH v7 05/16] virtagent: common helpers and init routines
Date: Mon, 7 Mar 2011 14:10:31 -0600

Signed-off-by: Michael Roth <address@hidden>
---
 virtagent-common.c |  206 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-common.h |   95 ++++++++++++++++++++++++
 2 files changed, 301 insertions(+), 0 deletions(-)
 create mode 100644 virtagent-common.c
 create mode 100644 virtagent-common.h

diff --git a/virtagent-common.c b/virtagent-common.c
new file mode 100644
index 0000000..4b13ee8
--- /dev/null
+++ b/virtagent-common.c
@@ -0,0 +1,206 @@
+/*
+ * virtagent - common host/guest functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <address@hidden>
+ *  Michael Roth      <address@hidden>
+ *
+ * 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 "virtagent-common.h"
+
+VAState *va_state;
+
+/* helper to avoid tedious key/type checking on QDict entries */
+bool va_qdict_haskey_with_type(const QDict *qdict, const char *key,
+                               qtype_code type)
+{
+    QObject *qobj;
+    if (!qdict) {
+        return false;
+    }
+    if (!qdict_haskey(qdict, key)) {
+        return false;
+    }
+    qobj = qdict_get(qdict, key);
+    if (qobject_type(qobj) != type) {
+        return false;
+    }
+
+    return true;
+}
+
+static void va_qdict_insert(const char *key, QObject *entry, void *opaque)
+{
+    QDict *dict = opaque;
+
+    if (key && entry) {
+        qdict_put_obj(dict, key, entry);
+    }
+}
+
+QDict *va_qdict_copy(const QDict *old)
+{
+    QDict *new;
+
+    if (!old) {
+        return NULL;
+    }
+
+    new = qdict_new();
+    qdict_iter(old, va_qdict_insert, new);
+
+    return new;
+}
+
+static int va_connect(void)
+{
+    QemuOpts *opts;
+    int fd, ret = 0;
+
+    TRACE("called");
+    if (va_state->channel_method == NULL) {
+        LOG("no channel method specified");
+        return -EINVAL;
+    }
+    if (va_state->channel_path == NULL) {
+        LOG("no channel path specified");
+        return -EINVAL;
+    }
+
+    if (strcmp(va_state->channel_method, "unix-connect") == 0) {
+        TRACE("connecting to %s", va_state->channel_path);
+        opts = qemu_opts_create(qemu_find_opts("chardev"), NULL, 0);
+        qemu_opt_set(opts, "path", va_state->channel_path);
+        fd = unix_connect_opts(opts);
+        if (fd == -1) {
+            qemu_opts_del(opts);
+            LOG("error opening channel: %s", strerror(errno));
+            return -errno;
+        }
+        qemu_opts_del(opts);
+        socket_set_nonblock(fd);
+    } else if (strcmp(va_state->channel_method, "virtio-serial") == 0) {
+        if (va_state->is_host) {
+            LOG("specified channel method not available for host");
+            return -EINVAL;
+        }
+        if (va_state->channel_path == NULL) {
+            va_state->channel_path = VA_GUEST_PATH_VIRTIO_DEFAULT;
+        }
+        TRACE("opening %s", va_state->channel_path);
+        fd = qemu_open(va_state->channel_path, O_RDWR);
+        if (fd == -1) {
+            LOG("error opening channel: %s", strerror(errno));
+            return -errno;
+        }
+        ret = fcntl(fd, F_GETFL);
+        if (ret < 0) {
+            LOG("error getting channel flags: %s", strerror(errno));
+            return -errno;
+        }
+        ret = fcntl(fd, F_SETFL, ret | O_ASYNC | O_NONBLOCK);
+        if (ret < 0) {
+            LOG("error setting channel flags: %s", strerror(errno));
+            return -errno;
+        }
+    } else if (strcmp(va_state->channel_method, "isa-serial") == 0) {
+        struct termios tio;
+        if (va_state->is_host) {
+            LOG("specified channel method not available for host");
+            return -EINVAL;
+        }
+        if (va_state->channel_path == NULL) {
+            LOG("you must specify the path of the serial device to use");
+            return -EINVAL;
+        }
+        TRACE("opening %s", va_state->channel_path);
+        fd = qemu_open(va_state->channel_path, O_RDWR | O_NOCTTY);
+        if (fd == -1) {
+            LOG("error opening channel: %s", strerror(errno));
+            return -errno;
+        }
+        tcgetattr(fd, &tio);
+        /* set up serial port for non-canonical, dumb byte streaming */
+        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
+                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY | 
IMAXBEL);
+        tio.c_oflag = 0;
+        tio.c_lflag = 0;
+        tio.c_cflag |= VA_BAUDRATE;
+        /* 1 available byte min, else reads will block (we'll set non-blocking
+         * elsewhere, else we'd have to deal with read()=0 instead)
+         */
+        tio.c_cc[VMIN] = 1;
+        tio.c_cc[VTIME] = 0;
+        /* flush everything waiting for read/xmit, it's garbage at this point 
*/
+        tcflush(fd, TCIFLUSH);
+        tcsetattr(fd, TCSANOW, &tio);
+    } else {
+        LOG("invalid channel method");
+        return -EINVAL;
+    }
+
+    va_state->fd = fd;
+    return 0;
+}
+
+int va_init(VAContext ctx)
+{
+    VAState *s;
+    VAManager *m;
+    int ret;
+
+    TRACE("called");
+    if (va_state) {
+        LOG("virtagent already initialized");
+        return -EPERM;
+    }
+
+    s = qemu_mallocz(sizeof(VAState));
+    m = va_manager_new();
+
+    ret = va_server_init(m, &s->server_data, ctx.is_host);
+    if (ret) {
+        LOG("error initializing virtagent server");
+        goto out_bad;
+    }
+    ret = va_client_init(m, &s->client_data);
+    if (ret) {
+        LOG("error initializing virtagent client");
+        goto out_bad;
+    }
+
+    s->client_job_count = 0;
+    s->client_jobs_in_flight = 0;
+    s->server_job_count = 0;
+    s->channel_method = ctx.channel_method;
+    s->channel_path = ctx.channel_path;
+    s->is_host = ctx.is_host;
+    s->manager = m;
+    va_state = s;
+
+    /* connect to our end of the channel */
+    ret = va_connect();
+    if (ret) {
+        LOG("error connecting to channel");
+        goto out_bad;
+    }
+
+    /* start listening for requests/responses */
+    qemu_set_fd_handler(va_state->fd, va_http_read_handler, NULL, NULL);
+
+    if (!va_state->is_host) {
+        /* tell the host the agent is running */
+        va_send_hello();
+    }
+
+    return 0;
+out_bad:
+    qemu_free(s);
+    return ret;
+}
diff --git a/virtagent-common.h b/virtagent-common.h
new file mode 100644
index 0000000..5ae50d1
--- /dev/null
+++ b/virtagent-common.h
@@ -0,0 +1,95 @@
+/*
+ * virt-agent - host/guest RPC client functions
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Adam Litke        <address@hidden>
+ *  Michael Roth      <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef VIRTAGENT_COMMON_H
+#define VIRTAGENT_COMMON_H
+
+#include <termios.h>
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "qemu-timer.h"
+#include "monitor.h"
+#include "virtagent-manager.h"
+#include "virtagent-server.h"
+#include "virtagent.h"
+
+#define DEBUG_VA
+
+#ifdef DEBUG_VA
+#define TRACE(msg, ...) do { \
+    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
+            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+} while(0)
+#else
+#define TRACE(msg, ...) \
+    do { } while (0)
+#endif
+
+#define LOG(msg, ...) do { \
+    fprintf(stderr, "%s:%s(): " msg "\n", \
+            __FILE__, __FUNCTION__, ## __VA_ARGS__); \
+} while(0)
+
+#define VA_VERSION "1.0"
+#define EOL "\r\n"
+
+#define VA_PIDFILE "/var/run/qemu-va.pid"
+#define VA_HDR_LEN_MAX 4096 /* http header limit */
+#define VA_CONTENT_LEN_MAX 2*1024*1024 /* rpc/http send limit */
+#define VA_CLIENT_JOBS_MAX 5 /* max client rpcs we can queue */
+#define VA_SERVER_JOBS_MAX 5 /* max server rpcs we can queue */
+#define VA_SERVER_TIMEOUT_MS 5 * 1000
+#define VA_CLIENT_TIMEOUT_MS 5 * 1000
+#define VA_SENTINEL 0xFF
+#define VA_BAUDRATE B38400 /* for isa-serial channels */
+
+typedef struct VAContext {
+    bool is_host;
+    const char *channel_method;
+    const char *channel_path;
+} VAContext;
+
+typedef struct VAState {
+    bool is_host;
+    const char *channel_method;
+    const char *channel_path;
+    int fd;
+    QEMUTimer *client_timer;
+    QEMUTimer *server_timer;
+    VAClientData client_data;
+    VAServerData server_data;
+    int client_job_count;
+    int client_jobs_in_flight;
+    int server_job_count;
+    VAManager *manager;
+} VAState;
+
+enum va_job_status {
+    VA_JOB_STATUS_PENDING = 0,
+    VA_JOB_STATUS_OK,
+    VA_JOB_STATUS_ERROR,
+    VA_JOB_STATUS_CANCELLED,
+};
+
+typedef void (VAHTSendCallback)(const void *opaque);
+
+int va_init(VAContext ctx);
+bool va_qdict_haskey_with_type(const QDict *qdict, const char *key,
+                               qtype_code type);
+QDict *va_qdict_copy(const QDict *old);
+int va_xport_send_response(const char *content, size_t content_len, const char 
*tag,
+                           const void *opaque, VAHTSendCallback cb);
+int va_xport_send_request(const char *content, size_t content_len, const char 
*tag,
+                          const void *opaque, VAHTSendCallback cb);
+void va_http_read_handler(void *opaque);
+#endif /* VIRTAGENT_COMMON_H */
-- 
1.7.0.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]