Re: s6, listen(8), etc.

From: Daniel Kahn Gillmor <>
Date: Thu, 01 Sep 2016 15:12:30 -0400

I think we might be approaching diminishing returns on this thread, so
please don't take offense if i don't reply too much beyond this. I do
appreciate your taking the time to document your thought process here,
though. thanks!

A couple minor comments:

On Thu 2016-09-01 08:34:18 -0400, Laurent Bercot wrote:
> I agree with this principle entirely. This is good design. The question
> now becomes: how does the daemon know what fd corresponds to what use?
> The simplest, natural answer, used for instance by UCSPI clients and
> servers, is: the fd numbers are hardcoded, they're a part of the daemon
> interface and that should be documented.
> So, in your example, the kresd documentation should say something like:
> - fd 3 must be a datagram socket, that's where kresd will read its
> UDP DNS queries from.
> - fds 4 and 5 must be listening stream sockets, that's where kresd will
> read its TCP DNS queries from. kresd use two sockets for this in order to
> allow one of them to be set up over TLS.
> - fd 6 must be a listening Unix domain stream socket, that's where kresd
> will read its control messages from.

This doesn't allow for the creation of multiple different sockets
e.g. for a daemon expected to listen on distinct IPv6 and IPv4
addresses, but not on all available addresses.

> LISTEN_FD_MAP=udp=3,tcp=4,tls=5,control=6

I'd want the map the other way around: from number to use case, if i was
going to go for a re-design like this, though i suppose it's roughly
equivalent to have udp=3,udp=4,tcp=5 as long as you don't mind having
repeated keys. but meh, this is basically equivalent.

> Or does it? The API still constrains you: even if you can provide labels,
> you still don't send a map, you send a number of fds and a list of labels.
> So you still have to make sure the fds you send are 3, 4, 5, 6 ! And
> if your "listen" program happens to have fd 3 open when it's launched
> (and there may be very good reasons to have some fd already open when you
> run a daemon), well, it has to overwrite it with the udp socket it opens,
> because that's what the API forces you to do. If I want the daemon to run
> with some open fd that's not explicitly passed via LISTEN_FDS (for instance
> if the daemon doesn't have to know it has it open) then I have to make sure
> that my fd is at least 3+$LISTEN_FDS. Talk about unwieldy.

this seems no more unwieldy (probably less unwieldy) than the convention
to always use FD 6 and FD 7. what if i wanted to have some other fd
open on those numbers for some other reason? i'd have to move it out of
the way to use the s6 convention. Note that i'm not claiming this is
terrible, it's only a minor hassle. but it's the same minor hassle as
what you're describing here, no?

> And from the daemon's side? it has to parse the contents of $LISTEN_FDNAMES,
> which is a colon-separated list of labels; that's not really easier than
> parsing my suggested LISTEN_FD_MAP string.

right, it's equivalent.

> So, LISTEN_FDS doesn't know if it wants to pass a list of hardcoded fd
> numbers, or a map with labels; it ends up doing a bit of both, badly, and
> getting the worst of both worlds.

eh? on the contrary: if your daemon doesn't need to distinguish between
any of its sockets -- if all sockets are standard listening sockets
(it can still inspect the socket itself to distinguish between datagram
and stream) then it doesn't care about anything but LISTEN_FDs.

If the daemon receives some sockets (like a local control socket) that
need to be treated differently, then it needs to look at the map. Your
proposed LISTEN_FD_MAP looks precisely equivalent to LISTEN_FDNAMES for
this purpose, with only minor syntactic differences. The non-syntactic
difference, of course, is that multiple daemons written and running
today actually already know how to parse LISTEN_FDNAMES, whether because
they link to libsystemd or do the simple parsing themselves. if
LISTEN_FD_MAP had gotten there first, i would have made listen(8)
implement that labeling scheme.

> Oh, and I haven't entirely given up my argument of political agenda.
> The only reason you could have for designing such a whimsical interface,
> apart from obvious lack of experience in software design, is to encourage
> daemon authors to use the sd_listen_fds_with_names() interface (and so,
> link against libsystemd), because it's too painful to fully implement it
> yourself as a daemon author - you have to handle the case when
> LISTEN_FD_NAMES is set, the case when it's not set, etc. etc.

(i don't think that baseless slights against the authors of other
software advance your cause here) on the technical merits, i really
don't see it as difficult as you're making it out to be. When this
convention is in use, your daemon already knows whether it needs to
parse LISTEN_FDNAMES, or whether it can get away with just looking at
LISTEN_FDS. in any case, both will be set. And there is absolutely no
need to link against libsystemd.

For example:

patches to enable a simple daemon that doesn't need to parse

patches to convert a more complex daemon with multiple types of
listeners (and has to parse LISTEN_FDNAMES):

It's a little more than 15 lines of C under this particular project's
coding conventions, but not much.

> I have written a small wrapper so that daemons can avoid using
> sd_notify():
> I think I should write a similar wrapper so that daemons can avoid using
> sd_listen_fds_with_names(), and can just read an fd map from the environment,
> while still being usable under systemd that uses the LISTEN_FDS
> mechanism.

I'd still call LISTEN_FDS a "convention" and not a "mechanism", fwiw.
I'd be interested in seeing a pointer to anything you write up. Please
post it here!

Thanks for the discussion,


Received on Thu Sep 01 2016 - 19:12:30 UTC

This archive was generated by hypermail 2.3.0 : Sun May 09 2021 - 19:44:19 UTC