CommandError.cxx 3.69 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 57 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
gcc_const
static enum ack
ToAck(PlaylistResult result)
{
	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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#ifdef ENABLE_DATABASE
gcc_const
static enum ack
ToAck(DatabaseErrorCode code)
{
	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 110 111 112 113 114 115 116 117
gcc_pure
static enum ack
ToAck(std::exception_ptr ep)
{
	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
#ifdef GLIBCXX_49X
127 128
	} catch (const std::exception &e) {
#else
129
	} catch (...) {
130
#endif
131
		try {
132
#ifdef GLIBCXX_49X
133 134 135 136
			/* workaround for g++ 4.x: no overload for
			   rethrow_exception(exception_ptr) */
			std::rethrow_if_nested(e);
#else
137
			std::rethrow_if_nested(ep);
138
#endif
139 140 141 142
			return ACK_ERROR_UNKNOWN;
		} catch (...) {
			return ToAck(std::current_exception());
		}
143 144 145
	}
}

146
void
147
PrintError(Response &r, std::exception_ptr ep)
148
{
149 150
	LogError(ep);
	r.Error(ToAck(ep), FullMessage(ep).c_str());
151
}