summary refs log tree commit diff
path: root/vsockserver-socketbinder.c
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-03-19 03:17:13 +0000
committerAlyssa Ross <hi@alyssa.is>2021-03-21 14:37:33 +0000
commit20a27f13713bb1c7be9bd82ac659e346f5384a51 (patch)
tree43f5c216753b0031a74d5949c0bc7befeca0b25a /vsockserver-socketbinder.c
parent38559b5aa5a6e371a5fd8a20367fc142e02945c3 (diff)
downloaducspi-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.c88
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");
+}