Skip to content

Commit

Permalink
Update for new vchan API, remove unused code
Browse files Browse the repository at this point in the history
This change is mainly about passing libvchan_t from gui-daemon code, not
magical static variable in txrx-vchan.c.
  • Loading branch information
marmarek authored and woju committed Oct 27, 2014
1 parent df0fdd5 commit d0fcc6c
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 507 deletions.
278 changes: 39 additions & 239 deletions gui-common/txrx-vchan.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,131 +23,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <libvchan.h>
#include <xs.h>
#include <xenctrl.h>
#include <sys/select.h>
#include <errno.h>
#include "double-buffer.h"

struct libvchan *ctrl;
int double_buffered = 0;
int is_server;
void (*vchan_at_eof)(void) = NULL;
int vchan_is_closed = 0;

/* double buffered in gui-daemon to deal with deadlock
* during send large clipboard content
*/
int double_buffered = 1;

void vchan_register_at_eof(void (*new_vchan_at_eof)(void)) {
vchan_at_eof = new_vchan_at_eof;
}

int write_data_exact(char *buf, int size)
void handle_vchan_error(libvchan_t *vchan, const char *op)
{
if (!libvchan_is_open(vchan)) {
fprintf(stderr, "EOF\n");
exit(0);
} else {
fprintf(stderr, "Error while vchan %s\n, terminating", op);
exit(1);
}
}

int write_data_exact(libvchan_t *vchan, 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);
}
ret = libvchan_write(vchan, buf + written, size - written);
if (ret <= 0)
handle_vchan_error(vchan, "write data");
written += ret;
}
// fprintf(stderr, "sent %d bytes\n", size);
return size;
}

int write_data(char *buf, int size)
int write_data(libvchan_t *vchan, char *buf, int size)
{
int count;
if (!double_buffered)
return write_data_exact(buf, size); // this may block
return write_data_exact(vchan, buf, size); // this may block
double_buffer_append(buf, size);
count = libvchan_buffer_space(ctrl);
count = libvchan_buffer_space(vchan);
if (count > double_buffer_datacount())
count = double_buffer_datacount();
// below, we write only as much data as possible without
// blocking; remainder of data stays in the double buffer
write_data_exact(double_buffer_data(), count);
write_data_exact(vchan, double_buffer_data(), count);
double_buffer_substract(count);
return size;
}

int real_write_message(char *hdr, int size, char *data, int datasize)
int real_write_message(libvchan_t *vchan, char *hdr, int size, char *data, int datasize)
{
write_data(hdr, size);
write_data(data, datasize);
write_data(vchan, hdr, size);
write_data(vchan, data, datasize);
return 0;
}

int read_data(char *buf, int size)
int read_data(libvchan_t *vchan, char *buf, int size)
{
int written = 0;
int ret;
while (written < size) {
ret = libvchan_read(ctrl, buf + written, size - written);
if (ret == 0) {
fprintf(stderr, "EOF\n");
exit(1);
}
if (ret < 0) {
perror("read");
exit(1);
}
ret = libvchan_read(vchan, buf + written, size - written);
if (ret <= 0)
handle_vchan_error(vchan, "read data");
written += ret;
}
// fprintf(stderr, "read %d bytes\n", size);
return size;
}

int read_ready(void)
{
return libvchan_data_ready(ctrl);
}

// if the remote domain is destroyed, we get no notification
// thus, we check for the status periodically

#ifdef XENCTRL_HAS_XC_INTERFACE
static xc_interface *xc_handle = NULL;
#else
static int xc_handle = -1;
#endif
int slow_check_for_libvchan_is_eof(struct libvchan *ctrl)
{
struct evtchn_status evst;
evst.port = ctrl->evport;
evst.dom = DOMID_SELF;
if (xc_evtchn_status(xc_handle, &evst)) {
perror("xc_evtchn_status");
vchan_is_closed = 1;
libvchan_cleanup(ctrl);
if (vchan_at_eof != NULL) {
vchan_at_eof();
return 1;
} else
exit(1);
}
if (evst.status != EVTCHNSTAT_interdomain) {
fprintf(stderr, "event channel disconnected\n");
vchan_is_closed = 1;
libvchan_cleanup(ctrl);
if (vchan_at_eof != NULL) {
vchan_at_eof();
return 1;
} else
exit(0);
}
return 0;
}


int wait_for_vchan_or_argfd_once(int nfd, int *fd, fd_set * retset)
int wait_for_vchan_or_argfd_once(libvchan_t *vchan, int nfd, int *fd, fd_set * retset)
{
fd_set rfds;
int vfd, max = 0, ret, i;
struct timeval tv = { 0, 1000000 };
write_data(NULL, 0); // trigger write of queued data, if any present
vfd = libvchan_fd_for_select(ctrl);
write_data(vchan, NULL, 0); // trigger write of queued data, if any present
vfd = libvchan_fd_for_select(vchan);
FD_ZERO(&rfds);
for (i = 0; i < nfd; i++) {
int cfd = fd[i];
Expand All @@ -166,188 +127,27 @@ int wait_for_vchan_or_argfd_once(int nfd, int *fd, fd_set * retset)
perror("select");
exit(1);
}
if (libvchan_is_eof(ctrl)) {
if (!libvchan_is_open(vchan)) {
fprintf(stderr, "libvchan_is_eof\n");
vchan_is_closed = 1;
libvchan_cleanup(ctrl);
libvchan_close(vchan);
if (vchan_at_eof != NULL) {
vchan_at_eof();
return -1;
} else
exit(0);
}
if (!is_server && ret == 0)
if (slow_check_for_libvchan_is_eof(ctrl))
return -1;
if (FD_ISSET(vfd, &rfds))
// the following will never block; we need to do this to
// clear libvchan_fd pending state
libvchan_wait(ctrl);
libvchan_wait(vchan);
if (retset)
*retset = rfds;
return ret;
}

int wait_for_vchan_or_argfd(int nfd, int *fd, fd_set * retset)
int wait_for_vchan_or_argfd(libvchan_t *vchan, int nfd, int *fd, fd_set * retset)
{
int ret;
while ((ret=wait_for_vchan_or_argfd_once(nfd, fd, retset)) == 0);
while ((ret=wait_for_vchan_or_argfd_once(vchan, nfd, fd, retset)) == 0);
return ret;
}

int peer_server_init(int port)
{
#ifdef CONFIG_STUBDOM
double_buffer_init();
double_buffered = 1;
#else
double_buffered = 0; // writes to vchan may block
#endif
is_server = 1;
ctrl = libvchan_server_init(port);
if (!ctrl) {
perror("libvchan_server_init");
exit(1);
}
return 0;
}

char *get_vm_name(int dom, int *target_dom)
{
struct xs_handle *xs;
char buf[64];
char *name;
char *target_dom_str;
unsigned int len = 0;

xs = xs_daemon_open();
if (!xs) {
perror("xs_daemon_open");
exit(1);
}
snprintf(buf, sizeof(buf), "/local/domain/%d/target", dom);
target_dom_str = xs_read(xs, 0, buf, &len);
if (target_dom_str) {
errno = 0;
*target_dom = strtol(target_dom_str, (char **) NULL, 10);
if (errno != 0) {
perror("strtol");
exit(1);
}
free(target_dom_str);
} else
*target_dom = dom;
snprintf(buf, sizeof(buf), "/local/domain/%d/name", *target_dom);
name = xs_read(xs, 0, buf, &len);
if (!name) {
perror("xs_read domainname");
exit(1);
}
xs_daemon_close(xs);
return name;
}

void peer_client_init(int dom, int port)
{
struct xs_handle *xs;
char *dummy, *dummy2;
unsigned int len = 0;
char devbuf[128];
char dombuf[128];
unsigned int count;
char **vec;

double_buffered = 1; // writes to vchan are buffered, nonblocking
double_buffer_init();
xs = xs_daemon_open();
if (!xs) {
perror("xs_daemon_open");
exit(1);
}
snprintf(devbuf, sizeof(devbuf),
"/local/domain/%d/device/vchan/%d/event-channel", dom,
port);
snprintf(dombuf, sizeof(dombuf), "/local/domain/%d", dom);
xs_watch(xs, devbuf, devbuf);
do {
vec = xs_read_watch(xs, &count);
if (vec)
free(vec);
len = 0;
dummy = xs_read(xs, 0, devbuf, &len);
if (dummy)
free(dummy);
else {
/* check if domain still alive */
dummy2 = xs_read(xs, 0, dombuf, &len);
if (!dummy2) {
fprintf(stderr, "domain dead\n");
exit(1);
}
free(dummy2);
}
}
while (!dummy || !len); // wait for the server to create xenstore entries
xs_daemon_close(xs);

if (!(ctrl = libvchan_client_init(dom, port))) {
perror("libvchan_client_init");
exit(1);
}

#ifdef XENCTRL_HAS_XC_INTERFACE
xc_handle = xc_interface_open(NULL, 0, 0);
if (!xc_handle) {
#else
xc_handle = xc_interface_open();
if (xc_handle < 0) {
#endif
perror("xc_interface_open");
exit(1);
}
}

int peer_server_reinitialize(int port)
{
if (libvchan_cleanup(ctrl) < 0)
return -1;
return peer_server_init(port);
}

void vchan_close(void)
{
if (!vchan_is_closed)
libvchan_close(ctrl);
vchan_is_closed = 1;
}

int vchan_fd(void)
{
return libvchan_fd_for_select(ctrl);
}

#ifdef CONFIG_STUBDOM
int vchan_handle_connected(void)
{
return libvchan_server_handle_connected(ctrl);
}

void vchan_handler_called(void)
{
// clear the pending flag, will never block if called as name suggest
libvchan_wait(ctrl);
}

void vchan_unmask_channel(void)
{
libvchan_prepare_to_select(ctrl);
}

/* only for stubdom, because eof is handled in wait_for_vchan_or_argfd in other
* cases */
int vchan_is_eof(void)
{
return libvchan_is_eof(ctrl);
}

#endif
14 changes: 10 additions & 4 deletions gui-daemon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,21 @@
#

CC=gcc
CFLAGS+=-I../include/ -g -O2 -Wall -Wextra -Werror \
`pkg-config --cflags libconfig libpng libnotify` -pie -fPIC
CFLAGS+=-I../include/ -g -O2 -Wall -Wextra -Werror -pie -fPIC \
`pkg-config --cflags libconfig` \
`pkg-config --cflags libnotify` \
`pkg-config --cflags libpng` \
`pkg-config --cflags vchan-$(BACKEND_VMM)`
OBJS=xside.o png.o ../gui-common/double-buffer.o ../gui-common/txrx-vchan.o \
../gui-common/error.o ../common/list.o

all: qubes-guid
qubes-guid: $(OBJS)
$(CC) -g -pie -o qubes-guid $(OBJS) \
-lX11 -lXext -lvchan -lxenstore -lxenctrl -Wall \
`pkg-config --libs libpng libnotify libconfig`
-lX11 -lXext -Wall \
`pkg-config --libs vchan-$(BACKEND_VMM)` \
`pkg-config --libs libpng` \
`pkg-config --libs libconfig` \
`pkg-config --libs libnotify`
clean:
rm -f qubes-guid *.o *~
Loading

0 comments on commit d0fcc6c

Please sign in to comment.