From 52652cb609831569c383d652b5afee5076663b5f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 29 Dec 2016 14:28:03 +0100 Subject: [PATCH] command/{Player,Error}: extract messages from nested exceptions --- Makefile.am | 1 + src/command/CommandError.cxx | 11 ++------ src/command/PlayerCommands.cxx | 6 ++-- src/util/Exception.cxx | 50 ++++++++++++++++++++++++++++++++++ src/util/Exception.hxx | 43 +++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 src/util/Exception.cxx create mode 100644 src/util/Exception.hxx diff --git a/Makefile.am b/Makefile.am index 1bff2e27b..78e30ffbe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -388,6 +388,7 @@ endif # Generic utility library libutil_a_SOURCES = \ + src/util/Exception.cxx src/util/Exception.hxx \ src/util/RuntimeError.hxx \ src/util/Macros.hxx \ src/util/BindMethod.hxx \ diff --git a/src/command/CommandError.cxx b/src/command/CommandError.cxx index 74fca78ab..eecca1158 100644 --- a/src/command/CommandError.cxx +++ b/src/command/CommandError.cxx @@ -23,6 +23,7 @@ #include "db/DatabaseError.hxx" #include "client/Response.hxx" #include "Log.hxx" +#include "util/Exception.hxx" #include @@ -122,12 +123,6 @@ ToAck(std::exception_ptr ep) void PrintError(Response &r, std::exception_ptr ep) { - try { - std::rethrow_exception(ep); - } catch (const std::exception &e) { - LogError(e); - r.Error(ToAck(ep), e.what()); - } catch (...) { - r.Error(ACK_ERROR_UNKNOWN, "Unknown error"); - } + LogError(ep); + r.Error(ToAck(ep), FullMessage(ep).c_str()); } diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx index ec4142b7b..b96f4a13f 100644 --- a/src/command/PlayerCommands.cxx +++ b/src/command/PlayerCommands.cxx @@ -31,6 +31,7 @@ #include "Idle.hxx" #include "AudioFormat.hxx" #include "util/ScopeExit.hxx" +#include "util/Exception.hxx" #ifdef ENABLE_DATABASE #include "db/update/Service.hxx" @@ -192,10 +193,9 @@ handle_status(Client &client, gcc_unused Request args, Response &r) try { client.player_control.LockCheckRethrowError(); - } catch (const std::exception &e) { - r.Format(COMMAND_STATUS_ERROR ": %s\n", e.what()); } catch (...) { - r.Format(COMMAND_STATUS_ERROR ": unknown\n"); + r.Format(COMMAND_STATUS_ERROR ": %s\n", + FullMessage(std::current_exception()).c_str()); } song = playlist.GetNextPosition(); diff --git a/src/util/Exception.cxx b/src/util/Exception.cxx new file mode 100644 index 000000000..06201cbc0 --- /dev/null +++ b/src/util/Exception.cxx @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Exception.hxx" + +#include + +std::string +FullMessage(std::exception_ptr ep) +{ + try { + std::rethrow_exception(ep); + } catch (const std::exception &e) { + try { + std::rethrow_if_nested(e); + return e.what(); + } catch (...) { + return std::string(e.what()) + "; " + + FullMessage(std::current_exception()); + } + } + + return std::string("Unknown error"); +} diff --git a/src/util/Exception.hxx b/src/util/Exception.hxx new file mode 100644 index 000000000..7e36c3d85 --- /dev/null +++ b/src/util/Exception.hxx @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EXCEPTION_HXX +#define EXCEPTION_HXX + +#include +#include + +/** + * Extract the full message of a C++ exception, considering its nested + * exceptions (if any). + */ +std::string +FullMessage(std::exception_ptr ep); + +#endif