[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 11/16] tools: add simple vchan-socket-proxy
On Jan 14, 2020, at 21:42, Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx> wrote: > > diff --git a/tools/libvchan/Makefile b/tools/libvchan/Makefile > index 7892750..1c845ca 100644 > --- a/tools/libvchan/Makefile > +++ b/tools/libvchan/Makefile > @@ -13,6 +13,7 @@ LIBVCHAN_PIC_OBJS = $(patsubst %.o,%.opic,$(LIBVCHAN_OBJS)) > LIBVCHAN_LIBS = $(LDLIBS_libxenstore) $(LDLIBS_libxengnttab) > $(LDLIBS_libxenevtchn) > $(LIBVCHAN_OBJS) $(LIBVCHAN_PIC_OBJS): CFLAGS += $(CFLAGS_libxenstore) > $(CFLAGS_libxengnttab) $(CFLAGS_libxenevtchn) > $(NODE_OBJS) $(NODE2_OBJS): CFLAGS += $(CFLAGS_libxengnttab) > $(CFLAGS_libxenevtchn) > +vchan-socket-proxy.o: CFLAGS += $(CFLAGS_libxenstore) $(CFLAGS_libxenctrl) > $(CFLAGS_libxengnttab) $(CFLAGS_libxenevtchn) > > MAJOR = 4.14 > MINOR = 0 > @@ -39,7 +40,7 @@ $(PKG_CONFIG_LOCAL): PKG_CONFIG_LIBDIR = $(CURDIR) > $(PKG_CONFIG_LOCAL): PKG_CONFIG_CFLAGS_LOCAL = $(CFLAGS_xeninclude) > > .PHONY: all > -all: libxenvchan.so vchan-node1 vchan-node2 libxenvchan.a $(PKG_CONFIG_INST) > $(PKG_CONFIG_LOCAL) > +all: libxenvchan.so vchan-node1 vchan-node2 vchan-socket-proxy libxenvchan.a > $(PKG_CONFIG_INST) $(PKG_CONFIG_LOCAL) > > libxenvchan.so: libxenvchan.so.$(MAJOR) > ln -sf $< $@ > @@ -59,6 +60,9 @@ vchan-node1: $(NODE_OBJS) libxenvchan.so > vchan-node2: $(NODE2_OBJS) libxenvchan.so > $(CC) $(LDFLAGS) -o $@ $(NODE2_OBJS) $(LDLIBS_libxenvchan) > $(APPEND_LDFLAGS) > > +vchan-socket-proxy: vchan-socket-proxy.o libxenvchan.so > + $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenvchan) $(LDLIBS_libxenstore) > $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) > + > .PHONY: install > install: all > $(INSTALL_DIR) $(DESTDIR)$(libdir) > @@ -66,6 +70,7 @@ install: all > $(INSTALL_PROG) libxenvchan.so.$(MAJOR).$(MINOR) $(DESTDIR)$(libdir) > ln -sf libxenvchan.so.$(MAJOR).$(MINOR) > $(DESTDIR)$(libdir)/libxenvchan.so.$(MAJOR) > ln -sf libxenvchan.so.$(MAJOR) $(DESTDIR)$(libdir)/libxenvchan.so > + $(INSTALL_PROG) vchan-socket-proxy $(DESTDIR)$(bindir) Does this need directory creation, to avoid vchan binary being named "bin"? + $(INSTALL_DIR) $(DESTDIR)$(bindir) > diff --git a/tools/libvchan/vchan-socket-proxy.c > b/tools/libvchan/vchan-socket-proxy.c > new file mode 100644 > index 0000000..6b4ae09 > --- /dev/null > +++ b/tools/libvchan/vchan-socket-proxy.c > @@ -0,0 +1,469 @@ > +/** > + * @file > + * @section AUTHORS > + * > + * Copyright (C) 2010 Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> > + * > + * Authors: > + * Rafal Wojtczuk <rafal@xxxxxxxxxxxxxxxxxxxxxx> > + * Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> > + * Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx> > + * > + * @section LICENSE > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 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 > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this program; If not, see > <http://www.gnu.org/licenses/>. > + * > + * @section DESCRIPTION > + * > + * This is a vchan to unix socket proxy. Vchan server is set, and on client > + * connection, local socket connection is established. Communication is > bidirectional. > + * One client is served at a time, clients needs to coordinate this > themselves. > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > +#include <unistd.h> > +#include <fcntl.h> > +#include <errno.h> > +#include <sys/socket.h> > +#include <sys/un.h> > +#include <getopt.h> > + > +#include <xenstore.h> > +#include <xenctrl.h> > +#include <libxenvchan.h> > + > +static void usage(char** argv) > +{ > + fprintf(stderr, "usage:\n" > + "\t%s [options] domainid nodepath [socket-path|file-no|-]\n" > + "\n" > + "options:\n" > + "\t-m, --mode=client|server - vchan connection mode\n" > + "\t-m, --state-path=path - xenstore path where write \"running\" to > at startup\n" > + "\t-v, --verbose - verbose logging\n" > + "\n" > + "client: client of a vchan connection, fourth parameter can be:\n" > + "\tsocket-path: listen on a UNIX socket at this path and connect to > vchan\n" > + "\t whenever new connection is accepted;\n" > + "\t handle multiple _subsequent_ connections, until terminated\n" > + "\tfile-no: except open FD of a socket in listen mode; otherwise > similar to socket-path\n" > + "\t-: open vchan connection immediately and pass the data from > stdin/stdout;\n" > + "\t terminate when vchan connection is closed\n" > + "server: server of a vchan connection, fourth parameter can be:\n" > + "\tsocket-path: connect to this UNIX socket when new vchan > connection is accepted\n" > + "\t handle multiple _subsequent_ connections, until terminated\n" > + "\tfile-no: pass data to/from this FD; terminate when vchan > connection is closed\n" > + "\t-: pass data to/from stdin/stdout; terminatate when vchan > connection is closed\n", > + argv[0]); > + exit(1); > +} > + > +#define BUFSIZE 8192 > +char inbuf[BUFSIZE]; > +char outbuf[BUFSIZE]; > +int insiz = 0; > +int outsiz = 0; > +int verbose = 0; > + > +static void vchan_wr(struct libxenvchan *ctrl) { > + int ret; > + > + if (!insiz) > + return; > + ret = libxenvchan_write(ctrl, inbuf, insiz); > + if (ret < 0) { > + fprintf(stderr, "vchan write failed\n"); > + exit(1); > + } > + if (verbose) > + fprintf(stderr, "written %d bytes to vchan\n", ret); > + if (ret > 0) { > + insiz -= ret; > + memmove(inbuf, inbuf + ret, insiz); > + } > +} > + > +static void socket_wr(int output_fd) { > + int ret; > + > + if (!outsiz) > + return; > + ret = write(output_fd, outbuf, outsiz); > + if (ret < 0 && errno != EAGAIN) > + exit(1); > + if (ret > 0) { > + outsiz -= ret; > + memmove(outbuf, outbuf + ret, outsiz); > + } > +} > + > +static int set_nonblocking(int fd, int nonblocking) { > + int flags = fcntl(fd, F_GETFL); > + if (flags == -1) > + return -1; > + > + if (nonblocking) > + flags |= O_NONBLOCK; > + else > + flags &= ~O_NONBLOCK; > + > + if (fcntl(fd, F_SETFL, flags) == -1) > + return -1; > + > + return 0; > +} > + > +static int connect_socket(const char *path_or_fd) { > + int fd; > + char *endptr; > + struct sockaddr_un addr; > + > + fd = strtoll(path_or_fd, &endptr, 0); > + if (*endptr == '\0') { > + set_nonblocking(fd, 1); > + return fd; > + } > + > + fd = socket(AF_UNIX, SOCK_STREAM, 0); > + if (fd == -1) > + return -1; > + > + addr.sun_family = AF_UNIX; > + strncpy(addr.sun_path, path_or_fd, sizeof(addr.sun_path)); > + if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { > + close(fd); > + return -1; > + } > + > + set_nonblocking(fd, 1); > + > + return fd; > +} > + > +static int listen_socket(const char *path_or_fd) { > + int fd; > + char *endptr; > + struct sockaddr_un addr; > + > + fd = strtoll(path_or_fd, &endptr, 0); > + if (*endptr == '\0') { > + return fd; > + } > + > + /* if not a number, assume a socket path */ > + fd = socket(AF_UNIX, SOCK_STREAM, 0); > + if (fd == -1) > + return -1; > + > + addr.sun_family = AF_UNIX; > + strncpy(addr.sun_path, path_or_fd, sizeof(addr.sun_path)); > + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { > + close(fd); > + return -1; > + } > + if (listen(fd, 5) != 0) { > + close(fd); > + return -1; > + } > + > + return fd; > +} > + > +static struct libxenvchan *connect_vchan(int domid, const char *path) { > + struct libxenvchan *ctrl = NULL; > + struct xs_handle *xs = NULL; > + xc_interface *xc = NULL; > + xc_dominfo_t dominfo; > + char **watch_ret; > + unsigned int watch_num; > + int ret; > + > + xs = xs_open(XS_OPEN_READONLY); > + if (!xs) { > + perror("xs_open"); > + goto out; > + } > + xc = xc_interface_open(NULL, NULL, XC_OPENFLAG_NON_REENTRANT); > + if (!xc) { > + perror("xc_interface_open"); > + goto out; > + } > + /* wait for vchan server to create *path* */ > + xs_watch(xs, path, "path"); > + xs_watch(xs, "@releaseDomain", "release"); > + while ((watch_ret = xs_read_watch(xs, &watch_num))) { > + /* don't care about exact which fired the watch */ > + free(watch_ret); > + ctrl = libxenvchan_client_init(NULL, domid, path); > + if (ctrl) > + break; > + > + ret = xc_domain_getinfo(xc, domid, 1, &dominfo); > + /* break the loop if domain is definitely not there anymore, but > + * continue if it is or the call failed (like EPERM) */ > + if (ret == -1 && errno == ESRCH) > + break; > + if (ret == 1 && (dominfo.domid != (uint32_t)domid || dominfo.dying)) > + break; > + } > + > +out: > + if (xc) > + xc_interface_close(xc); > + if (xs) > + xs_close(xs); > + return ctrl; > +} > + > + > +static void discard_buffers(struct libxenvchan *ctrl) { > + /* discard local buffers */ > + insiz = 0; > + outsiz = 0; > + > + /* discard remaining incoming data */ > + while (libxenvchan_data_ready(ctrl)) { > + if (libxenvchan_read(ctrl, inbuf, BUFSIZE) == -1) { > + perror("vchan read"); > + exit(1); > + } > + } > +} > + > +int data_loop(struct libxenvchan *ctrl, int input_fd, int output_fd) > +{ > + int ret; > + int libxenvchan_fd; > + int max_fd; > + > + libxenvchan_fd = libxenvchan_fd_for_select(ctrl); > + for (;;) { > + fd_set rfds; > + fd_set wfds; > + FD_ZERO(&rfds); > + FD_ZERO(&wfds); > + > + max_fd = -1; > + if (input_fd != -1 && insiz != BUFSIZE) { > + FD_SET(input_fd, &rfds); > + if (input_fd > max_fd) > + max_fd = input_fd; > + } > + if (output_fd != -1 && outsiz) { > + FD_SET(output_fd, &wfds); > + if (output_fd > max_fd) > + max_fd = output_fd; > + } > + FD_SET(libxenvchan_fd, &rfds); > + if (libxenvchan_fd > max_fd) > + max_fd = libxenvchan_fd; > + ret = select(max_fd + 1, &rfds, &wfds, NULL, NULL); > + if (ret < 0) { > + perror("select"); > + exit(1); > + } > + if (FD_ISSET(libxenvchan_fd, &rfds)) { > + libxenvchan_wait(ctrl); > + if (!libxenvchan_is_open(ctrl)) { > + if (verbose) > + fprintf(stderr, "vchan client disconnected\n"); > + while (outsiz) > + socket_wr(output_fd); > + close(output_fd); > + close(input_fd); > + discard_buffers(ctrl); > + break; > + } > + vchan_wr(ctrl); > + } > + > + /* socket_fd guaranteed to be != -1 */ > + > + if (FD_ISSET(input_fd, &rfds)) { > + ret = read(input_fd, inbuf + insiz, BUFSIZE - insiz); > + if (ret < 0 && errno != EAGAIN) > + exit(1); > + if (verbose) > + fprintf(stderr, "from-unix: %.*s\n", ret, inbuf + insiz); > + if (ret == 0) { > + /* EOF on socket, write everything in the buffer and close > the > + * socket */ > + while (insiz) { > + vchan_wr(ctrl); > + libxenvchan_wait(ctrl); > + } > + close(input_fd); > + input_fd = -1; > + /* TODO: maybe signal the vchan client somehow? */ > + break; > + } > + if (ret) > + insiz += ret; > + vchan_wr(ctrl); > + } > + if (FD_ISSET(output_fd, &wfds)) > + socket_wr(output_fd); > + while (libxenvchan_data_ready(ctrl) && outsiz < BUFSIZE) { > + ret = libxenvchan_read(ctrl, outbuf + outsiz, BUFSIZE - outsiz); > + if (ret < 0) > + exit(1); > + if (verbose) > + fprintf(stderr, "from-vchan: %.*s\n", ret, outbuf + outsiz); > + outsiz += ret; > + socket_wr(output_fd); > + } > + } > + return 0; > +} > + > +/** > + Simple libxenvchan application, both client and server. > + Both sides may write and read, both from the libxenvchan and from > + stdin/stdout (just like netcat). > +*/ > + > +static struct option options[] = { > + { "mode", required_argument, NULL, 'm' }, > + { "verbose", no_argument, NULL, 'v' }, > + { "state-path", required_argument, NULL, 's' }, > + { } > +}; > + > +int main(int argc, char **argv) > +{ > + int is_server = 0; > + int socket_fd; When compiled for OpenEmbedded / OpenXT, gcc complained about socket_fd being uninitialized before possible use. Rich _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |