CommandError.cxx 3.84 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2017 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"
21
#include "CommandError.hxx"
22
#include "PlaylistError.hxx"
Max Kellermann's avatar
Max Kellermann committed
23
#include "db/DatabaseError.hxx"
24
#include "client/Response.hxx"
25
#include "Log.hxx"
26
#include "util/Exception.hxx"
27

28 29
#include <system_error>

30 31
#include <assert.h>

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#define GLIBCXX_490 20140422
#define GLIBCXX_491 20140716
#define GLIBCXX_492 20141030
#define GLIBCXX_492_Debian_9 20141220
#define GLIBCXX_493 20150626
#define GLIBCXX_494 20160803
#define GLIBCXX_49X_NDK_r13b 20150123

/* the big mess attempts to detect whether we're compiling with
   libstdc++ 4.9.x; __GLIBCXX__ is a date tag and cannot be used to
   check the major version; and just checking the compiler version
   isn't enough, because somebody could use an old libstdc++ with
   clang - SIGH! */
#if GCC_OLDER_THAN(5,0) || (defined(__GLIBCXX__) &&		     \
	(__GLIBCXX__ == GLIBCXX_490 || __GLIBCXX__ == GLIBCXX_491 || \
	 __GLIBCXX__ == GLIBCXX_492 || \
	 __GLIBCXX__ == GLIBCXX_492_Debian_9 || \
	 __GLIBCXX__ == GLIBCXX_493 || \
	 __GLIBCXX__ == GLIBCXX_494 || \
	 __GLIBCXX__ == GLIBCXX_49X_NDK_r13b))
#define GLIBCXX_49X
#endif

55 56
gcc_const
static enum ack
57
ToAck(PlaylistResult result) noexcept
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
{
	switch (result) {
	case PlaylistResult::SUCCESS:
		break;

	case PlaylistResult::DENIED:
		return ACK_ERROR_PERMISSION;

	case PlaylistResult::NO_SUCH_SONG:
	case PlaylistResult::NO_SUCH_LIST:
		return ACK_ERROR_NO_EXIST;

	case PlaylistResult::LIST_EXISTS:
		return ACK_ERROR_EXIST;

	case PlaylistResult::BAD_NAME:
	case PlaylistResult::BAD_RANGE:
		return ACK_ERROR_ARG;

	case PlaylistResult::NOT_PLAYING:
		return ACK_ERROR_PLAYER_SYNC;

	case PlaylistResult::TOO_LARGE:
		return ACK_ERROR_PLAYLIST_MAX;

	case PlaylistResult::DISABLED:
		break;
	}

	return ACK_ERROR_UNKNOWN;
}

90 91 92
#ifdef ENABLE_DATABASE
gcc_const
static enum ack
93
ToAck(DatabaseErrorCode code) noexcept
94 95 96 97 98 99 100 101 102 103 104 105 106 107
{
	switch (code) {
	case DatabaseErrorCode::DISABLED:
	case DatabaseErrorCode::NOT_FOUND:
		return ACK_ERROR_NO_EXIST;

	case DatabaseErrorCode::CONFLICT:
		return ACK_ERROR_ARG;
	}

	return ACK_ERROR_UNKNOWN;
}
#endif

108 109
gcc_pure
static enum ack
110
ToAck(std::exception_ptr ep) noexcept
111 112 113 114 115 116 117
{
	try {
		std::rethrow_exception(ep);
	} catch (const ProtocolError &pe) {
		return pe.GetCode();
	} catch (const PlaylistError &pe) {
		return ToAck(pe.GetCode());
118 119 120 121
#ifdef ENABLE_DATABASE
	} catch (const DatabaseError &de) {
		return ToAck(de.GetCode());
#endif
122 123
	} catch (const std::system_error &e) {
		return ACK_ERROR_SYSTEM;
124 125
	} catch (const std::invalid_argument &e) {
		return ACK_ERROR_ARG;
126 127 128 129
	} catch (const std::length_error &e) {
		return ACK_ERROR_ARG;
	} catch (const std::out_of_range &e) {
		return ACK_ERROR_ARG;
130
#ifdef GLIBCXX_49X
131 132
	} catch (const std::exception &e) {
#else
133
	} catch (...) {
134
#endif
135
		try {
136
#ifdef GLIBCXX_49X
137 138 139 140
			/* workaround for g++ 4.x: no overload for
			   rethrow_exception(exception_ptr) */
			std::rethrow_if_nested(e);
#else
141
			std::rethrow_if_nested(ep);
142
#endif
143 144 145 146
			return ACK_ERROR_UNKNOWN;
		} catch (...) {
			return ToAck(std::current_exception());
		}
147 148 149
	}
}

150
void
151
PrintError(Response &r, std::exception_ptr ep)
152
{
153
	LogError(ep);
154
	r.Error(ToAck(ep), GetFullMessage(ep).c_str());
155
}