From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Jason Andryuk <jandryuk@gmail.com>, xen-devel@lists.xenproject.org
Cc: "Ian Jackson" <ian.jackson@citrix.com>,
"Marek Marczykowski-Górecki" <marmarek@invisiblethingslab.com>,
"Wei Liu" <wl@xen.org>
Subject: Re: [PATCH v7 12/19] tools: add simple vchan-socket-proxy
Date: Thu, 21 May 2020 12:09:26 +0100 [thread overview]
Message-ID: <edb28eba-622e-e9e6-5d22-0d5e86b503bd@citrix.com> (raw)
In-Reply-To: <20200519015503.115236-13-jandryuk@gmail.com>
On 19/05/2020 02:54, Jason Andryuk wrote:
> +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));
Coverity has identified issues, some perhaps more concerning than others.
Here, addr.sun_path not necessarily NUL terminated.
> + 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));
And here.
> + 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");
Return values not checked.
> + 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);
> + }
> +
> + 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
> + * input_fd socket */
> + while (insiz) {
> + vchan_wr(ctrl);
> + libxenvchan_wait(ctrl);
> + }
> + close(input_fd);
> + input_fd = -1;
Dead store.
> + /* 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 = -1;
> + int input_fd, output_fd;
> + struct libxenvchan *ctrl = NULL;
> + const char *socket_path;
> + int domid;
> + const char *vchan_path;
> + const char *state_path = NULL;
> + int opt;
> +
> + while ((opt = getopt_long(argc, argv, "m:vs:", options, NULL)) != -1) {
> + switch (opt) {
> + case 'm':
> + if (strcmp(optarg, "server") == 0)
> + is_server = 1;
> + else if (strcmp(optarg, "client") == 0)
> + is_server = 0;
> + else {
> + fprintf(stderr, "invalid argument for --mode: %s\n", optarg);
> + usage(argv);
> + return 1;
> + }
> + break;
> + case 'v':
> + verbose = 1;
> + break;
> + case 's':
> + state_path = optarg;
> + break;
> + case '?':
> + usage(argv);
> + }
> + }
> +
> + if (argc-optind != 3)
> + usage(argv);
> +
> + domid = atoi(argv[optind]);
> + vchan_path = argv[optind+1];
> + socket_path = argv[optind+2];
> +
> + if (is_server) {
> + ctrl = libxenvchan_server_init(NULL, domid, vchan_path, 0, 0);
> + if (!ctrl) {
> + perror("libxenvchan_server_init");
> + exit(1);
> + }
> + } else {
> + if (strcmp(socket_path, "-") == 0) {
> + input_fd = 0;
> + output_fd = 1;
> + } else {
> + socket_fd = listen_socket(socket_path);
> + if (socket_fd == -1) {
> + perror("listen socket");
> + return 1;
> + }
> + }
> + }
> +
> + if (state_path) {
> + struct xs_handle *xs;
> +
> + xs = xs_open(0);
> + if (!xs) {
> + perror("xs_open");
> + return 1;
> + }
> + if (!xs_write(xs, XBT_NULL, state_path, "running", strlen("running"))) {
> + perror("xs_write");
> + return 1;
> + }
> + xs_close(xs);
> + }
> +
> + for (;;) {
> + if (is_server) {
> + /* wait for vchan connection */
> + while (libxenvchan_is_open(ctrl) != 1)
> + libxenvchan_wait(ctrl);
> + /* vchan client connected, setup local FD if needed */
> + if (strcmp(socket_path, "-") == 0) {
> + input_fd = 0;
> + output_fd = 1;
> + } else {
> + input_fd = output_fd = connect_socket(socket_path);
> + }
> + if (input_fd == -1) {
> + perror("connect socket");
> + return 1;
> + }
> + if (data_loop(ctrl, input_fd, output_fd) != 0)
> + break;
> + /* keep it running only when get UNIX socket path */
> + if (socket_path[0] != '/')
> + break;
> + } else {
> + /* wait for local socket connection */
> + if (strcmp(socket_path, "-") != 0)
> + input_fd = output_fd = accept(socket_fd, NULL, NULL);
> + if (input_fd == -1) {
> + perror("accept");
Leakage of scoket_fd, and ...
> + return 1;
> + }
> + set_nonblocking(input_fd, 1);
> + set_nonblocking(output_fd, 1);
> + ctrl = connect_vchan(domid, vchan_path);
> + if (!ctrl) {
> + perror("vchan client init");
All 3 FDs here.
~Andrew
> + return 1;
> + }
> + if (data_loop(ctrl, input_fd, output_fd) != 0)
> + break;
> + /* don't reconnect if output was stdout */
> + if (strcmp(socket_path, "-") == 0)
> + break;
> +
> + libxenvchan_close(ctrl);
> + ctrl = NULL;
> + }
> + }
> + return 0;
> +}
next prev parent reply other threads:[~2020-05-21 11:10 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-19 1:54 [PATCH v7 00/19] Add support for qemu-xen runnning in a Linux-based stubdomain Jason Andryuk
2020-05-18 22:24 ` Wei Liu
2020-05-19 1:54 ` [PATCH v7 01/19] Document ioemu MiniOS stubdomain protocol Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 02/19] Document ioemu Linux " Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 03/19] libxl: fix qemu-trad cmdline for no sdl/vnc case Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 04/19] libxl: Allow running qemu-xen in stubdomain Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 05/19] libxl: Handle Linux stubdomain specific QEMU options Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 06/19] libxl: Use libxl__xs_* in libxl__write_stub_dmargs Jason Andryuk
2020-05-19 15:09 ` Ian Jackson
2020-05-19 1:54 ` [PATCH v7 07/19] libxl: write qemu arguments into separate xenstore keys Jason Andryuk
2020-05-19 15:10 ` Ian Jackson
2020-05-19 15:21 ` Wei Liu
2020-05-19 15:33 ` Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 08/19] xl: add stubdomain related options to xl config parser Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 09/19] tools/libvchan: notify server when client is connected Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 10/19] libxl: add save/restore support for qemu-xen in stubdomain Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 11/19] tools: add missing libxenvchan cflags Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 12/19] tools: add simple vchan-socket-proxy Jason Andryuk
2020-05-21 11:09 ` Andrew Cooper [this message]
2020-05-21 13:12 ` Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 13/19] libxl: Refactor kill_device_model to libxl__kill_xs_path Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 14/19] libxl: use vchan for QMP access with Linux stubdomain Jason Andryuk
2020-05-19 1:54 ` [PATCH v7 15/19] libxl: require qemu in dom0 for multiple stubdomain consoles Jason Andryuk
2020-05-19 1:55 ` [PATCH v7 16/19] libxl: ignore emulated IDE disks beyond the first 4 Jason Andryuk
2020-05-19 1:55 ` [PATCH v7 17/19] libxl: consider also qemu in stubdomain in libxl__dm_active check Jason Andryuk
2020-05-19 1:55 ` [PATCH v7 18/19] docs: Add device-model-domid to xenstore-paths Jason Andryuk
2020-05-19 1:55 ` [PATCH v7 19/19] libxl: Check stubdomain kernel & ramdisk presence Jason Andryuk
2020-05-22 9:10 ` [PATCH v7 00/19] Add support for qemu-xen runnning in a Linux-based stubdomain George Dunlap
2020-05-22 9:54 ` Paul Durrant
2020-05-22 13:30 ` Jason Andryuk
2020-05-22 13:37 ` Ian Jackson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=edb28eba-622e-e9e6-5d22-0d5e86b503bd@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=ian.jackson@citrix.com \
--cc=jandryuk@gmail.com \
--cc=marmarek@invisiblethingslab.com \
--cc=wl@xen.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).