[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v7 12/19] tools: add simple vchan-socket-proxy
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; > +}
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |