diff options
author | Alyssa Ross <hi@alyssa.is> | 2021-03-19 03:17:13 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2021-03-21 14:37:33 +0000 |
commit | 20a27f13713bb1c7be9bd82ac659e346f5384a51 (patch) | |
tree | 43f5c216753b0031a74d5949c0bc7befeca0b25a /vsockserver-socketbinder.c | |
parent | 38559b5aa5a6e371a5fd8a20367fc142e02945c3 (diff) | |
download | ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.tar ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.tar.gz ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.tar.bz2 ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.tar.lz ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.tar.xz ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.tar.zst ucspi-vsock-20a27f13713bb1c7be9bd82ac659e346f5384a51.zip |
Extract vsockserver-socketbinder and vsockserverd
vsockserver-socketbinder creates and listens on a socket, and vsockserverd accepts connections and sets up file descriptors. vsockserver previously did both of these things in one big program, but now it just sets up a command line to run vsockserver-socketbinder followed by vsockserverd. Having two seperate programs allows one program to be used in situations where the other is not suitable (e.g. using vsockserver-socketbinder to create a socket in situations where accept behaviour more complex than vsockserverd can provide is required). This design is taken from s6[1], which uses the same design for its s6-ipcserver, s6-ipcserver-socketbinder, and s6-ipcserverd programs. [1]: https://skarnet.org/software/s6/ Message-Id: <20210319031713.23600-1-hi@alyssa.is> Reviewed-by: Cole Helbling <cole.e.helbling@outlook.com>
Diffstat (limited to 'vsockserver-socketbinder.c')
-rw-r--r-- | vsockserver-socketbinder.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/vsockserver-socketbinder.c b/vsockserver-socketbinder.c new file mode 100644 index 0000000..fdcdfa8 --- /dev/null +++ b/vsockserver-socketbinder.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2020-2021 Alyssa Ross <hi@alyssa.is> + +#define _GNU_SOURCE + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdnoreturn.h> +#include <string.h> +#include <sysexits.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <linux/vm_sockets.h> + +#include "log.h" +#include "num.h" +#include "vsock.h" + +static const int LISTEN_BACKLOG = 40; + +noreturn static void ex_usage(void) +{ + if (verbosity) + fprintf(stderr, "Usage: %s cid port prog...\n", + program_invocation_short_name); + exit(EX_USAGE); +} + +int main(int argc, char *argv[]) +{ + int opt, fd; + uint32_t cid, port; + + // A skeleton of an option parser to reject any options that + // are given, so we can add options in the future without + // worrying about breaking backwards compatibility because + // they were previously interpreted as a first argument. + while ((opt = getopt(argc, argv, "+")) != -1) { + switch (opt) { + default: + ex_usage(); + } + } + + // Check there are enough positional arguments (two for the + // address and at least one to exec into). + if (optind > argc - 3) + ex_usage(); + + // Parse the `cid' argument. + if (!strcmp(argv[optind], "-1")) + cid = VMADDR_CID_ANY; + else if (getu32(argv[optind], 0, UINT32_MAX, &cid)) + ex_usage(); + optind++; + + // Parse the `port' argument. + if (!strcmp(argv[optind], "-1")) + port = VMADDR_PORT_ANY; + else if (getu32(argv[optind], 0, UINT32_MAX, &port)) + ex_usage(); + optind++; + + // Set up the socket. + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (fd == -1) + diee(EX_OSERR, "socket"); + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) + diee(EX_OSERR, "fcntl"); + if (vsock_bind(fd, cid, port) == -1) + diee(EX_OSERR, "bind"); + if (listen(fd, LISTEN_BACKLOG) == -1) + diee(EX_OSERR, "listen"); + + // Place the socket at stdout. + if (dup2(fd, STDIN_FILENO) == -1) + diee(EX_OSERR, "dup2"); + if (fd != STDIN_FILENO) + close(fd); + + // Finally, exec into `prog'. + execvp(argv[optind], &argv[optind]); + diee(EX_OSERR, "execvp"); +} |