diff options
Diffstat (limited to 'ipc/dbus')
-rw-r--r-- | ipc/dbus/DBusConnectionDelete.h | 42 | ||||
-rw-r--r-- | ipc/dbus/DBusConnectionRefPtr.h | 40 | ||||
-rw-r--r-- | ipc/dbus/DBusHelpers.cpp | 246 | ||||
-rw-r--r-- | ipc/dbus/DBusHelpers.h | 65 | ||||
-rw-r--r-- | ipc/dbus/DBusMessageRefPtr.h | 30 | ||||
-rw-r--r-- | ipc/dbus/DBusPendingCallRefPtr.h | 30 | ||||
-rw-r--r-- | ipc/dbus/DBusUtils.cpp | 99 | ||||
-rw-r--r-- | ipc/dbus/DBusUtils.h | 105 | ||||
-rw-r--r-- | ipc/dbus/DBusWatcher.cpp | 149 | ||||
-rw-r--r-- | ipc/dbus/DBusWatcher.h | 50 | ||||
-rw-r--r-- | ipc/dbus/RawDBusConnection.cpp | 114 | ||||
-rw-r--r-- | ipc/dbus/RawDBusConnection.h | 54 | ||||
-rw-r--r-- | ipc/dbus/moz.build | 33 |
13 files changed, 1057 insertions, 0 deletions
diff --git a/ipc/dbus/DBusConnectionDelete.h b/ipc/dbus/DBusConnectionDelete.h new file mode 100644 index 0000000000..80e47d14e3 --- /dev/null +++ b/ipc/dbus/DBusConnectionDelete.h @@ -0,0 +1,42 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_DBusConnectionDelete_h +#define mozilla_ipc_DBusConnectionDelete_h + +#include <dbus/dbus.h> +#include "mozilla/UniquePtr.h" + +namespace mozilla { + +/* + * |DBusConnectionDelete| is a deleter for managing instances + * of |DBusConnection| in |UniquePtr|. Upon destruction, it + * will close an open connection before unref'ing the data + * structure. + * + * Do not use |UniquePtr| with shared DBus connections. For + * shared connections, use |RefPtr|. + */ +class DBusConnectionDelete +{ +public: + constexpr DBusConnectionDelete() + { } + + void operator()(DBusConnection* aConnection) const + { + MOZ_ASSERT(aConnection); + if (dbus_connection_get_is_connected(aConnection)) { + dbus_connection_close(aConnection); + } + dbus_connection_unref(aConnection); + } +}; + +} // namespace mozilla + +#endif // mozilla_ipc_DBusConnectionDelete_h diff --git a/ipc/dbus/DBusConnectionRefPtr.h b/ipc/dbus/DBusConnectionRefPtr.h new file mode 100644 index 0000000000..93bf115d9e --- /dev/null +++ b/ipc/dbus/DBusConnectionRefPtr.h @@ -0,0 +1,40 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_DBusConnectionRefPtr_h +#define mozilla_ipc_DBusConnectionRefPtr_h + +#include <dbus/dbus.h> +#include "mozilla/RefPtr.h" + +namespace mozilla { + +/* + * |RefPtrTraits<DBusConnection>| specializes |RefPtrTraits<>| + * for managing |DBusConnection| with |RefPtr|. + * + * |RefPtrTraits<DBusConnection>| will _not_ close the DBus + * connection upon the final unref. The caller is responsible + * for closing the connection. + * + * See |DBusConnectionDelete| for auto-closing of connections. + */ +template<> +struct RefPtrTraits<DBusConnection> +{ + static void AddRef(DBusConnection* aConnection) { + MOZ_ASSERT(aConnection); + dbus_connection_ref(aConnection); + } + static void Release(DBusConnection* aConnection) { + MOZ_ASSERT(aConnection); + dbus_connection_unref(aConnection); + } +}; + +} // namespace mozilla + +#endif // mozilla_ipc_DBusConnectionRefPtr_h diff --git a/ipc/dbus/DBusHelpers.cpp b/ipc/dbus/DBusHelpers.cpp new file mode 100644 index 0000000000..73b4596f29 --- /dev/null +++ b/ipc/dbus/DBusHelpers.cpp @@ -0,0 +1,246 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DBusHelpers.h" +#include "mozilla/ipc/DBusMessageRefPtr.h" +#include "mozilla/ipc/DBusPendingCallRefPtr.h" +#include "mozilla/ipc/DBusWatcher.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Unused.h" +#include "nsThreadUtils.h" + +#undef CHROMIUM_LOG +#if defined(MOZ_WIDGET_GONK) +#include <android/log.h> +#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args); +#else +#define CHROMIUM_LOG(args...) printf(args); +#endif + +namespace mozilla { +namespace ipc { + +// +// DBus I/O +// + +namespace { + +class Notification final +{ +public: + Notification(DBusReplyCallback aCallback, void* aData) + : mCallback(aCallback) + , mData(aData) + { } + + // Callback function for DBus replies. Only run it on I/O thread. + // + static void Handle(DBusPendingCall* aCall, void* aData) + { + MOZ_ASSERT(!NS_IsMainThread()); + + RefPtr<DBusPendingCall> call = already_AddRefed<DBusPendingCall>(aCall); + + UniquePtr<Notification> ntfn(static_cast<Notification*>(aData)); + + RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>( + dbus_pending_call_steal_reply(call)); + + // The reply can be null if the timeout has been reached. + if (reply) { + ntfn->RunCallback(reply); + } + + dbus_pending_call_cancel(call); + } + +private: + void RunCallback(DBusMessage* aMessage) + { + if (mCallback) { + mCallback(aMessage, mData); + } + } + + DBusReplyCallback mCallback; + void* mData; +}; + +static already_AddRefed<DBusMessage> +BuildDBusMessage(const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + va_list aArgs) +{ + RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>( + dbus_message_new_method_call(aDestination, aPath, aIntf, aFunc)); + + if (!msg) { + CHROMIUM_LOG("dbus_message_new_method_call failed"); + return nullptr; + } + + auto success = dbus_message_append_args_valist(msg, aFirstArgType, aArgs); + + if (!success) { + CHROMIUM_LOG("dbus_message_append_args_valist failed"); + return nullptr; + } + + return msg.forget(); +} + +} // anonymous namespace + +nsresult +DBusWatchConnection(DBusConnection* aConnection) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + auto success = + dbus_connection_set_watch_functions(aConnection, + DBusWatcher::AddWatchFunction, + DBusWatcher::RemoveWatchFunction, + DBusWatcher::ToggleWatchFunction, + aConnection, nullptr); + if (!success) { + CHROMIUM_LOG("dbus_connection_set_watch_functions failed"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +void +DBusUnwatchConnection(DBusConnection* aConnection) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + auto success = dbus_connection_set_watch_functions(aConnection, + nullptr, nullptr, nullptr, + nullptr, nullptr); + if (!success) { + CHROMIUM_LOG("dbus_connection_set_watch_functions failed"); + } +} + +nsresult +DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + MOZ_ASSERT(aMessage); + + auto success = dbus_connection_send(aConnection, aMessage, nullptr); + + if (!success) { + CHROMIUM_LOG("dbus_connection_send failed"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, void* aData, + int aTimeout, + DBusMessage* aMessage) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + MOZ_ASSERT(aMessage); + + UniquePtr<Notification> ntfn = MakeUnique<Notification>(aCallback, aData); + + auto call = static_cast<DBusPendingCall*>(nullptr); + + auto success = dbus_connection_send_with_reply(aConnection, + aMessage, + &call, + aTimeout); + if (!success) { + CHROMIUM_LOG("dbus_connection_send_with_reply failed"); + return NS_ERROR_FAILURE; + } + + success = dbus_pending_call_set_notify(call, Notification::Handle, + ntfn.get(), nullptr); + if (!success) { + CHROMIUM_LOG("dbus_pending_call_set_notify failed"); + return NS_ERROR_FAILURE; + } + + Unused << ntfn.release(); // Picked up in |Notification::Handle| + + return NS_OK; +} + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + va_list aArgs) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + RefPtr<DBusMessage> msg = + BuildDBusMessage(aDestination, aPath, aIntf, aFunc, aFirstArgType, aArgs); + + if (!msg) { + return NS_ERROR_FAILURE; + } + + return DBusSendMessageWithReply(aConnection, aCallback, aData, aTimeout, msg); +} + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + ...) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + va_list args; + va_start(args, aFirstArgType); + + auto rv = DBusSendMessageWithReply(aConnection, + aCallback, aData, + aTimeout, + aDestination, aPath, aIntf, aFunc, + aFirstArgType, args); + va_end(args); + + if (NS_FAILED(rv)) { + return rv; + } + + return NS_OK; +} + +} +} diff --git a/ipc/dbus/DBusHelpers.h b/ipc/dbus/DBusHelpers.h new file mode 100644 index 0000000000..dc5212971a --- /dev/null +++ b/ipc/dbus/DBusHelpers.h @@ -0,0 +1,65 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_DBusHelpers_h +#define mozilla_ipc_DBusHelpers_h + +#include <dbus/dbus.h> +#include <stdarg.h> +#include "nsError.h" + +namespace mozilla { +namespace ipc { + +// +// DBus I/O +// + +typedef void (*DBusReplyCallback)(DBusMessage*, void*); + +nsresult +DBusWatchConnection(DBusConnection* aConnection); + +void +DBusUnwatchConnection(DBusConnection* aConnection); + +nsresult +DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage); + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, void* aData, + int aTimeout, + DBusMessage* aMessage); + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + va_list aArgs); + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + ...); + +} // namespace ipc +} // namespace mozilla + +#endif // mozilla_ipc_DBusHelpers_h diff --git a/ipc/dbus/DBusMessageRefPtr.h b/ipc/dbus/DBusMessageRefPtr.h new file mode 100644 index 0000000000..525463a4ca --- /dev/null +++ b/ipc/dbus/DBusMessageRefPtr.h @@ -0,0 +1,30 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_DBusMessageRefPtr_h +#define mozilla_ipc_DBusMessageRefPtr_h + +#include <dbus/dbus.h> +#include "mozilla/RefPtr.h" + +namespace mozilla { + +template<> +struct RefPtrTraits<DBusMessage> +{ + static void AddRef(DBusMessage* aMessage) { + MOZ_ASSERT(aMessage); + dbus_message_ref(aMessage); + } + static void Release(DBusMessage* aMessage) { + MOZ_ASSERT(aMessage); + dbus_message_unref(aMessage); + } +}; + +} // namespace mozilla + +#endif // mozilla_ipc_DBusMessageRefPtr_h diff --git a/ipc/dbus/DBusPendingCallRefPtr.h b/ipc/dbus/DBusPendingCallRefPtr.h new file mode 100644 index 0000000000..54e4cfd7c6 --- /dev/null +++ b/ipc/dbus/DBusPendingCallRefPtr.h @@ -0,0 +1,30 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_DBusPendingCallRefPtr_h +#define mozilla_ipc_DBusPendingCallRefPtr_h + +#include <dbus/dbus.h> +#include "mozilla/RefPtr.h" + +namespace mozilla { + +template<> +struct RefPtrTraits<DBusPendingCall> +{ + static void AddRef(DBusPendingCall* aPendingCall) { + MOZ_ASSERT(aPendingCall); + dbus_pending_call_ref(aPendingCall); + } + static void Release(DBusPendingCall* aPendingCall) { + MOZ_ASSERT(aPendingCall); + dbus_pending_call_unref(aPendingCall); + } +}; + +} // namespace mozilla + +#endif // mozilla_ipc_DBusPendingCallRefPtr_h diff --git a/ipc/dbus/DBusUtils.cpp b/ipc/dbus/DBusUtils.cpp new file mode 100644 index 0000000000..6e36bca0fe --- /dev/null +++ b/ipc/dbus/DBusUtils.cpp @@ -0,0 +1,99 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <dbus/dbus.h> +#include "DBusUtils.h" + +#undef CHROMIUM_LOG +#if defined(MOZ_WIDGET_GONK) +#include <android/log.h> +#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args); +#else +#define CHROMIUM_LOG(args...) printf(args); +#endif + +namespace mozilla { +namespace ipc { + +// +// DBusMessageRefPtr +// + +DBusMessageRefPtr::DBusMessageRefPtr(DBusMessage* aMsg) + : mMsg(aMsg) +{ + if (mMsg) { + dbus_message_ref(mMsg); + } +} + +DBusMessageRefPtr::~DBusMessageRefPtr() +{ + if (mMsg) { + dbus_message_unref(mMsg); + } +} + +// +// DBusReplyHandler +// + +void DBusReplyHandler::Callback(DBusMessage* aReply, void* aData) +{ + MOZ_ASSERT(aData); + + RefPtr<DBusReplyHandler> handler = + already_AddRefed<DBusReplyHandler>(static_cast<DBusReplyHandler*>(aData)); + + handler->Handle(aReply); +} + +// +// Utility functions +// + +void +log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg) +{ + if (msg) { + CHROMIUM_LOG("%s: D-Bus error in %s: %s (%s)", function, + dbus_message_get_member((msg)), (err)->name, (err)->message); + } else { + CHROMIUM_LOG("%s: D-Bus error: %s (%s)", __FUNCTION__, + (err)->name, (err)->message); + } + dbus_error_free((err)); +} + +int dbus_returns_int32(DBusMessage *reply) +{ + DBusError err; + int32_t ret = -1; + + dbus_error_init(&err); + if (!dbus_message_get_args(reply, &err, + DBUS_TYPE_INT32, &ret, + DBUS_TYPE_INVALID)) { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); + } + + return ret; +} + +} +} diff --git a/ipc/dbus/DBusUtils.h b/ipc/dbus/DBusUtils.h new file mode 100644 index 0000000000..8d80f1f87c --- /dev/null +++ b/ipc/dbus/DBusUtils.h @@ -0,0 +1,105 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef mozilla_ipc_dbus_dbusutils_h__ +#define mozilla_ipc_dbus_dbusutils_h__ + +#include <dbus/dbus.h> +#include "mozilla/RefPtr.h" +#include "nsISupportsImpl.h" + +// LOGE and free a D-Bus error +// Using #define so that __FUNCTION__ resolves usefully +#define LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg) log_and_free_dbus_error(err, __FUNCTION__, msg); +#define LOG_AND_FREE_DBUS_ERROR(err) log_and_free_dbus_error(err, __FUNCTION__); + +namespace mozilla { +namespace ipc { + +class DBusMessageRefPtr +{ +public: + explicit DBusMessageRefPtr(DBusMessage* aMsg); + ~DBusMessageRefPtr(); + + operator DBusMessage* () + { + return mMsg; + } + + DBusMessage* get() + { + return mMsg; + } + +private: + DBusMessage* mMsg; +}; + +/** + * DBusReplyHandler represents a handler for DBus reply messages. Inherit + * from this class and implement the Handle method. The method Callback + * should be passed to the DBus send function, with the class instance as + * user-data argument. + */ +class DBusReplyHandler +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DBusReplyHandler) + + /** + * Implements a call-back function for DBus. The supplied value for + * aData must be a pointer to an instance of DBusReplyHandler. + */ + static void Callback(DBusMessage* aReply, void* aData); + + /** + * Call-back method for handling the reply message from DBus. + */ + virtual void Handle(DBusMessage* aReply) = 0; + +protected: + DBusReplyHandler() + { + } + + DBusReplyHandler(const DBusReplyHandler& aHandler) + { + } + + DBusReplyHandler& operator = (const DBusReplyHandler& aRhs) + { + return *this; + } + + virtual ~DBusReplyHandler() + { + } +}; + +void log_and_free_dbus_error(DBusError* err, + const char* function, + DBusMessage* msg = nullptr); + +int dbus_returns_int32(DBusMessage *reply); + +} +} + +#endif + diff --git a/ipc/dbus/DBusWatcher.cpp b/ipc/dbus/DBusWatcher.cpp new file mode 100644 index 0000000000..1caeab3bb1 --- /dev/null +++ b/ipc/dbus/DBusWatcher.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DBusWatcher.h" +#include "mozilla/Unused.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace ipc { + +DBusWatcher::DBusWatcher(DBusConnection* aConnection, DBusWatch* aWatch) + : mConnection(aConnection) + , mWatch(aWatch) +{ + MOZ_ASSERT(mConnection); + MOZ_ASSERT(mWatch); +} + +DBusWatcher::~DBusWatcher() +{ } + +DBusConnection* +DBusWatcher::GetConnection() +{ + return mConnection; +} + +void +DBusWatcher::StartWatching() +{ + MOZ_ASSERT(!NS_IsMainThread()); + + auto flags = dbus_watch_get_flags(mWatch); + + if (!(flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) { + return; + } + + auto ioLoop = MessageLoopForIO::current(); + + auto fd = dbus_watch_get_unix_fd(mWatch); + + if (flags & DBUS_WATCH_READABLE) { + ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ, + &mReadWatcher, this); + } + if (flags & DBUS_WATCH_WRITABLE) { + ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE, + &mWriteWatcher, this); + } +} + +void +DBusWatcher::StopWatching() +{ + MOZ_ASSERT(!NS_IsMainThread()); + + auto flags = dbus_watch_get_flags(mWatch); + + if (flags & DBUS_WATCH_READABLE) { + mReadWatcher.StopWatchingFileDescriptor(); + } + if (flags & DBUS_WATCH_WRITABLE) { + mWriteWatcher.StopWatchingFileDescriptor(); + } +} + +// DBus utility functions, used as function pointers in DBus setup + +void +DBusWatcher::FreeFunction(void* aData) +{ + UniquePtr<DBusWatcher> watcher(static_cast<DBusWatcher*>(aData)); +} + +dbus_bool_t +DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + auto connection = static_cast<DBusConnection*>(aData); + + UniquePtr<DBusWatcher> dbusWatcher = + MakeUnique<DBusWatcher>(connection, aWatch); + + dbus_watch_set_data(aWatch, dbusWatcher.get(), DBusWatcher::FreeFunction); + + if (dbus_watch_get_enabled(aWatch)) { + dbusWatcher->StartWatching(); + } + + Unused << dbusWatcher.release(); // picked up in |FreeFunction| + + return TRUE; +} + +void +DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch)); + + dbusWatcher->StopWatching(); +} + +void +DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch)); + + if (dbus_watch_get_enabled(aWatch)) { + dbusWatcher->StartWatching(); + } else { + dbusWatcher->StopWatching(); + } +} + +// I/O-loop callbacks + +void +DBusWatcher::OnFileCanReadWithoutBlocking(int aFd) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + dbus_watch_handle(mWatch, DBUS_WATCH_READABLE); + + DBusDispatchStatus dbusDispatchStatus; + + do { + dbusDispatchStatus = dbus_connection_dispatch(mConnection); + } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS); +} + +void +DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE); +} + +} // namespace ipc +} // namespace mozilla diff --git a/ipc/dbus/DBusWatcher.h b/ipc/dbus/DBusWatcher.h new file mode 100644 index 0000000000..d866e61583 --- /dev/null +++ b/ipc/dbus/DBusWatcher.h @@ -0,0 +1,50 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_DBusWatcher_h +#define mozilla_ipc_DBusWatcher_h + +#include <dbus/dbus.h> +#include "base/message_loop.h" + +namespace mozilla { +namespace ipc { + +class DBusWatcher : public MessageLoopForIO::Watcher +{ +public: + DBusWatcher(DBusConnection* aConnection, DBusWatch* aWatch); + ~DBusWatcher(); + + void StartWatching(); + void StopWatching(); + + static void FreeFunction(void* aData); + static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData); + static void RemoveWatchFunction(DBusWatch* aWatch, void* aData); + static void ToggleWatchFunction(DBusWatch* aWatch, void* aData); + + DBusConnection* GetConnection(); + +private: + void OnFileCanReadWithoutBlocking(int aFd); + void OnFileCanWriteWithoutBlocking(int aFd); + + // Read watcher for libevent. Only to be accessed on IO Thread. + MessageLoopForIO::FileDescriptorWatcher mReadWatcher; + + // Write watcher for libevent. Only to be accessed on IO Thread. + MessageLoopForIO::FileDescriptorWatcher mWriteWatcher; + + // DBus structures + DBusConnection* mConnection; + DBusWatch* mWatch; +}; + +} // namespace ipc +} // namespace mozilla + +#endif // mozilla_ipc_DBusWatcher_h diff --git a/ipc/dbus/RawDBusConnection.cpp b/ipc/dbus/RawDBusConnection.cpp new file mode 100644 index 0000000000..420ecfe445 --- /dev/null +++ b/ipc/dbus/RawDBusConnection.cpp @@ -0,0 +1,114 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RawDBusConnection.h" +#include "base/message_loop.h" +#include "mozilla/ipc/DBusHelpers.h" +#include "mozilla/ipc/DBusWatcher.h" + +namespace mozilla { +namespace ipc { + +// +// RawDBusConnection +// + +bool RawDBusConnection::sDBusIsInit(false); + +RawDBusConnection::RawDBusConnection() +{ +} + +RawDBusConnection::~RawDBusConnection() +{ +} + +nsresult RawDBusConnection::EstablishDBusConnection() +{ + if (!sDBusIsInit) { + dbus_bool_t success = dbus_threads_init_default(); + NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE); + sDBusIsInit = true; + } + + DBusError err; + dbus_error_init(&err); + + mConnection = already_AddRefed<DBusConnection>( + dbus_bus_get_private(DBUS_BUS_SYSTEM, &err)); + + if (dbus_error_is_set(&err)) { + dbus_error_free(&err); + return NS_ERROR_FAILURE; + } + + dbus_connection_set_exit_on_disconnect(mConnection, FALSE); + + return NS_OK; +} + +bool RawDBusConnection::Watch() +{ + MOZ_ASSERT(MessageLoop::current()); + + return NS_SUCCEEDED(DBusWatchConnection(mConnection)); +} + +bool RawDBusConnection::Send(DBusMessage* aMessage) +{ + MOZ_ASSERT(MessageLoop::current()); + + auto rv = DBusSendMessage(mConnection, aMessage); + + if (NS_FAILED(rv)) { + dbus_message_unref(aMessage); + return false; + } + + return true; +} + +bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback, + void* aData, + int aTimeout, + DBusMessage* aMessage) +{ + MOZ_ASSERT(MessageLoop::current()); + + auto rv = DBusSendMessageWithReply(mConnection, aCallback, aData, aTimeout, + aMessage); + if (NS_FAILED(rv)) { + return false; + } + + dbus_message_unref(aMessage); + + return true; +} + +bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + ...) +{ + va_list args; + va_start(args, aFirstArgType); + + auto rv = DBusSendMessageWithReply(mConnection, aCallback, aData, + aTimeout, aDestination, aPath, aIntf, + aFunc, aFirstArgType, args); + va_end(args); + + return NS_SUCCEEDED(rv); +} + +} +} diff --git a/ipc/dbus/RawDBusConnection.h b/ipc/dbus/RawDBusConnection.h new file mode 100644 index 0000000000..21b809edf1 --- /dev/null +++ b/ipc/dbus/RawDBusConnection.h @@ -0,0 +1,54 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_dbus_gonk_rawdbusconnection_h__ +#define mozilla_ipc_dbus_gonk_rawdbusconnection_h__ + +#include <dbus/dbus.h> +#include "mozilla/ipc/DBusConnectionRefPtr.h" + +namespace mozilla { +namespace ipc { + +typedef void (*DBusReplyCallback)(DBusMessage*, void*); + +class RawDBusConnection +{ +public: + RawDBusConnection(); + virtual ~RawDBusConnection(); + + nsresult EstablishDBusConnection(); + + bool Watch(); + + DBusConnection* GetConnection() + { + return mConnection; + } + + bool Send(DBusMessage* aMessage); + + bool SendWithReply(DBusReplyCallback aCallback, void* aData, + int aTimeout, DBusMessage* aMessage); + + bool SendWithReply(DBusReplyCallback aCallback, void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, const char* aIntf, + const char *aFunc, int aFirstArgType, ...); + +protected: + RefPtr<DBusConnection> mConnection; + +private: + static bool sDBusIsInit; +}; + +} +} + +#endif diff --git a/ipc/dbus/moz.build b/ipc/dbus/moz.build new file mode 100644 index 0000000000..8df36ea676 --- /dev/null +++ b/ipc/dbus/moz.build @@ -0,0 +1,33 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS.mozilla.ipc += [ + 'DBusConnectionDelete.h', + 'DBusConnectionRefPtr.h', + 'DBusHelpers.h', + 'DBusMessageRefPtr.h', + 'DBusPendingCallRefPtr.h', + 'DBusUtils.h', + 'DBusWatcher.h', + 'RawDBusConnection.h', +] + +SOURCES += [ + 'DBusHelpers.cpp', + 'DBusUtils.cpp', + 'DBusWatcher.cpp', + 'RawDBusConnection.cpp', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' + +if CONFIG['MOZ_ENABLE_DBUS']: + CFLAGS += CONFIG['MOZ_DBUS_CFLAGS'] + CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] + CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS'] + CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] |