All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libvchan: interdomain communications library
@ 2011-08-19 14:38 Daniel De Graaf
  2011-08-22  7:40 ` Vasiliy G Tolstov
                   ` (4 more replies)
  0 siblings, 5 replies; 61+ messages in thread
From: Daniel De Graaf @ 2011-08-19 14:38 UTC (permalink / raw)
  To: konrad.wilk, stefano.stabellini; +Cc: Daniel De Graaf, xen-devel

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
---

This version includes a local copy of gntalloc.h and gntdev.h to allow
it to compile when the installed kernel headers do not include gntalloc
and to support GNTDEV_SET_UNMAP_NOTIFY when the running kernel does not
match the headers. 

---
 tools/Makefile               |    1 +
 tools/libvchan/Makefile      |   57 ++++++
 tools/libvchan/gntalloc.h    |   82 ++++++++
 tools/libvchan/gntdev.h      |  150 ++++++++++++++
 tools/libvchan/init.c        |  456 ++++++++++++++++++++++++++++++++++++++++++
 tools/libvchan/io.c          |  270 +++++++++++++++++++++++++
 tools/libvchan/libvchan.h    |  141 +++++++++++++
 tools/libvchan/node-select.c |  161 +++++++++++++++
 tools/libvchan/node.c        |  169 ++++++++++++++++
 9 files changed, 1487 insertions(+), 0 deletions(-)
 create mode 100644 tools/libvchan/Makefile
 create mode 100644 tools/libvchan/gntalloc.h
 create mode 100644 tools/libvchan/gntdev.h
 create mode 100644 tools/libvchan/init.c
 create mode 100644 tools/libvchan/io.c
 create mode 100644 tools/libvchan/libvchan.h
 create mode 100644 tools/libvchan/node-select.c
 create mode 100644 tools/libvchan/node.c

diff --git a/tools/Makefile b/tools/Makefile
index df6270c..9389e1f 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -27,6 +27,7 @@ SUBDIRS-$(CONFIG_NetBSD) += blktap2
 SUBDIRS-$(CONFIG_NetBSD) += xenbackendd
 SUBDIRS-y += libfsimage
 SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
+SUBDIRS-y += libvchan
 
 # do not recurse in to a dir we are about to delete
 ifneq "$(MAKECMDGOALS)" "distclean"
diff --git a/tools/libvchan/Makefile b/tools/libvchan/Makefile
new file mode 100644
index 0000000..9195f6e
--- /dev/null
+++ b/tools/libvchan/Makefile
@@ -0,0 +1,57 @@
+#
+# tools/libvchan/Makefile
+#
+
+XEN_ROOT = $(CURDIR)/../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+LIBVCHAN_OBJS = init.o io.o
+NODE_OBJS = node.o
+NODE2_OBJS = node-select.o
+
+LIBVCHAN_LIBS = $(LDLIBS_libxenstore)
+LIBVCHAN_OBJS: CFLAGS += $(CFLAGS_libxenstore)
+
+MAJOR = 1.0
+MINOR = 0
+
+CFLAGS += -I. -fPIC
+
+.PHONY: all
+all: libvchan.so vchan-node1 vchan-node2 libvchan.a
+
+libvchan.so: libvchan.so.$(MAJOR)
+	ln -sf $< $@
+
+libvchan.so.$(MAJOR): libvchan.so.$(MAJOR).$(MINOR)
+	ln -sf $< $@
+
+libvchan.so.$(MAJOR).$(MINOR): $(LIBVCHAN_OBJS)
+	$(CC) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libvchan.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(LIBVCHAN_LIBS)
+
+libvchan.a: $(LIBVCHAN_OBJS)
+	$(AR) rcs libvchan.a $^
+
+vchan-node1: $(NODE_OBJS) libvchan.so
+	$(CC) $(LDFLAGS) -o $@ $(NODE_OBJS) libvchan.so $(LDLIBS_libvchan)
+
+vchan-node2: $(NODE2_OBJS) libvchan.so
+	$(CC) $(LDFLAGS) -o $@ $(NODE2_OBJS) libvchan.so $(LDLIBS_libvchan)
+
+.PHONY: install
+install: all
+	$(INSTALL_DIR) $(DESTDIR)$(LIBDIR)
+	$(INSTALL_DIR) $(DESTDIR)$(INCLUDEDIR)
+	$(INSTALL_PROG) libvchan.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)
+	ln -sf libvchan.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)/libvchan.so.$(MAJOR)
+	ln -sf libvchan.so.$(MAJOR) $(DESTDIR)$(LIBDIR)/libvchan.so
+	$(INSTALL_DATA) libvchan.a $(DESTDIR)$(LIBDIR)
+	$(INSTALL_DATA) libvchan.h $(DESTDIR)$(INCLUDEDIR)
+
+.PHONY: clean
+clean:
+	$(RM) -f *.o *.so* *.a vchan-node1 vchan-node2 $(DEPS)
+
+distclean: clean
+
+-include $(DEPS)
diff --git a/tools/libvchan/gntalloc.h b/tools/libvchan/gntalloc.h
new file mode 100644
index 0000000..76bd580
--- /dev/null
+++ b/tools/libvchan/gntalloc.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * gntalloc.h
+ *
+ * Interface to /dev/xen/gntalloc.
+ *
+ * Author: Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * This file is in the public domain.
+ */
+
+#ifndef __LINUX_PUBLIC_GNTALLOC_H__
+#define __LINUX_PUBLIC_GNTALLOC_H__
+
+/*
+ * Allocates a new page and creates a new grant reference.
+ */
+#define IOCTL_GNTALLOC_ALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
+struct ioctl_gntalloc_alloc_gref {
+	/* IN parameters */
+	/* The ID of the domain to be given access to the grants. */
+	uint16_t domid;
+	/* Flags for this mapping */
+	uint16_t flags;
+	/* Number of pages to map */
+	uint32_t count;
+	/* OUT parameters */
+	/* The offset to be used on a subsequent call to mmap(). */
+	uint64_t index;
+	/* The grant references of the newly created grant, one per page */
+	/* Variable size, depending on count */
+	uint32_t gref_ids[1];
+};
+
+#define GNTALLOC_FLAG_WRITABLE 1
+
+/*
+ * Deallocates the grant reference, allowing the associated page to be freed if
+ * no other domains are using it.
+ */
+#define IOCTL_GNTALLOC_DEALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
+struct ioctl_gntalloc_dealloc_gref {
+	/* IN parameters */
+	/* The offset returned in the map operation */
+	uint64_t index;
+	/* Number of references to unmap */
+	uint32_t count;
+};
+
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
+struct ioctl_gntalloc_unmap_notify {
+	/* IN parameters */
+	/* Offset in the file descriptor for a byte within the page (same as
+	 * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+	 * be cleared. Otherwise, it can be any byte in the page whose
+	 * notification we are adjusting.
+	 */
+	uint64_t index;
+	/* Action(s) to take on unmap */
+	uint32_t action;
+	/* Event channel to notify */
+	uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+#endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
diff --git a/tools/libvchan/gntdev.h b/tools/libvchan/gntdev.h
new file mode 100644
index 0000000..5304bd3
--- /dev/null
+++ b/tools/libvchan/gntdev.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * gntdev.h
+ * 
+ * Interface to /dev/xen/gntdev.
+ * 
+ * Copyright (c) 2007, D G Murray
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __LINUX_PUBLIC_GNTDEV_H__
+#define __LINUX_PUBLIC_GNTDEV_H__
+
+struct ioctl_gntdev_grant_ref {
+	/* The domain ID of the grant to be mapped. */
+	uint32_t domid;
+	/* The grant reference of the grant to be mapped. */
+	uint32_t ref;
+};
+
+/*
+ * Inserts the grant references into the mapping table of an instance
+ * of gntdev. N.B. This does not perform the mapping, which is deferred
+ * until mmap() is called with @index as the offset.
+ */
+#define IOCTL_GNTDEV_MAP_GRANT_REF \
+_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
+struct ioctl_gntdev_map_grant_ref {
+	/* IN parameters */
+	/* The number of grants to be mapped. */
+	uint32_t count;
+	uint32_t pad;
+	/* OUT parameters */
+	/* The offset to be used on a subsequent call to mmap(). */
+	uint64_t index;
+	/* Variable IN parameter. */
+	/* Array of grant references, of size @count. */
+	struct ioctl_gntdev_grant_ref refs[1];
+};
+
+/*
+ * Removes the grant references from the mapping table of an instance of
+ * of gntdev. N.B. munmap() must be called on the relevant virtual address(es)
+ * before this ioctl is called, or an error will result.
+ */
+#define IOCTL_GNTDEV_UNMAP_GRANT_REF \
+_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))
+struct ioctl_gntdev_unmap_grant_ref {
+	/* IN parameters */
+	/* The offset was returned by the corresponding map operation. */
+	uint64_t index;
+	/* The number of pages to be unmapped. */
+	uint32_t count;
+	uint32_t pad;
+};
+
+/*
+ * Returns the offset in the driver's address space that corresponds
+ * to @vaddr. This can be used to perform a munmap(), followed by an
+ * UNMAP_GRANT_REF ioctl, where no state about the offset is retained by
+ * the caller. The number of pages that were allocated at the same time as
+ * @vaddr is returned in @count.
+ *
+ * N.B. Where more than one page has been mapped into a contiguous range, the
+ *      supplied @vaddr must correspond to the start of the range; otherwise
+ *      an error will result. It is only possible to munmap() the entire
+ *      contiguously-allocated range at once, and not any subrange thereof.
+ */
+#define IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR \
+_IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr))
+struct ioctl_gntdev_get_offset_for_vaddr {
+	/* IN parameters */
+	/* The virtual address of the first mapped page in a range. */
+	uint64_t vaddr;
+	/* OUT parameters */
+	/* The offset that was used in the initial mmap() operation. */
+	uint64_t offset;
+	/* The number of pages mapped in the VM area that begins at @vaddr. */
+	uint32_t count;
+	uint32_t pad;
+};
+
+/*
+ * Sets the maximum number of grants that may mapped at once by this gntdev
+ * instance.
+ *
+ * N.B. This must be called before any other ioctl is performed on the device.
+ */
+#define IOCTL_GNTDEV_SET_MAX_GRANTS \
+_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
+struct ioctl_gntdev_set_max_grants {
+	/* IN parameter */
+	/* The maximum number of grants that may be mapped at once. */
+	uint32_t count;
+};
+
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
+struct ioctl_gntdev_unmap_notify {
+	/* IN parameters */
+	/* Offset in the file descriptor for a byte within the page (same as
+	 * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+	 * be cleared. Otherwise, it can be any byte in the page whose
+	 * notification we are adjusting.
+	 */
+	uint64_t index;
+	/* Action(s) to take on unmap */
+	uint32_t action;
+	/* Event channel to notify */
+	uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+#endif /* __LINUX_PUBLIC_GNTDEV_H__ */
diff --git a/tools/libvchan/init.c b/tools/libvchan/init.c
new file mode 100644
index 0000000..0cf00e2
--- /dev/null
+++ b/tools/libvchan/init.c
@@ -0,0 +1,456 @@
+/**
+ * @file
+ * @section AUTHORS
+ *
+ * Copyright (C) 2010  Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *
+ *  Authors:
+ *       Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *       Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * @section LICENSE
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ *  This file contains the setup code used to establish the ring buffer.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/user.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <xs.h>
+#include <xen/sys/evtchn.h>
+
+#include "libvchan.h"
+#include "gntalloc.h"
+#include "gntdev.h"
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT 12
+#endif
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define max(a,b) ((a > b) ? a : b)
+
+static int init_gnt_srv(struct libvchan *ctrl)
+{
+	int pages_left = ctrl->read.order >= PAGE_SHIFT ? 1 << (ctrl->read.order - PAGE_SHIFT) : 0;
+	int pages_right = ctrl->write.order >= PAGE_SHIFT ? 1 << (ctrl->write.order - PAGE_SHIFT) : 0;
+
+	int ring_fd = open("/dev/xen/gntalloc", O_RDWR);
+	int ring_ref = -1;
+	if (ring_fd < 0)
+		return -1;
+	struct ioctl_gntalloc_alloc_gref *gref_info = malloc(
+		sizeof(struct ioctl_gntalloc_alloc_gref) + max(pages_left, pages_right)*sizeof(uint32_t));
+
+	gref_info->domid = ctrl->other_domain_id;
+	gref_info->flags = GNTALLOC_FLAG_WRITABLE;
+	gref_info->count = 1;
+
+	int err = ioctl(ring_fd, IOCTL_GNTALLOC_ALLOC_GREF, gref_info);
+	if (err)
+		goto out;
+
+	void* ring = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, ring_fd, gref_info->index);
+
+	if (ring == MAP_FAILED)
+		goto out;
+
+	ctrl->ring = ring;
+	ring_ref = gref_info->gref_ids[0];
+
+	memset(ring, 0, PAGE_SIZE);
+
+	ctrl->read.shr = &ctrl->ring->left;
+	ctrl->write.shr = &ctrl->ring->right;
+	ctrl->ring->left_order = ctrl->read.order;
+	ctrl->ring->right_order = ctrl->write.order;
+	ctrl->ring->cli_live = 2;
+	ctrl->ring->srv_live = 1;
+	ctrl->ring->debug = 0xabcd;
+
+#ifdef IOCTL_GNTALLOC_SET_UNMAP_NOTIFY
+	{
+		struct ioctl_gntalloc_unmap_notify arg;
+		arg.index = gref_info->index + offsetof(struct vchan_interface, srv_live);
+		arg.action = UNMAP_NOTIFY_CLEAR_BYTE | UNMAP_NOTIFY_SEND_EVENT;
+		arg.event_channel_port = ctrl->event_port;
+		ioctl(ring_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &arg);
+	}
+#endif
+
+	if (ctrl->read.order == 10) {
+		ctrl->read.buffer = ((void*)ctrl->ring) + 1024;
+	} else if (ctrl->read.order == 11) {
+		ctrl->read.buffer = ((void*)ctrl->ring) + 2048;
+	} else {
+		gref_info->count = pages_left;
+		err = ioctl(ring_fd, IOCTL_GNTALLOC_ALLOC_GREF, gref_info);
+		if (err)
+			goto out_ring;
+		void* area = mmap(NULL, pages_left * PAGE_SIZE, PROT_READ | PROT_WRITE,
+			MAP_SHARED, ring_fd, gref_info->index);
+		if (area == MAP_FAILED)
+			goto out_ring;
+		ctrl->read.buffer = area;
+		memcpy(ctrl->ring->grants, gref_info->gref_ids, pages_left * sizeof(uint32_t));
+	}
+
+	if (ctrl->write.order == 10) {
+		ctrl->write.buffer = ((void*)ctrl->ring) + 1024;
+	} else if (ctrl->write.order == 11) {
+		ctrl->write.buffer = ((void*)ctrl->ring) + 2048;
+	} else {
+		gref_info->count = pages_right;
+		err = ioctl(ring_fd, IOCTL_GNTALLOC_ALLOC_GREF, gref_info);
+		if (err)
+			goto out_unmap_left;
+		void* area = mmap(NULL, pages_right * PAGE_SIZE, PROT_READ | PROT_WRITE,
+			MAP_SHARED, ring_fd, gref_info->index);
+		if (area == MAP_FAILED)
+			goto out_unmap_left;
+		ctrl->write.buffer = area;
+		memcpy(ctrl->ring->grants + (pages_left * sizeof(uint32_t)),
+		       gref_info->gref_ids, pages_right * sizeof(uint32_t));
+	}
+
+out:
+	close(ring_fd);
+	return ring_ref;
+out_unmap_left:
+	munmap(ctrl->read.buffer, pages_left * PAGE_SIZE);
+out_ring:
+	munmap(ring, PAGE_SIZE);
+	ring_ref = -1;
+	ctrl->ring = NULL;
+	ctrl->write.order = ctrl->read.order = 0;
+	goto out;
+}
+
+static void* do_gnt_map(int fd, int domid, uint32_t* pages, size_t npages, uint64_t *index)
+{
+	int i, rv;
+	void* area = NULL;
+	struct ioctl_gntdev_map_grant_ref *gref_info;
+	gref_info = malloc(sizeof(*gref_info) + npages*sizeof(gref_info->refs[0]));
+	gref_info->count = npages;
+	for(i=0; i < npages; i++) {
+		gref_info->refs[i].domid = domid;
+		gref_info->refs[i].ref = pages[i];
+	}
+
+	rv = ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, gref_info);
+	if (rv)
+		goto out;
+	if (index)
+		*index = gref_info->index;
+	area = mmap(NULL, PAGE_SIZE * npages, PROT_READ | PROT_WRITE, MAP_SHARED, fd, gref_info->index);
+	if (area == MAP_FAILED) {
+		struct ioctl_gntdev_unmap_grant_ref undo = {
+			.index = gref_info->index,
+			.count = gref_info->count
+		};
+		ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &undo);
+		area = NULL;
+	}
+ out:
+	free(gref_info);
+	return area;
+}
+
+static int init_gnt_cli(struct libvchan *ctrl, uint32_t ring_ref)
+{
+	int ring_fd = open("/dev/xen/gntdev", O_RDWR);
+	int rv = -1;
+	uint64_t ring_index;
+	if (ring_fd < 0)
+		return -1;
+
+	ctrl->ring = do_gnt_map(ring_fd, ctrl->other_domain_id, &ring_ref, 1, &ring_index);
+
+	if (!ctrl->ring)
+		goto out;
+
+	ctrl->write.order = ctrl->ring->left_order;
+	ctrl->read.order = ctrl->ring->right_order;
+	ctrl->write.shr = &ctrl->ring->left;
+	ctrl->read.shr = &ctrl->ring->right;
+	if (ctrl->write.order < 10 || ctrl->write.order > 24)
+		goto out_unmap_ring;
+	if (ctrl->read.order < 10 || ctrl->read.order > 24)
+		goto out_unmap_ring;
+	if (ctrl->read.order == ctrl->write.order && ctrl->read.order < 12)
+		goto out_unmap_ring;
+
+	uint32_t* grants = ctrl->ring->grants;
+
+	if (ctrl->write.order == 10) {
+		ctrl->write.buffer = ((void*)ctrl->ring) + 1024;
+	} else if (ctrl->write.order == 11) {
+		ctrl->write.buffer = ((void*)ctrl->ring) + 2048;
+	} else {
+		int pages_left = 1 << (ctrl->write.order - PAGE_SHIFT);
+		ctrl->write.buffer = do_gnt_map(ring_fd, ctrl->other_domain_id, grants, pages_left, NULL);
+		if (!ctrl->write.buffer)
+			goto out_unmap_ring;
+		grants += pages_left;
+	}
+
+	if (ctrl->read.order == 10) {
+		ctrl->read.buffer = ((void*)ctrl->ring) + 1024;
+	} else if (ctrl->read.order == 11) {
+		ctrl->read.buffer = ((void*)ctrl->ring) + 2048;
+	} else {
+		int pages_right = 1 << (ctrl->read.order - PAGE_SHIFT);
+		ctrl->read.buffer = do_gnt_map(ring_fd, ctrl->other_domain_id, grants, pages_right, NULL);
+		if (!ctrl->read.buffer)
+			goto out_unmap_left;
+	}
+
+#ifdef IOCTL_GNTDEV_SET_UNMAP_NOTIFY
+	{
+		struct ioctl_gntdev_unmap_notify arg;
+		arg.index = ring_index + offsetof(struct vchan_interface, cli_live);
+		arg.action = UNMAP_NOTIFY_CLEAR_BYTE | UNMAP_NOTIFY_SEND_EVENT;
+		arg.event_channel_port = ctrl->event_port;
+		ioctl(ring_fd, IOCTL_GNTDEV_SET_UNMAP_NOTIFY, &arg);
+	}
+#endif
+
+	rv = 0;
+ out:
+	close(ring_fd);
+	return rv;
+ out_unmap_left:
+	if (ctrl->write.order >= PAGE_SHIFT)
+		munmap(ctrl->write.buffer, 1 << ctrl->write.order);
+ out_unmap_ring:
+	munmap(ctrl->ring, PAGE_SIZE);
+	ctrl->ring = 0;
+	ctrl->write.order = ctrl->read.order = 0;
+	rv = -1;
+	goto out;
+}
+
+static int init_evt_srv(struct libvchan *ctrl)
+{
+	struct ioctl_evtchn_bind_unbound_port bind;
+	ctrl->event_fd = open("/dev/xen/evtchn", O_RDWR);
+	if (ctrl->event_fd < 0)
+		return -1;
+	bind.remote_domain = ctrl->other_domain_id;
+	ctrl->event_port = ioctl(ctrl->event_fd, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
+	if (ctrl->event_port < 0)
+		return -1;
+	write(ctrl->event_fd, &ctrl->event_port, sizeof(ctrl->event_port));
+	return 0;
+}
+
+static int init_xs_srv(struct libvchan *ctrl, int ring_ref)
+{
+	int ret = -1;
+	struct xs_handle *xs;
+	struct xs_permissions perms[2];
+	char buf[64];
+	char ref[16];
+	char* domid_str = NULL;
+	xs = xs_domain_open();
+	if (!xs)
+		goto fail;
+	domid_str = xs_read(xs, 0, "domid", NULL);
+	if (!domid_str)
+		goto fail_xs_open;
+
+	// owner domain is us
+	perms[0].id = atoi(domid_str);
+	// permissions for domains not listed = none
+	perms[0].perms = XS_PERM_NONE;
+	// other domains
+	perms[1].id = ctrl->other_domain_id;
+	perms[1].perms = XS_PERM_READ;
+
+	snprintf(ref, sizeof ref, "%d", ring_ref);
+	snprintf(buf, sizeof buf, "data/vchan/%d/ring-ref", ctrl->device_number);
+	if (!xs_write(xs, 0, buf, ref, strlen(ref)))
+		goto fail_xs_open;
+	if (!xs_set_permissions(xs, 0, buf, perms, 2))
+		goto fail_xs_open;
+
+	snprintf(ref, sizeof ref, "%d", ctrl->event_port);
+	snprintf(buf, sizeof buf, "data/vchan/%d/event-channel", ctrl->device_number);
+	if (!xs_write(xs, 0, buf, ref, strlen(ref)))
+		goto fail_xs_open;
+	if (!xs_set_permissions(xs, 0, buf, perms, 2))
+		goto fail_xs_open;
+
+	ret = 0;
+ fail_xs_open:
+	free(domid_str);
+	xs_daemon_close(xs);
+ fail:
+	return ret;
+}
+
+static int min_order(size_t siz)
+{
+	int rv = PAGE_SHIFT;
+	while (siz > (1 << rv))
+		rv++;
+	return rv;
+}
+
+struct libvchan *libvchan_server_init(int domain, int devno, size_t left_min, size_t right_min)
+{
+	// if you go over this size, you'll have too many grants to fit in the shared page.
+	size_t MAX_RING_SIZE = 256 * PAGE_SIZE;
+	if (left_min > MAX_RING_SIZE || right_min > MAX_RING_SIZE)
+		return 0;
+
+	struct libvchan *ctrl = malloc(sizeof(struct libvchan));
+	if (!ctrl)
+		return 0;
+
+	ctrl->other_domain_id = domain;
+	ctrl->device_number = devno;
+	ctrl->ring = NULL;
+	ctrl->event_fd = -1;
+	ctrl->is_server = 1;
+	ctrl->server_persist = 0;
+
+	ctrl->read.order = min_order(left_min);
+	ctrl->write.order = min_order(right_min);
+
+	// if we can avoid allocating extra pages by using in-page rings, do so
+#define MAX_SMALL_RING 1024
+#define MAX_LARGE_RING 2048
+	if (left_min <= MAX_SMALL_RING && right_min <= MAX_LARGE_RING) {
+		ctrl->read.order = 10;
+		ctrl->write.order = 11;
+	} else if (left_min <= MAX_LARGE_RING && right_min <= MAX_SMALL_RING) {
+		ctrl->read.order = 11;
+		ctrl->write.order = 10;
+	} else if (left_min <= MAX_LARGE_RING) {
+		ctrl->read.order = 11;
+	} else if (right_min <= MAX_LARGE_RING) {
+		ctrl->write.order = 11;
+	}
+	if (init_evt_srv(ctrl))
+		goto out;
+	int ring_ref = init_gnt_srv(ctrl);
+	if (ring_ref < 0)
+		goto out;
+	if (init_xs_srv(ctrl, ring_ref))
+		goto out;
+	return ctrl;
+out:
+	libvchan_close(ctrl);
+	return 0;
+}
+
+static int init_evt_cli(struct libvchan *ctrl)
+{
+	struct ioctl_evtchn_bind_interdomain bind;
+	ctrl->event_fd = open("/dev/xen/evtchn", O_RDWR);
+	if (ctrl->event_fd < 0)
+		return -1;
+
+	bind.remote_domain = ctrl->other_domain_id;
+	bind.remote_port = ctrl->event_port;
+	ctrl->event_port = ioctl(ctrl->event_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
+	if (ctrl->event_port < 0)
+		return -1;
+	return 0;
+}
+
+
+struct libvchan *libvchan_client_init(int domain, int devno)
+{
+	struct libvchan *ctrl = malloc(sizeof(struct libvchan));
+	struct xs_handle *xs = NULL;
+	char buf[64];
+	char *ref;
+	int ring_ref;
+	unsigned int len;
+	if (!ctrl)
+		return 0;
+	ctrl->other_domain_id = domain;
+	ctrl->device_number = devno;
+	ctrl->ring = NULL;
+	ctrl->event_fd = -1;
+	ctrl->write.order = ctrl->read.order = 0;
+	ctrl->is_server = 0;
+
+	xs = xs_daemon_open();
+	if (!xs)
+		xs = xs_domain_open();
+	if (!xs)
+		goto fail;
+
+// find xenstore entry
+	snprintf(buf, sizeof buf, "/local/domain/%d/data/vchan/%d/ring-ref",
+		ctrl->other_domain_id, ctrl->device_number);
+	ref = xs_read(xs, 0, buf, &len);
+	if (!ref)
+		goto fail;
+	ring_ref = atoi(ref);
+	free(ref);
+	if (!ring_ref)
+		goto fail;
+	snprintf(buf, sizeof buf, "/local/domain/%d/data/vchan/%d/event-channel",
+		ctrl->other_domain_id, ctrl->device_number);
+	ref = xs_read(xs, 0, buf, &len);
+	if (!ref)
+		goto fail;
+	ctrl->event_port = atoi(ref);
+	free(ref);
+	if (!ctrl->event_port)
+		goto fail;
+
+// set up event channel
+	if (init_evt_cli(ctrl))
+		goto fail;
+
+// set up shared page(s)
+	if (init_gnt_cli(ctrl, ring_ref))
+		goto fail;
+
+	ctrl->ring->cli_live = 1;
+	ctrl->ring->debug = 0xabce;
+
+ out:
+	if (xs)
+		xs_daemon_close(xs);
+	return ctrl;
+ fail:
+	libvchan_close(ctrl);
+	ctrl = NULL;
+	goto out;
+}
diff --git a/tools/libvchan/io.c b/tools/libvchan/io.c
new file mode 100644
index 0000000..f95c7b0
--- /dev/null
+++ b/tools/libvchan/io.c
@@ -0,0 +1,270 @@
+/**
+ * @file
+ * @section AUTHORS
+ *
+ * Copyright (C) 2010  Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *
+ *  Authors:
+ *       Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *       Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * @section LICENSE
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ *  This file contains the communications interface built on the ring buffer.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <xenctrl.h>
+
+#include "libvchan.h"
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT 12
+#endif
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+// allow vchan data to be easily observed in strace by doing a
+// writev() to FD -1 with the data being read/written.
+#ifndef VCHAN_DEBUG
+#define VCHAN_DEBUG 0
+#endif
+
+static uint32_t rd_prod(struct libvchan *ctrl)
+{
+	return ctrl->read.shr->prod;
+}
+
+static uint32_t* _rd_cons(struct libvchan *ctrl)
+{
+	return &ctrl->read.shr->cons;
+}
+#define rd_cons(x) (*_rd_cons(x))
+
+static uint32_t* _wr_prod(struct libvchan *ctrl)
+{
+	return &ctrl->write.shr->prod;
+}
+#define wr_prod(x) (*_wr_prod(x))
+
+static uint32_t wr_cons(struct libvchan *ctrl)
+{
+	return ctrl->write.shr->cons;
+}
+
+static const void* rd_ring(struct libvchan *ctrl)
+{
+	return ctrl->read.buffer;
+}
+
+static void* wr_ring(struct libvchan *ctrl)
+{
+	return ctrl->write.buffer;
+}
+
+static uint32_t wr_ring_size(struct libvchan *ctrl)
+{
+	return (1 << ctrl->write.order);
+}
+
+static uint32_t rd_ring_size(struct libvchan *ctrl)
+{
+	return (1 << ctrl->read.order);
+}
+
+int libvchan_data_ready(struct libvchan *ctrl)
+{
+	return rd_prod(ctrl) - rd_cons(ctrl);
+}
+
+int libvchan_buffer_space(struct libvchan *ctrl)
+{
+	return wr_ring_size(ctrl) - (wr_prod(ctrl) - wr_cons(ctrl));
+}
+
+static int do_notify(struct libvchan *ctrl)
+{
+	struct ioctl_evtchn_notify notify;
+	notify.port = ctrl->event_port;
+	return ioctl(ctrl->event_fd, IOCTL_EVTCHN_NOTIFY, &notify);
+}
+
+int libvchan_wait(struct libvchan *ctrl)
+{
+	int ret;
+	uint32_t dummy;
+	ret = read(ctrl->event_fd, &dummy, sizeof(dummy));
+	if (ret == -1)
+		return -1;
+	write(ctrl->event_fd, &dummy, sizeof(dummy));
+	return 0;
+}
+
+/**
+ * returns -1 on error, or size on success
+ */
+static int do_send(struct libvchan *ctrl, const void *data, size_t size)
+{
+	int real_idx = wr_prod(ctrl) & (wr_ring_size(ctrl) - 1);
+	int avail_contig = wr_ring_size(ctrl) - real_idx;
+	if (VCHAN_DEBUG) {
+		char metainfo[32];
+		struct iovec iov[2];
+		iov[0].iov_base = metainfo;
+		iov[0].iov_len = snprintf(metainfo, 32, "vchan wr %d/%d", ctrl->other_domain_id, ctrl->device_number);
+		iov[1].iov_base = (void *)data;
+		iov[1].iov_len = size;
+		writev(-1, iov, 2);
+	}
+	if (avail_contig > size)
+		avail_contig = size;
+	memcpy(wr_ring(ctrl) + real_idx, data, avail_contig);
+	if (avail_contig < size)
+	{
+		// we rolled across the end of the ring
+		memcpy(wr_ring(ctrl), data + avail_contig, size - avail_contig);
+	}
+	wr_prod(ctrl) += size;
+	if (do_notify(ctrl) < 0)
+		return -1;
+	return size;
+}
+
+/**
+ * returns 0 if no buffer space is available, -1 on error, or size on success
+ */
+int libvchan_send(struct libvchan *ctrl, const void *data, size_t size)
+{
+	int avail = libvchan_buffer_space(ctrl);
+	if (!libvchan_is_open(ctrl))
+		return -1;
+	if (size > avail)
+		return 0;
+	return do_send(ctrl, data, size);
+}
+
+int libvchan_write(struct libvchan *ctrl, const void *data, size_t size)
+{
+	int avail = libvchan_buffer_space(ctrl);
+	if (!libvchan_is_open(ctrl))
+		return -1;
+	if (size > avail)
+		size = avail;
+	return do_send(ctrl, data, size);
+}
+
+static int do_recv(struct libvchan *ctrl, void *data, size_t size)
+{
+	int real_idx = rd_cons(ctrl) & (rd_ring_size(ctrl) - 1);
+	int avail_contig = rd_ring_size(ctrl) - real_idx;
+	if (avail_contig > size)
+		avail_contig = size;
+	memcpy(data, rd_ring(ctrl) + real_idx, avail_contig);
+	if (avail_contig < size)
+	{
+		// we rolled across the end of the ring
+		memcpy(data + avail_contig, rd_ring(ctrl), size - avail_contig);
+	}
+	rd_cons(ctrl) += size;
+	if (VCHAN_DEBUG) {
+		char metainfo[32];
+		struct iovec iov[2];
+		iov[0].iov_base = metainfo;
+		iov[0].iov_len = snprintf(metainfo, 32, "vchan rd %d/%d", ctrl->other_domain_id, ctrl->device_number);
+		iov[1].iov_base = data;
+		iov[1].iov_len = size;
+		writev(-1, iov, 2);
+	}
+	if (do_notify(ctrl) < 0)
+		return -1;
+	return size;
+}
+
+/**
+ * reads exactly size bytes from the vchan.
+ * returns 0 if insufficient data is available, -1 on error, or size on success
+ */
+int libvchan_recv(struct libvchan *ctrl, void *data, size_t size)
+{
+	int avail = libvchan_data_ready(ctrl);
+	if (size <= avail)
+		return do_recv(ctrl, data, size);
+	else if (libvchan_is_open(ctrl))
+		return 0;
+	else
+		return -1;
+}
+
+int libvchan_read(struct libvchan *ctrl, void *data, size_t size)
+{
+	int avail = libvchan_data_ready(ctrl);
+	if (size > avail)
+		size = avail;
+	if (avail)
+		return do_recv(ctrl, data, size);
+	else if (libvchan_is_open(ctrl))
+		return 0;
+	else
+		return -1;
+}
+
+int libvchan_is_open(struct libvchan* ctrl)
+{
+	if (ctrl->is_server)
+		return ctrl->server_persist || ctrl->ring->cli_live;
+	else
+		return ctrl->ring->srv_live;
+}
+
+/// The fd to use for select() set
+int libvchan_fd_for_select(struct libvchan *ctrl)
+{
+	return ctrl->event_fd;
+}
+
+void libvchan_close(struct libvchan *ctrl)
+{
+	if (!ctrl)
+		return;
+	if (ctrl->ring) {
+		if (ctrl->is_server)
+			ctrl->ring->srv_live = 0;
+		else
+			ctrl->ring->cli_live = 0;
+		munmap(ctrl->ring, PAGE_SIZE);
+	}
+	if (ctrl->event_fd != -1) {
+		if (ctrl->event_port > 0 && ctrl->ring)
+			do_notify(ctrl);
+		close(ctrl->event_fd);
+	}
+	if (ctrl->read.order >= PAGE_SHIFT)
+		munmap(ctrl->read.buffer, 1 << ctrl->read.order);
+	if (ctrl->write.order >= PAGE_SHIFT)
+		munmap(ctrl->write.buffer, 1 << ctrl->write.order);
+	free(ctrl);
+}
diff --git a/tools/libvchan/libvchan.h b/tools/libvchan/libvchan.h
new file mode 100644
index 0000000..a6c08f4
--- /dev/null
+++ b/tools/libvchan/libvchan.h
@@ -0,0 +1,141 @@
+/**
+ * @file
+ * @section AUTHORS
+ *
+ * Copyright (C) 2010  Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *
+ *  Authors:
+ *       Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *       Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * @section LICENSE
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ *  Originally borrowed from the Qubes OS Project, http://www.qubes-os.org,
+ *  this code has been substantially rewritten to use the gntdev and gntalloc
+ *  devices instead of raw MFN's and map_foreign_range.
+ *
+ *  This is a library for inter-domain communication.  A standard Xen ring
+ *  buffer is used, with a datagram-based interface built on top.  The grant
+ *  reference is expected to be shared through some out-of-band mechanism
+ *  such as XenStore.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <xen/sys/evtchn.h>
+
+struct ring_shared {
+	uint32_t cons, prod;
+};
+
+/// struct vchan_interface is placed in memory shared between domains
+struct vchan_interface {
+	// standard consumer/producer interface, one pair per buffer
+	// left is client write, server read
+	// right is client read, server write
+	struct ring_shared left, right;
+	// size of the rings, which determines their location
+	// 10   - at offset 1024 in ring's page
+	// 11   - at offset 2048 in ring's page
+	// 12+  - uses 2^(N-12) grants to describe the multi-page ring
+	// These should remain constant once the page is shared.
+	// Only one of the two orders can be 10 (or 11).
+	uint16_t left_order, right_order;
+	// Shutdown detection
+	uint8_t cli_live, srv_live;
+	uint16_t debug;
+	// Grant list: ordering is left, right. Must not extend into actual ring
+	// or grow beyond the end of the initial shared page.
+	// These should remain constant once the page is shared, to allow
+	// for possible remapping by a client that restarts.
+	uint32_t grants[0];
+};
+
+struct libvchan_ring {
+	// Pointer into the shared page. Offsets into buffer
+	struct ring_shared* shr;
+	// ring data
+	void* buffer;
+	// size of the ring is (1 << order).
+	// This is used to constrain offsets to the buffer.
+	// (we can't trust the order in the shared page to remain constant)
+	int order;
+};
+
+/// struct libvchan is a control structure, passed to all library calls
+struct libvchan {
+	// person we communicate with
+	int other_domain_id;
+	// "port" we communicate on (allows multiple vchans to exist in xenstore)
+	int device_number;
+	// Shared ring page, mapped using gntdev or gntalloc
+	// Note that the FD for gntdev or gntalloc has already been closed.
+	struct vchan_interface *ring;
+	// event channel interface (needs port for API)
+	int event_fd;
+	uint32_t event_port;
+	// informative flag
+	int is_server:1;
+	int server_persist:1;
+	struct libvchan_ring read, write;
+};
+
+/**
+ * Set up a vchan, including granting pages
+ * @param domain The peer domain that will be connecting
+ * @param devno A device number, used to identify this vchan in xenstore
+ * @param send_min The minimum size (in bytes) of the send ring (left)
+ * @param recv_min The minimum size (in bytes) of the receive ring (right)
+ * @return The structure, or NULL in case of an error
+ */
+struct libvchan *libvchan_server_init(int domain, int devno, size_t read_min, size_t write_min);
+/** 
+ * Connect to an existing vchan. Note: you can reconnect to an existing vchan
+ * safely, however no locking is performed, so you must prevent multiple clients
+ * from connecting to a single server.
+ *
+ * @param domain The peer domain to connect to
+ * @param devno A device number, used to identify this vchan in xenstore
+ * @return The structure, or NULL in case of an error
+ */
+struct libvchan *libvchan_client_init(int domain, int devno);
+/**
+ * Close a vchan. This deallocates the vchan and attempts to free its
+ * resources. The other side is notified of the close, but can still read any
+ * data pending prior to the close.
+ */
+void libvchan_close(struct libvchan *ctrl);
+
+// reads exactly size or aborts
+int libvchan_recv(struct libvchan *ctrl, void *data, size_t size);
+// reads up to size bytes (including zero) without blocking
+int libvchan_read(struct libvchan *ctrl, void *data, size_t size);
+// sends entire buffer or aborts
+int libvchan_send(struct libvchan *ctrl, const void *data, size_t size);
+// sends as much data as possible without blocking
+int libvchan_write(struct libvchan *ctrl, const void *data, size_t size);
+// waits for reads or writes to unblock, or for a close
+int libvchan_wait(struct libvchan *ctrl);
+// (only) when this FD is readable, libvchan_wait() will not block
+int libvchan_fd_for_select(struct libvchan *ctrl);
+// return 0 when one side has called libvchan_close() or crashed
+// return 1 when both sides are open
+// return 2 [server only] when no client has yet connected
+int libvchan_is_open(struct libvchan* ctrl);
+int libvchan_data_ready(struct libvchan *ctrl);
+int libvchan_buffer_space(struct libvchan *ctrl);
diff --git a/tools/libvchan/node-select.c b/tools/libvchan/node-select.c
new file mode 100644
index 0000000..a7c614b
--- /dev/null
+++ b/tools/libvchan/node-select.c
@@ -0,0 +1,161 @@
+/**
+ * @file
+ * @section AUTHORS
+ *
+ * Copyright (C) 2010  Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *
+ *  Authors:
+ *       Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *       Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * @section LICENSE
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * This is a test program for libvchan.  Communications are bidirectional,
+ * with either server (grant offeror) or client able to read and write.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "libvchan.h"
+
+void usage(char** argv)
+{
+	fprintf(stderr, "usage:\n"
+		"\t%s [client|server] domainid nodeid [rbufsiz wbufsiz]\n",
+		argv[0]);
+	exit(1);
+}
+
+#define BUFSIZE 5000
+char inbuf[BUFSIZE];
+char outbuf[BUFSIZE];
+int insiz = 0;
+int outsiz = 0;
+struct libvchan *ctrl = 0;
+
+void vchan_wr() {
+	if (!insiz)
+		return;
+	int ret = libvchan_write(ctrl, inbuf, insiz);
+	if (ret < 0) {
+		fprintf(stderr, "vchan write failed\n");
+		exit(1);
+	}
+	if (ret > 0) {
+		insiz -= ret;
+		memmove(inbuf, inbuf + ret, insiz);
+	}
+}
+
+void stdout_wr() {
+	if (!outsiz)
+		return;
+	int ret = write(1, outbuf, outsiz);
+	if (ret < 0 && errno != EAGAIN)
+		exit(1);
+	if (ret > 0) {
+		outsiz -= ret;
+		memmove(outbuf, outbuf + ret, outsiz);
+	}
+}
+
+/**
+    Simple libvchan application, both client and server.
+	Both sides may write and read, both from the libvchan and from 
+	stdin/stdout (just like netcat).
+*/
+
+int main(int argc, char **argv)
+{
+	int ret;
+	int libvchan_fd;
+	if (argc < 4)
+		usage(argv);
+	if (!strcmp(argv[1], "server")) {
+		int rsiz = argc > 4 ? atoi(argv[4]) : 0;
+		int wsiz = argc > 5 ? atoi(argv[5]) : 0;
+		ctrl = libvchan_server_init(atoi(argv[2]), atoi(argv[3]), rsiz, wsiz);
+	} else if (!strcmp(argv[1], "client"))
+		ctrl = libvchan_client_init(atoi(argv[2]), atoi(argv[3]));
+	else
+		usage(argv);
+	if (!ctrl) {
+		perror("libvchan_*_init");
+		exit(1);
+	}
+
+	fcntl(0, F_SETFL, O_NONBLOCK);
+	fcntl(1, F_SETFL, O_NONBLOCK);
+
+	libvchan_fd = libvchan_fd_for_select(ctrl);
+	for (;;) {
+		fd_set rfds;
+		fd_set wfds;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+		if (insiz != BUFSIZE)
+			FD_SET(0, &rfds);
+		if (outsiz)
+			FD_SET(1, &wfds);
+		FD_SET(libvchan_fd, &rfds);
+		ret = select(libvchan_fd + 1, &rfds, &wfds, NULL, NULL);
+		if (ret < 0) {
+			perror("select");
+			exit(1);
+		}
+		if (FD_ISSET(0, &rfds)) {
+			ret = read(0, inbuf + insiz, BUFSIZE - insiz);
+			if (ret < 0 && errno != EAGAIN)
+				exit(1);
+			if (ret == 0) {
+				while (insiz) {
+					vchan_wr();
+					libvchan_wait(ctrl);
+				}
+				return 0;
+			}
+			if (ret)
+				insiz += ret;
+			vchan_wr();
+		}
+		if (FD_ISSET(libvchan_fd, &rfds)) {
+			libvchan_wait(ctrl);
+			vchan_wr();
+		}
+		if (FD_ISSET(1, &wfds))
+			stdout_wr();
+		while (libvchan_data_ready(ctrl) && outsiz < BUFSIZE) {
+			ret = libvchan_read(ctrl, outbuf + outsiz, BUFSIZE - outsiz);
+			if (ret < 0)
+				exit(1);
+			outsiz += ret;
+			stdout_wr();
+		}
+		if (!libvchan_is_open(ctrl)) {
+			fcntl(1, F_SETFL, 0);
+			while (outsiz)
+				stdout_wr();
+			return 0;
+		}
+	}
+}
diff --git a/tools/libvchan/node.c b/tools/libvchan/node.c
new file mode 100644
index 0000000..d00a50f
--- /dev/null
+++ b/tools/libvchan/node.c
@@ -0,0 +1,169 @@
+/**
+ * @file
+ * @section AUTHORS
+ *
+ * Copyright (C) 2010  Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *
+ *  Authors:
+ *       Rafal Wojtczuk  <rafal@invisiblethingslab.com>
+ *       Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * @section LICENSE
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * @section DESCRIPTION
+ *
+ * This is a test program for libvchan.  Communications are in one direction,
+ * either server (grant offeror) to client or vice versa.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "libvchan.h"
+
+int libvchan_write_all(struct libvchan *ctrl, char *buf, int size)
+{
+	int written = 0;
+	int ret;
+	while (written < size) {
+		ret = libvchan_write(ctrl, buf + written, size - written);
+		if (ret <= 0) {
+			perror("write");
+			exit(1);
+		}
+		written += ret;
+	}
+	return size;
+}
+
+int write_all(int fd, char *buf, int size)
+{
+	int written = 0;
+	int ret;
+	while (written < size) {
+		ret = write(fd, buf + written, size - written);
+		if (ret <= 0) {
+			perror("write");
+			exit(1);
+		}
+		written += ret;
+	}
+	return size;
+}
+
+void usage(char** argv)
+{
+	fprintf(stderr, "usage:\n"
+		"%s [client|server] [read|write] domid nodeid\n", argv[0]);
+	exit(1);
+}
+
+#define BUFSIZE 5000
+char buf[BUFSIZE];
+void reader(struct libvchan *ctrl)
+{
+	int size;
+	for (;;) {
+		size = rand() % (BUFSIZE - 1) + 1;
+		size = libvchan_read(ctrl, buf, size);
+		fprintf(stderr, "#");
+		if (size < 0) {
+			perror("read vchan");
+			libvchan_close(ctrl);
+			exit(1);
+		}
+		if (size == 0)
+			break;
+		size = write_all(1, buf, size);
+		if (size < 0) {
+			perror("stdout write");
+			exit(1);
+		}
+		if (size == 0) {
+			perror("write size=0?\n");
+			exit(1);
+		}
+	}
+}
+
+void writer(struct libvchan *ctrl)
+{
+	int size;
+	for (;;) {
+		size = rand() % (BUFSIZE - 1) + 1;
+		size = read(0, buf, size);
+		if (size < 0) {
+			perror("read stdin");
+			libvchan_close(ctrl);
+			exit(1);
+		}
+		if (size == 0)
+			break;
+		size = libvchan_write_all(ctrl, buf, size);
+		fprintf(stderr, "#");
+		if (size < 0) {
+			perror("vchan write");
+			exit(1);
+		}
+		if (size == 0) {
+			perror("write size=0?\n");
+			exit(1);
+		}
+	}
+}
+
+
+/**
+	Simple libvchan application, both client and server.
+	One side does writing, the other side does reading; both from
+	standard input/output fds.
+*/
+int main(int argc, char **argv)
+{
+	int seed = time(0);
+	struct libvchan *ctrl = 0;
+	int wr;
+	if (argc < 4)
+		usage(argv);
+	if (!strcmp(argv[2], "read"))
+		wr = 0;
+	else if (!strcmp(argv[2], "write"))
+		wr = 1;
+	else
+		usage(argv);
+	if (!strcmp(argv[1], "server"))
+		ctrl = libvchan_server_init(atoi(argv[3]), atoi(argv[4]), 0, 0);
+	else if (!strcmp(argv[1], "client"))
+		ctrl = libvchan_client_init(atoi(argv[3]), atoi(argv[4]));
+	else
+		usage(argv);
+	if (!ctrl) {
+		perror("libvchan_*_init");
+		exit(1);
+	}
+
+	srand(seed);
+	fprintf(stderr, "seed=%d\n", seed);
+	if (wr)
+		writer(ctrl);
+	else
+		reader(ctrl);
+	libvchan_close(ctrl);
+	return 0;
+}
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 61+ messages in thread

end of thread, other threads:[~2011-12-01 18:20 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-19 14:38 [PATCH] libvchan: interdomain communications library Daniel De Graaf
2011-08-22  7:40 ` Vasiliy G Tolstov
2011-08-24 19:28   ` Konrad Rzeszutek Wilk
2011-08-22  9:15 ` Ian Campbell
2011-08-24 18:52   ` Daniel De Graaf
2011-08-25 10:27     ` Tim Deegan
2011-08-25 18:36       ` Jeremy Fitzhardinge
2011-08-24 18:52   ` [PATCH v2] " Daniel De Graaf
2011-08-26 14:01     ` Ian Jackson
2011-08-29 18:48       ` [PATCH v3] " Daniel De Graaf
2011-08-30 10:32         ` Ian Campbell
2011-08-31 19:17           ` Daniel De Graaf
2011-09-01 16:28             ` Ian Campbell
2011-09-01 16:47               ` Daniel De Graaf
2011-09-01 16:56                 ` Ian Jackson
2011-09-01 17:46                   ` Daniel De Graaf
2011-09-01 16:22 ` [PATCH v4 0/3] " Daniel De Graaf
2011-09-01 16:22   ` [PATCH 1/3] libxc: add xc_gnttab_map_grant_ref_notify Daniel De Graaf
2011-09-01 19:29     ` Konrad Rzeszutek Wilk
2011-09-01 16:22   ` [PATCH 2/3] libxc: add xc_gntshr_* functions Daniel De Graaf
2011-09-01 19:24     ` Konrad Rzeszutek Wilk
2011-09-01 16:22   ` [PATCH 3/3] libvchan: interdomain communications library Daniel De Graaf
2011-09-19 22:43 ` [PATCH v5 0/3] Daniel De Graaf
2011-09-19 22:43   ` [PATCH 1/3] libxc: add xc_gnttab_map_grant_ref_notify Daniel De Graaf
2011-09-21 10:03     ` Ian Campbell
2011-09-21 15:02       ` Daniel De Graaf
2011-09-21 15:25         ` Ian Campbell
2011-09-21 17:07           ` Daniel De Graaf
2011-09-22  8:32             ` Ian Campbell
2011-09-22 18:09               ` Daniel De Graaf
2011-09-19 22:43   ` [PATCH 2/3] libxc: add xc_gntshr_* functions Daniel De Graaf
2011-09-21 10:13     ` Ian Campbell
2011-09-19 22:43   ` [PATCH 3/3] libvchan: interdomain communications library Daniel De Graaf
2011-09-21 10:53     ` Ian Campbell
2011-09-21 16:31       ` Daniel De Graaf
2011-09-22  8:18         ` Ian Campbell
2011-09-21 13:44     ` Ian Campbell
2011-09-22 22:14 ` [PATCH v6 0/3] libxenvchan: " Daniel De Graaf
2011-09-22 22:14   ` [PATCH 1/3] libxc: add xc_gnttab_map_grant_ref_notify Daniel De Graaf
2011-09-30  9:16     ` Ian Campbell
2011-09-30 14:12       ` Ian Jackson
2011-09-30 14:17         ` Ian Campbell
2011-09-22 22:14   ` [PATCH 2/3] libxc: add xc_gntshr_* functions Daniel De Graaf
2011-09-22 22:14   ` [PATCH 3/3] libvchan: interdomain communications library Daniel De Graaf
2011-09-30  7:51   ` [PATCH v6 0/3] libxenvchan: " Vasiliy Tolstov
2011-09-30  8:28     ` Vasiliy Tolstov
2011-09-30 14:40       ` Daniel De Graaf
2011-11-24 20:02         ` Anil Madhavapeddy
2011-11-25 16:53           ` Daniel De Graaf
2011-11-25 16:54             ` [PATCH] libxc: Fix checks on grant notify arguments Daniel De Graaf
2011-12-01 18:20               ` Ian Jackson
2011-11-25 16:56             ` [PATCH 1/2] xen/events: prevent calling evtchn_get on invlaid channels Daniel De Graaf
2011-11-25 16:56               ` [PATCH 2/2] xen/gntalloc: release grant references on page free Daniel De Graaf
2011-11-25 18:37                 ` [PATCH] xen/gntalloc: fix reference counts on multi-page mappings Daniel De Graaf
2011-09-30  8:34   ` [PATCH v6 0/3] libxenvchan: interdomain communications library Ian Campbell
2011-09-30  8:37     ` [PATCH] libxc: osdep: report missing backends in common code Ian Campbell
2011-10-06 18:44     ` [PATCH v6 0/3] libxenvchan: interdomain communications library Ian Jackson
2011-10-07  8:41       ` Roger Pau Monné
2011-10-07  9:15         ` Keir Fraser
2011-10-07  9:48           ` Ian Jackson
2011-10-07 10:22             ` Roger Pau Monné

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.