[Top][All Lists]
[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
- [Qemu-devel] [RFC][PATCH v7 15/16] virtagent: qemu-va, system-level virtagent guest agent, (continued)
- [Qemu-devel] [RFC][PATCH v7 15/16] virtagent: qemu-va, system-level virtagent guest agent, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 16/16] virtagent: add bits to build virtagent host/guest components, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 12/16] virtagent: add "shutdown" RPC to server, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 14/16] virtagent: add virtagent chardev, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 07/16] virtagent: base RPC client definitions, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 08/16] virtagnet: base RPC server definitions, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 04/16] virtagent: bi-directional RPC handling logic, Michael Roth, 2011/03/07
- [Qemu-devel] [RFC][PATCH v7 05/16] virtagent: common helpers and init routines,
Michael Roth <=
- [Qemu-devel] [RFC][PATCH v7 03/16] Make qemu timers available for tools, Michael Roth, 2011/03/07
- [Qemu-devel] Re: [RFC][PATCH v7 00/16] virtagent: host/guest communication agent, Anthony Liguori, 2011/03/07