From 0e8cd3b961a29058ee5f4d507170243d237994ef Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 29 Jan 2025 16:07:39 +0100 Subject: [PATCH] client/Process: explicitly disallow "idle" and "noidle" in command lists These commands cannot possibly work with command lists because command lists are supposed to be atomic, but suspended command execution conflicts with that. Closes https://github.com/MusicPlayerDaemon/MPD/issues/2167 --- NEWS | 1 + doc/protocol.rst | 3 +++ src/client/Process.cxx | 14 ++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/NEWS b/NEWS index 123e5e886..9690d84a0 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.23.17 (not yet released) * protocol - "albumart" tries to send larger chunks if available + - explicitly disallow "idle" and "noidle" in command lists * storage - nfs: require libnfs 4.0 or later * database diff --git a/doc/protocol.rst b/doc/protocol.rst index 6c105c3e2..2677f5f83 100644 --- a/doc/protocol.rst +++ b/doc/protocol.rst @@ -156,6 +156,9 @@ fails, no more commands are executed and the appropriate ``list_OK`` is returned for each successful command executed in the command list. +Only synchronous commands can be used in command lists. Commands that +suspend execution (``idle`` and ``noidle``) are not allowed. + Ranges ====== diff --git a/src/client/Process.cxx b/src/client/Process.cxx index 041e339c7..69bd78862 100644 --- a/src/client/Process.cxx +++ b/src/client/Process.cxx @@ -52,6 +52,13 @@ Client::ProcessCommandList(bool list_ok, return CommandResult::OK; } +[[gnu::pure]] +static bool +IsAsyncCommmand(const char *line) noexcept +{ + return StringIsEqual(line, "idle") || StringIsEqual(line, "noidle"); +} + CommandResult Client::ProcessLine(char *line) noexcept { @@ -67,6 +74,13 @@ Client::ProcessLine(char *line) noexcept return CommandResult::CLOSE; } + if (cmd_list.IsActive() && IsAsyncCommmand(line)) { + FmtWarning(client_domain, + "[{}] not possible in comand list: \"{}\"", + num, line); + return CommandResult::CLOSE; + } + if (StringIsEqual(line, "noidle")) { if (idle_waiting) { /* send empty idle response and leave idle mode */