summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Strauss <david@davidstrauss.net>2013-11-25 10:44:48 +1000
committerDavid Strauss <david@davidstrauss.net>2013-11-25 10:46:48 +1000
commitadcf4c81c58511b67644e17fa743d1729d3c9ccf (patch)
tree573e97f2f2cce161a0e8b3e8c67a2f1e37c931a0
parent828db5d84afbf4e6e7060b5da170114a5886b339 (diff)
socket-proxyd: Add --listener option for listener/destination pairs.
-rw-r--r--TODO1
-rw-r--r--man/systemd-socket-proxyd.xml80
-rw-r--r--src/socket-proxy/socket-proxyd.c63
3 files changed, 121 insertions, 23 deletions
diff --git a/TODO b/TODO
index f79f7b1015..9b898bb57d 100644
--- a/TODO
+++ b/TODO
@@ -105,7 +105,6 @@ Features:
* remove NSS usage from PID 1 (notably the specifiers)
* socket-proxyd:
- - Support multiple inherited sockets mapped to different remote hosts
- Use a nonblocking alternative to getaddrinfo
- Until we can start daemons directly, find a less ugly, less racy alternative than shell scripts for the second man page example.
- Support starting daemons directly without requiring a shell script; update man pages
diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml
index 4eb13e4d25..d57a59cf79 100644
--- a/man/systemd-socket-proxyd.xml
+++ b/man/systemd-socket-proxyd.xml
@@ -31,6 +31,12 @@
<surname>Strauss</surname>
<email>david@davidstrauss.net</email>
</author>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Lennart</firstname>
+ <surname>Poettering</surname>
+ <email>lennart@poettering.net</email>
+ </author>
</authorgroup>
</refentryinfo>
<refmeta>
@@ -84,6 +90,17 @@
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
+ <term><option>-l</option></term>
+ <term><option>--listener</option></term>
+ <listitem>
+ <para>Restricts listening to a
+ single inherited socket, specified
+ as a file descriptor. By default,
+ the proxy listens on all inherited
+ sockets.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><option>-h</option></term>
<term><option>--help</option></term>
<listitem>
@@ -196,8 +213,12 @@ while [ ! -f /tmp/nginx.pid ]
do
/usr/bin/inotifywait /tmp/nginx.pid
done
-exec /usr/bin/systemd-socket-proxyd localhost 8080]]>
+exec /usr/bin/systemd-socket-proxyd localhost:8080]]>
</programlisting>
+ <para>Make it executable:</para>
+ <programlisting>
+<![CDATA[chmod 755 /usr/bin/socket-proxyd-nginx.sh]]>
+ </programlisting>
</example>
<example label="nginx configuration">
<title>
@@ -218,6 +239,63 @@ $ curl http://localhost:80/]]>
</programlisting>
</example>
</refsect2>
+
+ <refsect2>
+ <title>Multiple Listeners with Multiple Destinations</title>
+ <para>When using namespaces, it may be useful to
+ have multiple listeners with each going to a unique
+ destination. systemd always passes sockets into
+ services in the order specified in the socket
+ unit, beginning with file descriptor 3.</para>
+ <para>In this example, port <literal>80</literal>
+ will proxy to <literal>localhost:8080</literal>,
+ and port <literal>443</literal> will proxy to
+ <literal>localhost:8443</literal>.</para>
+ <example label="proxy socket unit">
+ <title>/etc/systemd/system/multi-destination.socket</title>
+ <programlisting>
+<![CDATA[[Socket]
+ListenStream=80
+ListenStream=443
+
+[Install]
+WantedBy=sockets.target]]>
+</programlisting>
+ </example>
+ <example label="proxy service unit">
+ <title>/etc/systemd/system/multi-destination.service</title>
+ <programlisting>
+<![CDATA[[Service]
+ExecStart=/usr/bin/socket-proxyd-multi-destination.sh
+PrivateTmp=true
+PrivateNetwork=true]]>
+</programlisting>
+ </example>
+
+ <example label="shell script">
+ <title>
+ /usr/bin/socket-proxyd-multi-destination.sh</title>
+ <programlisting>
+<![CDATA[#!/bin/sh
+/usr/bin/systemd-socket-proxyd --listener=3 localhost:8080 &
+/usr/bin/systemd-socket-proxyd --listener=4 localhost:8443 &
+wait]]>
+</programlisting>
+ <para>Make it executable:</para>
+ <programlisting>
+<![CDATA[chmod 755 /usr/bin/socket-proxyd-multi-destination.sh]]>
+ </programlisting>
+ </example>
+
+ <example label="commands">
+ <programlisting>
+<![CDATA[# systemctl enable multi-destination.socket
+# systemctl start multi-destination.socket
+$ curl http://localhost/
+$ curl https://localhost/]]>
+</programlisting>
+ </example>
+ </refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 432558d190..362e8aae9f 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -66,6 +66,7 @@ typedef struct Connection {
} Connection;
static const char *arg_remote_host = NULL;
+static int arg_listener = -1;
static void connection_free(Connection *c) {
assert(c);
@@ -554,8 +555,9 @@ static int help(void) {
printf("%s [HOST:PORT]\n"
"%s [SOCKET]\n\n"
"Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n",
+ " -l --listener=FD Listen on a specific, single file descriptor.\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n",
program_invocation_short_name,
program_invocation_short_name);
@@ -565,22 +567,22 @@ static int help(void) {
static int parse_argv(int argc, char *argv[]) {
enum {
- ARG_VERSION = 0x100,
- ARG_IGNORE_ENV
+ ARG_VERSION = 0x100
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "listener", required_argument, NULL, 'l' },
{}
};
- int c;
+ int c, fd;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "hl:", options, NULL)) >= 0) {
switch (c) {
@@ -592,6 +594,18 @@ static int parse_argv(int argc, char *argv[]) {
puts(SYSTEMD_FEATURES);
return 0;
+ case 'l':
+ if (safe_atoi(optarg, &fd) < 0) {
+ log_error("Failed to parse listener file descriptor: %s", optarg);
+ return -EINVAL;
+ }
+ if (fd < SD_LISTEN_FDS_START) {
+ log_error("Listener file descriptor must be at least %d.", SD_LISTEN_FDS_START);
+ return -EINVAL;
+ }
+ arg_listener = fd;
+ break;
+
case '?':
return -EINVAL;
@@ -632,19 +646,26 @@ int main(int argc, char *argv[]) {
goto finish;
}
- n = sd_listen_fds(1);
- if (n < 0) {
- log_error("Failed to receive sockets from parent.");
- r = n;
- goto finish;
- } else if (n == 0) {
- log_error("Didn't get any sockets passed in.");
- r = -EINVAL;
- goto finish;
- }
-
- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
- r = add_listen_socket(&context, event, fd);
+ if (arg_listener == -1) {
+ n = sd_listen_fds(1);
+ if (n < 0) {
+ log_error("Failed to receive sockets from parent.");
+ r = n;
+ goto finish;
+ } else if (n == 0) {
+ log_error("Didn't get any sockets passed in.");
+ r = -EINVAL;
+ goto finish;
+ }
+ log_info("Listening on %d inherited socket(s), starting with fd=%d.", n, SD_LISTEN_FDS_START);
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
+ r = add_listen_socket(&context, event, fd);
+ if (r < 0)
+ goto finish;
+ }
+ } else {
+ log_info("Listening on single inherited socket fd=%d.", arg_listener);
+ r = add_listen_socket(&context, event, arg_listener);
if (r < 0)
goto finish;
}