From 56112a237ce9a86936d99d7e48eeaaf6e1fae041 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 30 Oct 2018 18:37:32 +0100 Subject: [PATCH] Listen: listen on $XDG_RUNTIME_DIR/mpd/socket by default --- NEWS | 1 + doc/user.rst | 3 +++ src/Listen.cxx | 63 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2b97662b5..a6db643c8 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,7 @@ ver 0.21 (not yet released) - sndio: new mixer plugin * encoder - opus: support for sending metadata using ogg stream chaining +* listen on $XDG_RUNTIME_DIR/mpd/socket by default * systemd watchdog support * require GCC 6 * build with Meson instead of autotools diff --git a/doc/user.rst b/doc/user.rst index 0bf4b9a76..1d7566f50 100644 --- a/doc/user.rst +++ b/doc/user.rst @@ -471,6 +471,9 @@ used multiple times to bind to more than one address. Example:: bind_to_address "127.0.0.1" The default is "any", which binds to all available addresses. +Additionally, MPD binds to :code:`$XDG_RUNTIME_DIR/mpd/socket` (if it +was launched as a per-user daemon and no :code:`bind_to_address` +setting exists). You can set a port that is different from the global port setting, e.g. "localhost:6602". IPv6 addresses must be enclosed in square diff --git a/src/Listen.cxx b/src/Listen.cxx index 4d7b4f9e9..aeb890e0c 100644 --- a/src/Listen.cxx +++ b/src/Listen.cxx @@ -19,16 +19,20 @@ #include "config.h" #include "Listen.hxx" +#include "Log.hxx" #include "client/Listener.hxx" #include "config/Param.hxx" #include "config/Data.hxx" #include "config/Option.hxx" #include "config/Net.hxx" +#include "net/AllocatedSocketAddress.hxx" #include "net/UniqueSocketDescriptor.hxx" +#include "net/SocketUtil.hxx" #include "system/Error.hxx" #include "util/RuntimeError.hxx" #include "fs/AllocatedPath.hxx" +#include #include #include @@ -61,6 +65,51 @@ listen_systemd_activation(ClientListener &listener) #endif +/** + * Listen on "$XDG_RUNTIME_DIR/mpd/socket" (if applicable). + * + * @return true if a listener socket was added + */ +static bool +ListenXdgRuntimeDir(ClientListener &listener) noexcept +{ +#if defined(_WIN32) || defined(ANDROID) || !defined(HAVE_UN) + (void)listener; + return false; +#else + if (geteuid() == 0) + /* this MPD instance is a system-wide daemon; don't + use $XDG_RUNTIME_DIR */ + return false; + + Path xdg_runtime_dir = Path::FromFS(getenv("XDG_RUNTIME_DIR")); + if (xdg_runtime_dir.IsNull()) + return false; + + const auto mpd_runtime_dir = xdg_runtime_dir / Path::FromFS("mpd"); + mkdir(mpd_runtime_dir.c_str(), 0700); + + const auto socket_path = mpd_runtime_dir / Path::FromFS("socket"); + unlink(socket_path.c_str()); + + AllocatedSocketAddress address; + address.SetLocal(socket_path.c_str()); + + try { + auto fd = socket_bind_listen(AF_LOCAL, SOCK_STREAM, 0, + address, 5); + chmod(socket_path.c_str(), 0600); + listener.AddFD(std::move(fd), std::move(address)); + return true; + } catch (...) { + FormatError(std::current_exception(), + "Failed to listen on '%s' (not fatal)", + socket_path.c_str()); + return false; + } +#endif +} + void listen_global_init(const ConfigData &config, ClientListener &listener) { @@ -82,10 +131,14 @@ listen_global_init(const ConfigData &config, ClientListener &listener) } } + bool have_xdg_runtime_listener = false; + if (listener.IsEmpty()) { /* no "bind_to_address" configured, bind the configured port on all interfaces */ + have_xdg_runtime_listener = ListenXdgRuntimeDir(listener); + try { listener.AddPort(port); } catch (...) { @@ -93,7 +146,15 @@ listen_global_init(const ConfigData &config, ClientListener &listener) } } - listener.Open(); + try { + listener.Open(); + } catch (...) { + if (have_xdg_runtime_listener) + LogError(std::current_exception(), + "Default TCP listener setup failed, but this is okay because we have a $XDG_RUNTIME_DIR listener"); + else + throw; + } listen_port = port; }