diff --git a/Makefile.am b/Makefile.am index eb896f8d4..39fcde0a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -278,6 +278,25 @@ ALSA_SOURCES = \ src/lib/alsa/PeriodBuffer.hxx \ src/lib/alsa/NonBlock.cxx src/lib/alsa/NonBlock.hxx +if ENABLE_DBUS +noinst_LIBRARIES += libodbus.a +libodbus_a_SOURCES = \ + src/lib/dbus/AppendIter.hxx \ + src/lib/dbus/Connection.cxx src/lib/dbus/Connection.hxx \ + src/lib/dbus/Error.cxx src/lib/dbus/Error.hxx \ + src/lib/dbus/Iter.hxx \ + src/lib/dbus/Message.cxx src/lib/dbus/Message.hxx \ + src/lib/dbus/PendingCall.hxx \ + src/lib/dbus/ReadIter.hxx \ + src/lib/dbus/ObjectManager.hxx \ + src/lib/dbus/UDisks2.hxx \ + src/lib/dbus/ScopeMatch.cxx src/lib/dbus/ScopeMatch.hxx \ + src/lib/dbus/Types.hxx \ + src/lib/dbus/Values.hxx \ + src/lib/dbus/Watch.cxx src/lib/dbus/Watch.hxx +libodbus_a_CPPFLAGS = $(AM_CPPFLAGS) $(DBUS_CFLAGS) +endif + # # Android native library # diff --git a/configure.ac b/configure.ac index fcda38e85..1dea3e8f2 100644 --- a/configure.ac +++ b/configure.ac @@ -626,6 +626,12 @@ if test x$enable_libwrap = xyes; then AC_DEFINE(HAVE_LIBWRAP, 1, [define to enable libwrap library]) fi +dnl --------------------------------------------------------------------------- +dnl D-Bus +dnl --------------------------------------------------------------------------- + +MPD_ENABLE_AUTO_PKG(dbus, DBUS, [dbus-1], [D-Bus support], [dbus-1 not found]) + dnl --------------------------------------------------------------------------- dnl Metadata Plugins dnl --------------------------------------------------------------------------- @@ -1501,6 +1507,7 @@ results(soxr, [libsoxr]) results(libmpdclient, [libmpdclient]) results(inotify, [inotify]) results(sqlite, [SQLite]) +results(dbus, [DBUS]) printf '\nMetadata support:\n\t' results(id3,[ID3]) diff --git a/src/CommandLine.cxx b/src/CommandLine.cxx index 6d74443f3..b615cab27 100644 --- a/src/CommandLine.cxx +++ b/src/CommandLine.cxx @@ -223,6 +223,9 @@ static void version(void) #ifdef HAVE_AVAHI " avahi" #endif +#ifdef ENABLE_DBUS + " dbus" +#endif #ifdef USE_EPOLL " epoll" #endif diff --git a/src/lib/dbus/AppendIter.hxx b/src/lib/dbus/AppendIter.hxx new file mode 100644 index 000000000..b5859c260 --- /dev/null +++ b/src/lib/dbus/AppendIter.hxx @@ -0,0 +1,204 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_APPEND_ITER_HXX +#define ODBUS_APPEND_ITER_HXX + +#include "Iter.hxx" +#include "Values.hxx" + +namespace ODBus { + +class AppendMessageIter : public MessageIter { +public: + explicit AppendMessageIter(DBusMessage &msg) noexcept { + dbus_message_iter_init_append(&msg, &iter); + } + + AppendMessageIter(AppendMessageIter &parent, int type, + const char *contained_signature) { + if (!dbus_message_iter_open_container(&parent.iter, type, + contained_signature, &iter)) + throw std::runtime_error("dbus_message_iter_open_container() failed"); + } + + AppendMessageIter &CloseContainer(AppendMessageIter &parent) { + if (!dbus_message_iter_close_container(&parent.iter, &iter)) + throw std::runtime_error("dbus_message_iter_close_container() failed"); + + return parent; + } + + AppendMessageIter &AppendBasic(int type, const void *value) { + if (!dbus_message_iter_append_basic(&iter, type, value)) + throw std::runtime_error("dbus_message_iter_append_basic() failed"); + return *this; + } + + AppendMessageIter &Append(const char *const&value) { + return AppendBasic(DBUS_TYPE_STRING, &value); + } + + AppendMessageIter &Append(const uint32_t &value) { + return AppendBasic(DBUS_TYPE_UINT32, &value); + } + + AppendMessageIter &AppendFixedArray(int element_type, + const void *value, + int n_elements) { + if (!dbus_message_iter_append_fixed_array(&iter, element_type, + &value, n_elements)) + throw std::runtime_error("dbus_message_iter_append_fixed_array() failed"); + + return *this; + }; + + AppendMessageIter &AppendFixedArray(ConstBuffer value) { + return AppendFixedArray(DBUS_TYPE_UINT32, + value.data, value.size); + } + + AppendMessageIter &Append(ConstBuffer value) { + return AppendMessageIter(*this, DBUS_TYPE_ARRAY, + DBUS_TYPE_UINT32_AS_STRING) + .AppendFixedArray(value) + .CloseContainer(*this); + } + + template + AppendMessageIter &AppendEmptyArray() { + return AppendMessageIter(*this, DBUS_TYPE_ARRAY, + T::TypeAsString::value) + .CloseContainer(*this); + } + + template + AppendMessageIter &AppendVariant(const char *contained_signature, + T &&value) { + return AppendMessageIter(*this, DBUS_TYPE_VARIANT, + contained_signature) + .Append(std::forward(value)) + .CloseContainer(*this); + } + + template + AppendMessageIter &AppendVariant(const T &value) { + typedef VariantTypeTraits Traits; + return AppendMessageIter(*this, Traits::TYPE, + Traits::TypeAsString::value) + .Append(value) + .CloseContainer(*this); + } + + template + AppendMessageIter &Append(BasicValue value) { + typedef decltype(value) W; + typedef typename W::Traits Traits; + + return AppendBasic(Traits::TYPE, &value.value); + } + + AppendMessageIter &Append(const Boolean &value) { + typedef typename Boolean::Traits Traits; + + return AppendBasic(Traits::TYPE, &value.value); + } + + template + AppendMessageIter &Append(WrapVariant value) { + typedef decltype(value) W; + typedef typename W::Traits Traits; + typedef typename W::ContainedTraits ContainedTraits; + + return AppendMessageIter(*this, Traits::TYPE, + ContainedTraits::TypeAsString::value) + .Append(value.value) + .CloseContainer(*this); + } + + template + AppendMessageIter &Append(WrapFixedArray value) { + typedef decltype(value) W; + typedef typename W::Traits Traits; + typedef typename W::ContainedTraits ContainedTraits; + + return AppendMessageIter(*this, Traits::TYPE, + ContainedTraits::TypeAsString::value) + .AppendFixedArray(value.value) + .CloseContainer(*this); + } + + template + struct _AppendTuple { + AppendMessageIter &operator()(AppendMessageIter &iter, std::tuple value) { + return _AppendTuple()(iter.Append(std::get(value)), + value); + } + }; + + template + struct _AppendTuple<0, T...> { + AppendMessageIter &operator()(AppendMessageIter &iter, std::tuple) { + return iter; + } + }; + + template + AppendMessageIter &AppendTuple(std::tuple value) { + return _AppendTuple()(*this, value); + } + + template + AppendMessageIter &Append(WrapStruct value) { + typedef decltype(value) W; + typedef typename W::Traits Traits; + + return AppendMessageIter(*this, Traits::TYPE, nullptr) + .AppendTuple(value.values) + .CloseContainer(*this); + } + + /** + * Like Append(), but only do it if the first argument is + * true. + */ + template + AppendMessageIter &AppendOptional(bool enabled, T &&value) { + return enabled + ? Append(std::forward(value)) + : *this; + } +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/Connection.cxx b/src/lib/dbus/Connection.cxx new file mode 100644 index 000000000..8564dfec8 --- /dev/null +++ b/src/lib/dbus/Connection.cxx @@ -0,0 +1,52 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 "Connection.hxx" +#include "Error.hxx" + +ODBus::Connection +ODBus::Connection::GetSystem() +{ + ODBus::Error error; + auto *c = dbus_bus_get(DBUS_BUS_SYSTEM, error); + error.CheckThrow("DBus connection error"); + return Connection(c); +} + +ODBus::Connection +ODBus::Connection::Open(const char *address) +{ + ODBus::Error error; + auto *c = dbus_connection_open(address, error); + error.CheckThrow("DBus connection error"); + return Connection(c); +} diff --git a/src/lib/dbus/Connection.hxx b/src/lib/dbus/Connection.hxx new file mode 100644 index 000000000..8ebb6e84d --- /dev/null +++ b/src/lib/dbus/Connection.hxx @@ -0,0 +1,85 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_CONNECTION_HXX +#define ODBUS_CONNECTION_HXX + +#include + +#include +#include + +namespace ODBus { + +/** + * OO wrapper for a #DBusConnection. + */ +class Connection { + DBusConnection *c = nullptr; + + explicit Connection(DBusConnection *_c) noexcept + :c(_c) {} + +public: + Connection() noexcept = default; + + Connection(const Connection &src) noexcept + :c(dbus_connection_ref(src.c)) {} + + Connection(Connection &&src) noexcept + :c(std::exchange(src.c, nullptr)) {} + + ~Connection() noexcept { + if (c != nullptr) + dbus_connection_unref(c); + } + + Connection &operator=(Connection &&src) noexcept { + std::swap(c, src.c); + return *this; + } + + static Connection GetSystem(); + static Connection Open(const char *address); + + operator DBusConnection *() noexcept { + return c; + } + + operator bool() const noexcept { + return c != nullptr; + } +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/Error.cxx b/src/lib/dbus/Error.cxx new file mode 100644 index 000000000..57d96fc81 --- /dev/null +++ b/src/lib/dbus/Error.cxx @@ -0,0 +1,47 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 "Error.hxx" +#include "util/RuntimeError.hxx" + +void +ODBus::Error::Throw(const char *prefix) const +{ + throw FormatRuntimeError("%s: %s", prefix, GetMessage()); +} + +void +ODBus::Error::CheckThrow(const char *prefix) const +{ + if (*this) + Throw(prefix); +} diff --git a/src/lib/dbus/Error.hxx b/src/lib/dbus/Error.hxx new file mode 100644 index 000000000..602dca892 --- /dev/null +++ b/src/lib/dbus/Error.hxx @@ -0,0 +1,81 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_ERROR_HXX +#define ODBUS_ERROR_HXX + +#include "Compiler.h" + +#include + +namespace ODBus { + +class Error { + DBusError error; + +public: + Error() noexcept { + dbus_error_init(&error); + } + + ~Error() noexcept { + dbus_error_free(&error); + } + + Error(const Error &) = delete; + Error &operator=(const Error &) = delete; + + gcc_pure + operator bool() const noexcept { + return dbus_error_is_set(&error); + } + + operator DBusError &() noexcept { + return error; + } + + operator DBusError *() noexcept { + return &error; + } + + const char *GetMessage() const noexcept { + return error.message; + } + + gcc_noreturn + void Throw(const char *prefix) const; + void CheckThrow(const char *prefix) const; +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/Iter.hxx b/src/lib/dbus/Iter.hxx new file mode 100644 index 000000000..86e73d3ed --- /dev/null +++ b/src/lib/dbus/Iter.hxx @@ -0,0 +1,51 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_ITER_HXX +#define ODBUS_ITER_HXX + +namespace ODBus { + +class MessageIter { +protected: + DBusMessageIter iter; + + MessageIter() = default; + +public: + MessageIter(const MessageIter &) = delete; + MessageIter &operator=(const MessageIter &) = delete; +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/Message.cxx b/src/lib/dbus/Message.cxx new file mode 100644 index 000000000..5206af9f3 --- /dev/null +++ b/src/lib/dbus/Message.cxx @@ -0,0 +1,79 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 "Message.hxx" +#include "ReadIter.hxx" + +ODBus::Message +ODBus::Message::NewMethodCall(const char *destination, + const char *path, + const char *iface, + const char *method) +{ + auto *msg = dbus_message_new_method_call(destination, path, + iface, method); + if (msg == nullptr) + throw std::runtime_error("dbus_message_new_method_call() failed"); + + return Message(msg); +} + +ODBus::Message +ODBus::Message::StealReply(DBusPendingCall &pending) +{ + auto *msg = dbus_pending_call_steal_reply(&pending); + if (msg == nullptr) + throw std::runtime_error("dbus_pending_call_steal_reply() failed"); + + return Message(msg); +} + +ODBus::Message +ODBus::Message::Pop(DBusConnection &connection) +{ + auto *msg = dbus_connection_pop_message(&connection); + return Message(msg); +} + +void +ODBus::Message::CheckThrowError() +{ + if (GetType() != DBUS_MESSAGE_TYPE_ERROR) + return; + + ReadMessageIter iter(*msg); + + if (iter.GetArgType() != DBUS_TYPE_STRING) + throw std::runtime_error("No DBUS_MESSAGE_TYPE_ERROR message"); + + throw std::runtime_error(iter.GetString()); +} diff --git a/src/lib/dbus/Message.hxx b/src/lib/dbus/Message.hxx new file mode 100644 index 000000000..f759ddac9 --- /dev/null +++ b/src/lib/dbus/Message.hxx @@ -0,0 +1,156 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_MESSAGE_HXX +#define ODBUS_MESSAGE_HXX + +#include + +#include +#include + +namespace ODBus { + +class Message { + DBusMessage *msg = nullptr; + + explicit Message(DBusMessage *_msg) noexcept + :msg(_msg) {} + +public: + Message() noexcept = default; + + Message(Message &&src) noexcept + :msg(std::exchange(src.msg, nullptr)) {} + + ~Message() noexcept { + if (msg != nullptr) + dbus_message_unref(msg); + } + + DBusMessage *Get() noexcept { + return msg; + } + + Message &operator=(Message &&src) noexcept { + std::swap(msg, src.msg); + return *this; + } + + static Message NewMethodCall(const char *destination, + const char *path, + const char *iface, + const char *method); + + static Message StealReply(DBusPendingCall &pending); + + static Message Pop(DBusConnection &connection); + + bool IsDefined() const noexcept { + return msg != nullptr; + } + + int GetType() noexcept { + return dbus_message_get_type(msg); + } + + const char *GetPath() noexcept { + return dbus_message_get_path(msg); + } + + bool HasPath(const char *object_path) noexcept { + return dbus_message_has_path(msg, object_path); + } + + const char *GetInterface() noexcept { + return dbus_message_get_interface(msg); + } + + bool HasInterface(const char *iface) noexcept { + return dbus_message_has_interface(msg, iface); + } + + const char *GetMember() noexcept { + return dbus_message_get_member(msg); + } + + bool HasMember(const char *member) noexcept { + return dbus_message_has_member(msg, member); + } + + bool IsError(const char *error_name) const noexcept { + return dbus_message_is_error(msg, error_name); + } + + const char *GetErrorName() const noexcept { + return dbus_message_get_error_name(msg); + } + + const char *GetDestination() const noexcept { + return dbus_message_get_destination(msg); + } + + const char *GetSender() const noexcept { + return dbus_message_get_sender(msg); + } + + const char *GetSignature() const noexcept { + return dbus_message_get_signature(msg); + } + + bool GetNoReply() const noexcept { + return dbus_message_get_no_reply(msg); + } + + bool IsMethodCall(const char *iface, + const char *method) const noexcept { + return dbus_message_is_method_call(msg, iface, method); + } + + bool IsSignal(const char *iface, + const char *signal_name) const noexcept { + return dbus_message_is_signal(msg, iface, signal_name); + } + + void CheckThrowError(); + + template + bool GetArgs(DBusError &error, Args... args) noexcept { + return dbus_message_get_args(msg, &error, + std::forward(args)..., + DBUS_TYPE_INVALID); + } +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/ObjectManager.hxx b/src/lib/dbus/ObjectManager.hxx new file mode 100644 index 000000000..d58fb9101 --- /dev/null +++ b/src/lib/dbus/ObjectManager.hxx @@ -0,0 +1,50 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * 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. + */ + +#ifndef ODBUS_OBJECT_MANAGER_HXX +#define ODBUS_OBJECT_MANAGER_HXX + +#include + +#define DBUS_OM_INTERFACE "org.freedesktop.DBus.ObjectManager" + +#define DBUS_OM_PROPERTIES_SIGNATURE \ + DBUS_TYPE_ARRAY_AS_STRING \ + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \ + DBUS_TYPE_STRING_AS_STRING \ + DBUS_TYPE_VARIANT_AS_STRING \ + DBUS_DICT_ENTRY_END_CHAR_AS_STRING + +#define DBUS_OM_INTERFACES_SIGNATURE \ + DBUS_TYPE_ARRAY_AS_STRING \ + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \ + DBUS_TYPE_STRING_AS_STRING \ + DBUS_OM_PROPERTIES_SIGNATURE \ + DBUS_DICT_ENTRY_END_CHAR_AS_STRING + +#define DBUS_OM_INTERFACES_ADDED_SIGNATURE \ + DBUS_TYPE_OBJECT_PATH_AS_STRING \ + DBUS_OM_INTERFACES_SIGNATURE + +#define DBUS_OM_INTERFACES_REMOVED_SIGNATURE \ + DBUS_TYPE_OBJECT_PATH_AS_STRING \ + DBUS_TYPE_ARRAY_AS_STRING \ + DBUS_TYPE_STRING_AS_STRING + +#endif diff --git a/src/lib/dbus/PendingCall.hxx b/src/lib/dbus/PendingCall.hxx new file mode 100644 index 000000000..f323f398b --- /dev/null +++ b/src/lib/dbus/PendingCall.hxx @@ -0,0 +1,108 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_PENDING_CALL_HXX +#define ODBUS_PENDING_CALL_HXX + +#include + +#include +#include + +namespace ODBus { + +class PendingCall { + DBusPendingCall *pending = nullptr; + + explicit PendingCall(DBusPendingCall *_pending) noexcept + :pending(_pending) {} + +public: + PendingCall() noexcept = default; + + PendingCall(PendingCall &&src) noexcept + :pending(std::exchange(src.pending, nullptr)) {} + + ~PendingCall() noexcept { + if (pending != nullptr) + dbus_pending_call_unref(pending); + } + + operator bool() const noexcept { + return pending; + } + + DBusPendingCall *Get() noexcept { + return pending; + } + + PendingCall &operator=(PendingCall &&src) noexcept { + std::swap(pending, src.pending); + return *this; + } + + static PendingCall SendWithReply(DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds=-1) { + DBusPendingCall *pending; + if (!dbus_connection_send_with_reply(connection, + message, + &pending, + timeout_milliseconds)) + throw std::runtime_error("dbus_connection_send_with_reply() failed"); + + if (pending == nullptr) + throw std::runtime_error("dbus_connection_send_with_reply() failed with pending=NULL"); + + return PendingCall(pending); + } + + bool SetNotify(DBusPendingCallNotifyFunction function, + void *user_data, + DBusFreeFunction free_user_data=nullptr) noexcept { + return dbus_pending_call_set_notify(pending, + function, user_data, + free_user_data); + } + + void Cancel() noexcept { + dbus_pending_call_cancel(pending); + } + + void Block() noexcept { + dbus_pending_call_block(pending); + } +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/ReadIter.hxx b/src/lib/dbus/ReadIter.hxx new file mode 100644 index 000000000..305f2de03 --- /dev/null +++ b/src/lib/dbus/ReadIter.hxx @@ -0,0 +1,90 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_READ_ITER_HXX +#define ODBUS_READ_ITER_HXX + +#include "Iter.hxx" + +namespace ODBus { + +class ReadMessageIter : public MessageIter { + struct RecurseTag {}; + ReadMessageIter(RecurseTag, ReadMessageIter &parent) noexcept { + dbus_message_iter_recurse(&parent.iter, &iter); + } + +public: + explicit ReadMessageIter(DBusMessage &msg) noexcept { + dbus_message_iter_init(&msg, &iter); + } + + bool HasNext() noexcept { + return dbus_message_iter_has_next(&iter); + } + + bool Next() noexcept { + return dbus_message_iter_next(&iter); + } + + int GetArgType() noexcept { + return dbus_message_iter_get_arg_type(&iter); + } + + const char *GetSignature() noexcept { + return dbus_message_iter_get_signature(&iter); + } + + void GetBasic(void *value) noexcept { + dbus_message_iter_get_basic(&iter, value); + } + + const char *GetString() noexcept { + const char *value; + GetBasic(&value); + return value; + } + + ReadMessageIter Recurse() noexcept { + return {RecurseTag(), *this}; + } + + template + void ForEach(int arg_type, F &&f) { + for (; GetArgType() == arg_type; Next()) + f(*this); + } +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/ScopeMatch.cxx b/src/lib/dbus/ScopeMatch.cxx new file mode 100644 index 000000000..98a416858 --- /dev/null +++ b/src/lib/dbus/ScopeMatch.cxx @@ -0,0 +1,42 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 "ScopeMatch.hxx" +#include "Error.hxx" + +ODBus::ScopeMatch::ScopeMatch(DBusConnection *_connection, const char *_rule) + :connection(_connection), rule(_rule) +{ + Error error; + dbus_bus_add_match(connection, rule, error); + error.CheckThrow("DBus AddMatch error"); +} diff --git a/src/lib/dbus/ScopeMatch.hxx b/src/lib/dbus/ScopeMatch.hxx new file mode 100644 index 000000000..b2c3febf8 --- /dev/null +++ b/src/lib/dbus/ScopeMatch.hxx @@ -0,0 +1,61 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_SCOPE_MATCH_HXX +#define ODBUS_SCOPE_MATCH_HXX + +#include + +namespace ODBus { + +/** + * RAII-style wrapper for dbus_bus_add_match() and + * dbus_bus_remove_match(). + */ +class ScopeMatch { + DBusConnection *const connection; + const char *const rule; + +public: + ScopeMatch(DBusConnection *_connection, const char *_rule); + + ~ScopeMatch() noexcept { + dbus_bus_remove_match(connection, rule, nullptr); + } + + ScopeMatch(const ScopeMatch &) = delete; + ScopeMatch &operator=(const ScopeMatch &) = delete; +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/Types.hxx b/src/lib/dbus/Types.hxx new file mode 100644 index 000000000..fc1db3440 --- /dev/null +++ b/src/lib/dbus/Types.hxx @@ -0,0 +1,93 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_TYPES_HXX +#define ODBUS_TYPES_HXX + +#include "util/TemplateString.hxx" + +#include + +namespace ODBus { + +template +struct BasicTypeTraits { + static constexpr int TYPE = type; + typedef TemplateString::CharAsString TypeAsString; +}; + +template +struct TypeTraits { +}; + +template<> +struct TypeTraits : BasicTypeTraits { +}; + +using StringTypeTraits = TypeTraits; + +template<> +struct TypeTraits : BasicTypeTraits { +}; + +using BooleanTypeTraits = BasicTypeTraits; + +template +struct ArrayTypeTraits { + typedef T ContainedTraits; + + static constexpr int TYPE = DBUS_TYPE_ARRAY; + typedef TemplateString::InsertBefore TypeAsString; +}; + +using VariantTypeTraits = BasicTypeTraits; + +template +struct _MakeStructTypeAsString + : TemplateString::Concat> {}; + +template +struct _MakeStructTypeAsString : T::TypeAsString {}; + +template +struct StructTypeTraits { + static constexpr int TYPE = DBUS_TYPE_STRUCT; + + typedef TemplateString::Concat, + _MakeStructTypeAsString, + TemplateString::CharAsString> TypeAsString; +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/UDisks2.hxx b/src/lib/dbus/UDisks2.hxx new file mode 100644 index 000000000..d4e8e6183 --- /dev/null +++ b/src/lib/dbus/UDisks2.hxx @@ -0,0 +1,26 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * 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. + */ + +#ifndef UDISKS2_HXX +#define UDISKS2_HXX + +#define UDISKS2_PATH "/org/freedesktop/UDisks2" +#define UDISKS2_INTERFACE "org.freedesktop.UDisks2" + +#endif diff --git a/src/lib/dbus/Values.hxx b/src/lib/dbus/Values.hxx new file mode 100644 index 000000000..cc81093d8 --- /dev/null +++ b/src/lib/dbus/Values.hxx @@ -0,0 +1,125 @@ +/* + * Copyright 2007-2017 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_VALUES_HXX +#define ODBUS_VALUES_HXX + +#include "Types.hxx" +#include "util/ConstBuffer.hxx" + +#include + +#include + +namespace ODBus { + +template +struct BasicValue { + typedef TypeTraits Traits; + const T &value; + + explicit constexpr BasicValue(const T &_value) noexcept + :value(_value) {} +}; + +struct String : BasicValue { + explicit constexpr String(const char *const&_value) noexcept + :BasicValue(_value) {} +}; + +struct Boolean { + typedef BooleanTypeTraits Traits; + dbus_bool_t value; + + explicit constexpr Boolean(bool _value) noexcept + :value(_value) {} +}; + +template class WrapTraits> +struct WrapValue { + typedef typename T::Traits ContainedTraits; + typedef WrapTraits Traits; + const T &value; + + explicit constexpr WrapValue(const T &_value) noexcept + :value(_value) {} +}; + +template +struct WrapVariant : BasicValue { + typedef typename T::Traits ContainedTraits; + typedef VariantTypeTraits Traits; + + explicit constexpr WrapVariant(const T &_value) noexcept + :BasicValue(_value) {} +}; + +template +static WrapVariant Variant(const T &_value) noexcept { + return WrapVariant(_value); +}; + +template +struct WrapFixedArray { + typedef TypeTraits ContainedTraits; + typedef ArrayTypeTraits Traits; + ConstBuffer value; + + explicit constexpr WrapFixedArray(const T *_data, + size_t _size) noexcept + :value(_data, _size) {} +}; + +template +static WrapFixedArray FixedArray(const T *_data, + size_t _size) noexcept { + return WrapFixedArray(_data, _size); +}; + +template +struct WrapStruct { + typedef StructTypeTraits Traits; + + std::tuple values; + + explicit constexpr WrapStruct(const T&... _values) noexcept + :values(_values...) {} +}; + +template +static WrapStruct Struct(const T&... values) noexcept { + return WrapStruct(values...); +}; + +} /* namespace ODBus */ + +#endif diff --git a/src/lib/dbus/Watch.cxx b/src/lib/dbus/Watch.cxx new file mode 100644 index 000000000..e707b4f90 --- /dev/null +++ b/src/lib/dbus/Watch.cxx @@ -0,0 +1,135 @@ +/* + * Copyright 2007-2018 Content Management AG + * All rights reserved. + * + * author: 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 "config.h" +#include "Watch.hxx" + +namespace ODBus { + +WatchManager::Watch::Watch(EventLoop &event_loop, + WatchManager &_parent, DBusWatch &_watch) noexcept + :SocketMonitor(event_loop), + parent(_parent), watch(_watch) +{ + Toggled(); +} + +static constexpr unsigned +DbusToLibevent(unsigned flags) noexcept +{ + return ((flags & DBUS_WATCH_READABLE) != 0) * SocketMonitor::READ | + ((flags & DBUS_WATCH_WRITABLE) != 0) * SocketMonitor::WRITE; +} + +void +WatchManager::Watch::Toggled() noexcept +{ + if (SocketMonitor::IsDefined()) + SocketMonitor::Cancel(); + + if (dbus_watch_get_enabled(&watch)) { + SocketMonitor::Open(SocketDescriptor(dbus_watch_get_unix_fd(&watch))); + SocketMonitor::Schedule(DbusToLibevent(dbus_watch_get_flags(&watch))); + } +} + +static constexpr unsigned +LibeventToDbus(unsigned flags) noexcept +{ + return ((flags & SocketMonitor::READ) != 0) * DBUS_WATCH_READABLE | + ((flags & SocketMonitor::WRITE) != 0) * DBUS_WATCH_WRITABLE; +} + +bool +WatchManager::Watch::OnSocketReady(unsigned events) noexcept +{ + /* copy the "parent" reference to the stack, because the + dbus_watch_handle() may invoke WatchManager::Remove() which + may destroy this object */ + auto &_parent = parent; + + dbus_watch_handle(&watch, LibeventToDbus(events)); + + _parent.ScheduleDispatch(); + return true; +} + +void +WatchManager::Shutdown() noexcept +{ + if (!connection) + return; + + dbus_connection_set_watch_functions(connection, + nullptr, nullptr, + nullptr, nullptr, + nullptr); + watches.clear(); + defer_dispatch.Cancel(); +} + +void +WatchManager::Dispatch() noexcept +{ + while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) {} + + if (!dbus_connection_get_is_connected(connection)) { + Shutdown(); + observer.OnDBusClosed(); + } +} + +bool +WatchManager::Add(DBusWatch *watch) noexcept +{ + watches.emplace(std::piecewise_construct, + std::forward_as_tuple(watch), + std::forward_as_tuple(GetEventLoop(), *this, *watch)); + return true; +} + +void +WatchManager::Remove(DBusWatch *watch) noexcept +{ + watches.erase(watch); +} + +void +WatchManager::Toggled(DBusWatch *watch) noexcept +{ + auto i = watches.find(watch); + assert(i != watches.end()); + + i->second.Toggled(); +} + +} /* namespace ODBus */ diff --git a/src/lib/dbus/Watch.hxx b/src/lib/dbus/Watch.hxx new file mode 100644 index 000000000..554be2ab8 --- /dev/null +++ b/src/lib/dbus/Watch.hxx @@ -0,0 +1,157 @@ +/* + * Copyright 2007-2018 Content Management AG + * All rights reserved. + * + * author: 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 ODBUS_WATCH_HXX +#define ODBUS_WATCH_HXX + +#include "Connection.hxx" +#include "event/SocketMonitor.hxx" +#include "event/DeferEvent.hxx" +#include "Compiler.h" + +#include + +#include + +class EventLoop; + +namespace ODBus { + +class WatchManagerObserver { +public: + virtual void OnDBusClosed() noexcept = 0; +}; + +/** + * Integrate a DBusConnection into the #EventLoop. + */ +class WatchManager { + WatchManagerObserver &observer; + + Connection connection; + + class Watch final : SocketMonitor { + WatchManager &parent; + DBusWatch &watch; + + public: + Watch(EventLoop &event_loop, WatchManager &_parent, + DBusWatch &_watch) noexcept; + + void Toggled() noexcept; + + private: + bool OnSocketReady(unsigned flags) noexcept override; + }; + + std::map watches; + + DeferEvent defer_dispatch; + +public: + WatchManager(EventLoop &event_loop, + WatchManagerObserver &_observer) noexcept + :observer(_observer), + defer_dispatch(event_loop, BIND_THIS_METHOD(Dispatch)) + { + } + + template + WatchManager(EventLoop &event_loop, WatchManagerObserver &_observer, + C &&_connection) noexcept + :WatchManager(event_loop, _observer) + { + SetConnection(std::forward(_connection)); + } + + ~WatchManager() noexcept { + Shutdown(); + } + + WatchManager(const WatchManager &) = delete; + WatchManager &operator=(const WatchManager &) = delete; + + void Shutdown() noexcept; + + EventLoop &GetEventLoop() noexcept { + return defer_dispatch.GetEventLoop(); + } + + Connection &GetConnection() noexcept { + return connection; + } + + template + void SetConnection(C &&_connection) noexcept { + Shutdown(); + + connection = std::forward(_connection); + + if (connection) + dbus_connection_set_watch_functions(connection, + AddFunction, + RemoveFunction, + ToggledFunction, + (void *)this, + nullptr); + } + +private: + void ScheduleDispatch() noexcept { + defer_dispatch.Schedule(); + } + + void Dispatch() noexcept; + + bool Add(DBusWatch *watch) noexcept; + void Remove(DBusWatch *watch) noexcept; + void Toggled(DBusWatch *watch) noexcept; + + static dbus_bool_t AddFunction(DBusWatch *watch, void *data) noexcept { + auto &wm = *(WatchManager *)data; + return wm.Add(watch); + } + + static void RemoveFunction(DBusWatch *watch, void *data) noexcept { + auto &wm = *(WatchManager *)data; + wm.Remove(watch); + } + + static void ToggledFunction(DBusWatch *watch, void *data) noexcept { + auto &wm = *(WatchManager *)data; + wm.Toggled(watch); + } +}; + +} /* namespace ODBus */ + +#endif