Moved vchan and u2mfn code to core.

This commit is contained in:
Rafal Wojtczuk 2011-03-08 12:24:47 +01:00
parent 0d12aeec88
commit f263aa6b7c
15 changed files with 972 additions and 1 deletions

View File

@ -28,3 +28,4 @@ clean:
(cd dom0/qmemman && make clean)
(cd common && make clean)
make -C qrexec clean
make -C vchan clean

View File

@ -1,5 +1,5 @@
CC=gcc
CFLAGS+=-g -Wall
CFLAGS+=-g -Wall -I../vchan
XENLIBS=-lvchan -lxenstore -lxenctrl
all: qrexec_daemon qrexec_agent qrexec_client

View File

@ -61,6 +61,8 @@ fi
make clean all
make -C ../common
make -C ../qrexec
make -C ../vchan
make -C ../u2mfn
%install
@ -98,6 +100,14 @@ cp xorg-preload-apps.conf $RPM_BUILD_ROOT/etc/X11
mkdir -p $RPM_BUILD_ROOT/home_volatile/user
chown 500:500 $RPM_BUILD_ROOT/home_volatile/user
install -D ../vchan/libvchan.h $RPM_BUILD_ROOT/usr/include/libvchan.h
install -D ../u2mfn/u2mfnlib.h $RPM_BUILD_ROOT/usr/include/u2mfnlib.h
install -D ../u2mfn/u2mfn-kernel.h $RPM_BUILD_ROOT/usr/include/u2mfn-kernel.h
install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so
install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so
%triggerin -- initscripts
cp /var/lib/qubes/serial.conf /etc/init/serial.conf
@ -214,3 +224,19 @@ rm -rf $RPM_BUILD_ROOT
%dir /home_volatile
%attr(700,user,user) /home_volatile/user
/etc/X11/xorg-preload-apps.conf
/usr/include/libvchan.h
%{_libdir}/libvchan.so
%{_libdir}/libu2mfn.so
%package devel
Summary: Include files for qubes core libraries
License: GPL v2 only
Group: Development/Sources
%description devel
%files devel
/usr/include/libvchan.h
/usr/include/u2mfnlib.h
/usr/include/u2mfn-kernel.h

View File

@ -50,6 +50,8 @@ python -O -m compileall qvm-core qmemman
make -C restore
make -C ../common
make -C ../qrexec
make -C ../vchan
make -C ../u2mfn
%install
@ -125,6 +127,9 @@ cp pm-utils/02qubes-pause-vms $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
mkdir -p $RPM_BUILD_ROOT/var/log/qubes
mkdir -p $RPM_BUILD_ROOT/var/run/qubes
install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so
install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so
%post
/usr/lib/qubes/qubes_fix_nm_conf.sh
@ -284,3 +289,5 @@ fi
%attr(4750,root,qubes) /usr/lib/qubes/xenfreepages
%attr(2770,root,qubes) %dir /var/log/qubes
%attr(770,root,qubes) %dir /var/run/qubes
%{_libdir}/libvchan.so
%{_libdir}/libu2mfn.so

View File

@ -51,6 +51,8 @@ fi
%build
make -C ../qrexec
make -C ../vchan
make -C ../u2mfn
%install
@ -78,6 +80,9 @@ cp ../common/serial.conf $RPM_BUILD_ROOT/var/lib/qubes/
mkdir -p $RPM_BUILD_ROOT/var/run/qubes
mkdir -p $RPM_BUILD_ROOT/etc/xen/scripts
cp ../common/vif-route-qubes $RPM_BUILD_ROOT/etc/xen/scripts
install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so
install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so
%triggerin -- initscripts
cp /var/lib/qubes/serial.conf /etc/init/serial.conf
@ -186,3 +191,5 @@ rm -rf $RPM_BUILD_ROOT
/sbin/qubes_serial_login
/etc/xen/scripts/vif-route-qubes
%dir /var/run/qubes
%{_libdir}/libvchan.so
%{_libdir}/libu2mfn.so

33
u2mfn/Makefile Normal file
View File

@ -0,0 +1,33 @@
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
#
# 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; either version 2
# of the License, or (at your option) any later version.
#
# 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.
#
#
CC=gcc
CFLAGS=-g -Wall
all: libu2mfn.so
libu2mfn.so : u2mfnlib.o
gcc -shared -o libu2mfn.so u2mfnlib.o
u2mfnlib.o: u2mfnlib.c
gcc -fPIC -Wall -g -c u2mfnlib.c
clean:
rm -f *.o *so *~ libu2mfn.so

26
u2mfn/u2mfn-kernel.h Normal file
View File

@ -0,0 +1,26 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include <linux/ioctl.h>
#define U2MFN_MAGIC 0xf5 // See ioctl-number.txt in kernel docs
#define U2MFN_GET_MFN_FOR_PAGE _IOW (U2MFN_MAGIC, 1, int)
#define U2MFN_GET_LAST_MFN _IO (U2MFN_MAGIC, 2)

75
u2mfn/u2mfnlib.c Normal file
View File

@ -0,0 +1,75 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include "u2mfn-kernel.h"
static int u2mfn_fd = -1;
static int get_fd()
{
if (u2mfn_fd == -1) {
u2mfn_fd = open("/proc/u2mfn", O_RDWR);
if (u2mfn_fd < 0)
return -1;
}
return 0;
}
int u2mfn_get_mfn_for_page(long va, int *mfn)
{
if (get_fd())
return -1;
*mfn = ioctl(u2mfn_fd, U2MFN_GET_MFN_FOR_PAGE, va);
if (*mfn == -1)
return -1;
return 0;
}
int u2mfn_get_last_mfn(int *mfn)
{
if (get_fd())
return -1;
*mfn = ioctl(u2mfn_fd, U2MFN_GET_LAST_MFN, 0);
if (*mfn == -1)
return -1;
return 0;
}
char *u2mfn_alloc_kpage()
{
char *ret;
if (get_fd())
return MAP_FAILED;
ret =
mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, u2mfn_fd, 0);
return ret;
}

24
u2mfn/u2mfnlib.h Normal file
View File

@ -0,0 +1,24 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
int u2mfn_get_mfn_for_page(long va, int *mfn) ;
int u2mfn_get_last_mfn(int *mfn) ;
char *u2mfn_alloc_kpage(void) ;

39
vchan/Makefile Normal file
View File

@ -0,0 +1,39 @@
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
#
# 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; either version 2
# of the License, or (at your option) any later version.
#
# 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.
#
#
CC=gcc
CFLAGS=-g -Wall -I../u2mfn
all: libvchan.so
libvchan.so : init.o io.o
gcc -shared -o libvchan.so init.o io.o -L ../u2mfn -lu2mfn
init.o: init.c
gcc -fPIC -Wall -g -c init.c
io.o: io.c
gcc -fPIC -Wall -g -c io.c
node: node.o libvchan.so
gcc -g -o node node.o -L. -lvchan -lxenctrl -lxenstore
node-select: node-select.o libvchan.so
gcc -g -o node-select node-select.o -L. -lvchan -lxenctrl -lxenstore
clean:
rm -f *.o *so *~ client server node node-select

224
vchan/init.c Normal file
View File

@ -0,0 +1,224 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <malloc.h>
#include <xs.h>
#include <string.h>
#include <xenctrl.h>
#include <unistd.h>
#include <stdlib.h>
#include "libvchan.h"
#include "../u2mfn/u2mfnlib.h"
static int ring_init(struct libvchan *ctrl)
{
int u2mfn = open("/proc/u2mfn", O_RDONLY);
int mfn;
struct vchan_interface *ring;
ring = (struct vchan_interface *) u2mfn_alloc_kpage ();
if (ring == MAP_FAILED)
return -1;
ctrl->ring = ring;
if (u2mfn_get_last_mfn (&mfn) < 0)
return -1;
ctrl->ring_ref = mfn;
close(u2mfn);
ring->cons_in = ring->prod_in = ring->cons_out = ring->prod_out =
0;
ring->server_closed = ring->client_closed = 0;
ring->debug = 0xaabbccdd;
return 0;
}
/**
creates event channel;
creates "ring-ref" and "event-channel" xenstore entries;
waits for connection to event channel from the peer
*/
static int server_interface_init(struct libvchan *ctrl, int devno)
{
int ret = -1;
struct xs_handle *xs;
char buf[64];
char ref[16];
int evfd;
evtchn_port_or_error_t port;
xs = xs_domain_open();
if (!xs) {
return ret;
}
evfd = xc_evtchn_open();
if (evfd < 0)
goto fail;
ctrl->evfd = evfd;
// the following hardcoded 0 is the peer domain id
port = xc_evtchn_bind_unbound_port(evfd, 0);
if (port < 0)
goto fail2;
ctrl->evport = port;
snprintf(ref, sizeof ref, "%d", ctrl->ring_ref);
snprintf(buf, sizeof buf, "device/vchan/%d/ring-ref", devno);
if (!xs_write(xs, 0, buf, ref, strlen(ref)))
goto fail2;
snprintf(ref, sizeof ref, "%d", ctrl->evport);
snprintf(buf, sizeof buf, "device/vchan/%d/event-channel", devno);
if (!xs_write(xs, 0, buf, ref, strlen(ref)))
goto fail2;
// wait for the peer to arrive
if (xc_evtchn_pending(evfd) == -1)
goto fail2;
xc_evtchn_unmask(ctrl->evfd, ctrl->evport);
snprintf(buf, sizeof buf, "device/vchan/%d", devno);
xs_rm(xs, 0, buf);
ret = 0;
fail2:
if (ret)
close(evfd);
fail:
xs_daemon_close(xs);
return ret;
}
#define dir_select(dir1, dir2) \
ctrl->wr_cons = &ctrl->ring->cons_##dir1; \
ctrl->wr_prod = &ctrl->ring->prod_##dir1; \
ctrl->rd_cons = &ctrl->ring->cons_##dir2; \
ctrl->rd_prod = &ctrl->ring->prod_##dir2; \
ctrl->wr_ring = ctrl->ring->buf_##dir1; \
ctrl->rd_ring = ctrl->ring->buf_##dir2; \
ctrl->wr_ring_size = sizeof(ctrl->ring->buf_##dir1); \
ctrl->rd_ring_size = sizeof(ctrl->ring->buf_##dir2)
/**
Run in AppVM (any domain).
Sleeps until the connection is established.
\param devno something like a well-known port.
\returns NULL on failure, handle on success
*/
struct libvchan *libvchan_server_init(int devno)
{
struct libvchan *ctrl =
(struct libvchan *) malloc(sizeof(struct libvchan));
if (!ctrl)
return 0;
if (ring_init(ctrl))
return 0;;
if (server_interface_init(ctrl, devno))
return 0;
/*
We want the same code for read/write functions, regardless whether
we are client, or server. Thus, we do not access buf_in nor buf_out
buffers directly. Instead, in *_init functions, the dir_select
macro assigns proper values to wr* and rd* pointers, so that they
point to correct one out of buf_in or buf_out related fields.
*/
dir_select(in, out);
ctrl->is_server = 1;
return ctrl;
}
/**
retrieves ring-ref and event-channel numbers from xenstore (if
they don't exist, return error, because nobody seems to listen);
map the ring, connect the event channel
*/
static int client_interface_init(struct libvchan *ctrl, int domain, int devno)
{
int ret = -1;
unsigned int len;
struct xs_handle *xs;
int xcfd;
char buf[64];
char *ref;
int evfd;
int remote_port;
xs = xs_daemon_open();
if (!xs) {
return ret;
}
snprintf(buf, sizeof buf,
"/local/domain/%d/device/vchan/%d/ring-ref", domain,
devno);
ref = xs_read(xs, 0, buf, &len);
if (!ref)
goto fail;
ctrl->ring_ref = atoi(ref);
if (!ctrl->ring_ref)
goto fail;
free(ref);
snprintf(buf, sizeof buf,
"/local/domain/%d/device/vchan/%d/event-channel", domain,
devno);
ref = xs_read(xs, 0, buf, &len);
if (!ref)
goto fail;
remote_port = atoi(ref);
if (!remote_port)
goto fail;
free(ref);
xcfd = xc_interface_open();
if (xcfd < 0)
goto fail;
ctrl->ring = (struct vchan_interface *)
xc_map_foreign_range(xcfd, domain, 4096,
PROT_READ | PROT_WRITE, ctrl->ring_ref);
close(xcfd);
if (ctrl->ring == 0 || ctrl->ring == MAP_FAILED)
goto fail;
evfd = xc_evtchn_open();
if (evfd < 0)
goto fail;
ctrl->evfd = evfd;
ctrl->evport =
xc_evtchn_bind_interdomain(evfd, domain, remote_port);
if (ctrl->evport < 0 || xc_evtchn_notify(evfd, ctrl->evport))
close(evfd);
else
ret = 0;
fail:
xs_daemon_close(xs);
return ret;
}
/**
Run on the client side of connection (currently, must be dom0).
\returns NULL on failure (e.g. noone listening), handle on success
*/
struct libvchan *libvchan_client_init(int domain, int devno)
{
struct libvchan *ctrl =
(struct libvchan *) malloc(sizeof(struct libvchan));
if (!ctrl)
return 0;
if (client_interface_init(ctrl, domain, devno))
return 0;
// See comment in libvchan_server_init
dir_select(out, in);
ctrl->is_server = 0;
return ctrl;
}

159
vchan/io.c Normal file
View File

@ -0,0 +1,159 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include "libvchan.h"
#include <xenctrl.h>
#include <string.h>
/**
\return How much data is immediately available for reading
*/
int libvchan_data_ready(struct libvchan *ctrl)
{
return *ctrl->rd_prod - *ctrl->rd_cons;
}
/**
\return How much space is available for writing, without blocking
*/
int libvchan_buffer_space(struct libvchan *ctrl)
{
return ctrl->wr_ring_size - (*ctrl->wr_prod - *ctrl->wr_cons);
}
static int do_notify(struct libvchan *ctrl)
{
return xc_evtchn_notify(ctrl->evfd, ctrl->evport);
}
/// returns nonzero if the peer has closed connection
int libvchan_is_eof(struct libvchan *ctrl)
{
if (ctrl->is_server) {
if (ctrl->ring->client_closed)
return -1;
} else {
if (ctrl->ring->server_closed) {
ctrl->ring->client_closed = 1;
do_notify(ctrl);
return -1;
}
}
return 0;
}
/// waits for the peer to do any action
/**
\return -1 return value means peer has closed
*/
int libvchan_wait(struct libvchan *ctrl)
{
int ret;
ret = xc_evtchn_pending(ctrl->evfd);
if (ret!=-1 && xc_evtchn_unmask(ctrl->evfd, ctrl->evport))
return -1;
if (ret!=-1 && libvchan_is_eof(ctrl))
return -1;
return ret;
}
/**
may sleep (only if no buffer space available);
may write less data than requested;
returns the amount of data processed, -1 on error or peer close
*/
int libvchan_write(struct libvchan *ctrl, char *data, int size)
{
int avail, avail_contig;
int real_idx;
while ((avail = libvchan_buffer_space(ctrl)) == 0)
if (libvchan_wait(ctrl) < 0)
return -1;
if (avail > size)
avail = size;
real_idx = (*ctrl->wr_prod) & (ctrl->wr_ring_size - 1);
avail_contig = ctrl->wr_ring_size - real_idx;
if (avail_contig < avail)
avail = avail_contig;
memcpy(ctrl->wr_ring + real_idx, data, avail);
*ctrl->wr_prod += avail;
if (do_notify(ctrl) < 0)
return -1;
return avail;
}
/**
may sleep (only if no data is available for reading);
may return less data than requested;
returns the amount of data processed, -1 on error or peer close
*/
int libvchan_read(struct libvchan *ctrl, char *data, int size)
{
int avail, avail_contig;
int real_idx;
while ((avail = libvchan_data_ready(ctrl)) == 0)
if (libvchan_wait(ctrl) < 0)
return -1;
if (avail > size)
avail = size;
real_idx = (*ctrl->rd_cons) & (ctrl->rd_ring_size - 1);
avail_contig = ctrl->rd_ring_size - real_idx;
if (avail_contig < avail)
avail = avail_contig;
memcpy(data, ctrl->rd_ring + real_idx, avail);
*ctrl->rd_cons += avail;
if (do_notify(ctrl) < 0)
return -1;
return avail;
}
/**
Wait fot the writes to finish, then notify the peer of closing
On server side, it waits for the peer to acknowledge
*/
int libvchan_close(struct libvchan *ctrl)
{
while (*ctrl->wr_prod != *ctrl->wr_cons)
if (libvchan_wait(ctrl) < 0)
return -1;
if (ctrl->is_server) {
ctrl->ring->server_closed = 1;
do_notify(ctrl);
while (!ctrl->ring->client_closed
&& libvchan_wait(ctrl) == 0);
} else {
ctrl->ring->client_closed = 1;
do_notify(ctrl);
}
return 0;
}
/// The fd to use for select() set
int libvchan_fd_for_select(struct libvchan *ctrl)
{
return ctrl->evfd;
}
/// Unmasks event channel; must be called before calling select(), and only then
void libvchan_prepare_to_select(struct libvchan *ctrl)
{
xc_evtchn_unmask(ctrl->evfd, ctrl->evport);
}

60
vchan/libvchan.h Normal file
View File

@ -0,0 +1,60 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include <stdint.h>
typedef uint32_t VCHAN_RING_IDX;
/// struct vchan_interface is placed in memory shared between domains
struct vchan_interface {
// One buffer for each data direction
char buf_in[1024];
char buf_out[2048];
// standard consumer/producer interface, one pair per buffer
VCHAN_RING_IDX cons_in, prod_in, cons_out, prod_out;
uint32_t debug;
int client_closed, server_closed;
};
/// struct libvchan is a control structure, passed to all library calls
struct libvchan {
struct vchan_interface *ring;
uint32_t ring_ref;
/// descriptor to event channel interface
int evfd;
int evport;
VCHAN_RING_IDX *wr_cons, *wr_prod, *rd_cons, *rd_prod;
char *rd_ring, *wr_ring;
int rd_ring_size, wr_ring_size;
int is_server;
};
struct libvchan *libvchan_server_init(int devno);
struct libvchan *libvchan_client_init(int domain, int devno);
int libvchan_write(struct libvchan *ctrl, char *data, int size);
int libvchan_read(struct libvchan *ctrl, char *data, int size);
int libvchan_wait(struct libvchan *ctrl);
int libvchan_close(struct libvchan *ctrl);
void libvchan_prepare_to_select(struct libvchan *ctrl);
int libvchan_fd_for_select(struct libvchan *ctrl);
int libvchan_is_eof(struct libvchan *ctrl);
int libvchan_data_ready(struct libvchan *ctrl);
int libvchan_buffer_space(struct libvchan *ctrl);

133
vchan/node-select.c Normal file
View File

@ -0,0 +1,133 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include "libvchan.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.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()
{
fprintf(stderr, "usage:\n\tnode-select server nodeid\n"
"or\n" "\tnode-select client domainid nodeid\n");
exit(1);
}
#define BUFSIZE 5000
char buf[BUFSIZE];
/**
Simple libvchan application, both client and server.
Both sides may write and read, both from the libvchan and from
stdin/stdout (just like netcat). More code is required to avoid
deadlock when both sides write, and noone reads.
*/
int main(int argc, char **argv)
{
int ret;
int libvchan_fd;
struct libvchan *ctrl = 0;
if (argc < 3)
usage();
if (!strcmp(argv[1], "server"))
ctrl = libvchan_server_init(atoi(argv[2]));
else if (!strcmp(argv[1], "client"))
ctrl = libvchan_client_init(atoi(argv[2]), atoi(argv[3]));
else
usage();
if (!ctrl) {
perror("libvchan_*_init");
exit(1);
}
libvchan_fd = libvchan_fd_for_select(ctrl);
for (;;) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(libvchan_fd, &rfds);
// libvchan_prepare_to_select(ctrl);
ret = select(libvchan_fd + 1, &rfds, NULL, NULL, NULL);
if (ret < 0) {
perror("select");
exit(1);
}
if (libvchan_is_eof(ctrl))
exit(0);
if (FD_ISSET(libvchan_fd, &rfds))
// we don't care about the result, but we need to do the read to
// clear libvchan_fd pendind state
libvchan_wait(ctrl);
while (libvchan_data_ready(ctrl) > 0) {
ret = libvchan_read(ctrl, buf, BUFSIZE);
if (ret < 0)
exit(0);
write_all(1, buf, ret);
}
if (FD_ISSET(0, &rfds)) {
ret = read(0, buf, BUFSIZE);
if (ret == 0) {
libvchan_close(ctrl);
exit(0);
}
if (ret < 0) {
perror("read 0");
exit(1);
}
// libvchan_write_all can block; so if both sides write a lot,
// we can deadlock. Need higher level solution; would libvchan_write be ok ?
libvchan_write_all(ctrl, buf, ret);
}
}
}

157
vchan/node.c Normal file
View File

@ -0,0 +1,157 @@
/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
*/
#include "libvchan.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.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()
{
fprintf(stderr, "usage:\n\tnode server [read|write] nodeid\n"
"or\n" "\tnode client [read|write] domainid nodeid\n");
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();
if (!strcmp(argv[2], "read"))
wr = 0;
else if (!strcmp(argv[2], "write"))
wr = 1;
else
usage();
if (!strcmp(argv[1], "server"))
ctrl = libvchan_server_init(atoi(argv[3]));
else if (!strcmp(argv[1], "client"))
ctrl = libvchan_client_init(atoi(argv[3]), atoi(argv[4]));
else
usage();
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;
}