ipc/dbus/RawDBusConnection.cpp

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

michael@0 1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include <dbus/dbus.h>
michael@0 8 #include "base/message_loop.h"
michael@0 9 #include "nsThreadUtils.h"
michael@0 10 #include "RawDBusConnection.h"
michael@0 11
michael@0 12 #ifdef CHROMIUM_LOG
michael@0 13 #undef CHROMIUM_LOG
michael@0 14 #endif
michael@0 15
michael@0 16 #if defined(MOZ_WIDGET_GONK)
michael@0 17 #include <android/log.h>
michael@0 18 #define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
michael@0 19 #else
michael@0 20 #define CHROMIUM_LOG(args...) printf(args);
michael@0 21 #endif
michael@0 22
michael@0 23 namespace mozilla {
michael@0 24 namespace ipc {
michael@0 25
michael@0 26 //
michael@0 27 // DBusWatcher
michael@0 28 //
michael@0 29
michael@0 30 class DBusWatcher : public MessageLoopForIO::Watcher
michael@0 31 {
michael@0 32 public:
michael@0 33 DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
michael@0 34 : mConnection(aConnection),
michael@0 35 mWatch(aWatch)
michael@0 36 {
michael@0 37 MOZ_ASSERT(mConnection);
michael@0 38 MOZ_ASSERT(mWatch);
michael@0 39 }
michael@0 40
michael@0 41 ~DBusWatcher()
michael@0 42 { }
michael@0 43
michael@0 44 void StartWatching();
michael@0 45 void StopWatching();
michael@0 46
michael@0 47 static void FreeFunction(void* aData);
michael@0 48 static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
michael@0 49 static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
michael@0 50 static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
michael@0 51
michael@0 52 RawDBusConnection* GetConnection();
michael@0 53
michael@0 54 private:
michael@0 55 void OnFileCanReadWithoutBlocking(int aFd);
michael@0 56 void OnFileCanWriteWithoutBlocking(int aFd);
michael@0 57
michael@0 58 // Read watcher for libevent. Only to be accessed on IO Thread.
michael@0 59 MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
michael@0 60
michael@0 61 // Write watcher for libevent. Only to be accessed on IO Thread.
michael@0 62 MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
michael@0 63
michael@0 64 // DBus structures
michael@0 65 RawDBusConnection* mConnection;
michael@0 66 DBusWatch* mWatch;
michael@0 67 };
michael@0 68
michael@0 69 RawDBusConnection*
michael@0 70 DBusWatcher::GetConnection()
michael@0 71 {
michael@0 72 return mConnection;
michael@0 73 }
michael@0 74
michael@0 75 void DBusWatcher::StartWatching()
michael@0 76 {
michael@0 77 MOZ_ASSERT(!NS_IsMainThread());
michael@0 78 MOZ_ASSERT(mWatch);
michael@0 79
michael@0 80 int fd = dbus_watch_get_unix_fd(mWatch);
michael@0 81
michael@0 82 MessageLoopForIO* ioLoop = MessageLoopForIO::current();
michael@0 83
michael@0 84 unsigned int flags = dbus_watch_get_flags(mWatch);
michael@0 85
michael@0 86 if (flags & DBUS_WATCH_READABLE) {
michael@0 87 ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
michael@0 88 &mReadWatcher, this);
michael@0 89 }
michael@0 90 if (flags & DBUS_WATCH_WRITABLE) {
michael@0 91 ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
michael@0 92 &mWriteWatcher, this);
michael@0 93 }
michael@0 94 }
michael@0 95
michael@0 96 void DBusWatcher::StopWatching()
michael@0 97 {
michael@0 98 MOZ_ASSERT(!NS_IsMainThread());
michael@0 99
michael@0 100 unsigned int flags = dbus_watch_get_flags(mWatch);
michael@0 101
michael@0 102 if (flags & DBUS_WATCH_READABLE) {
michael@0 103 mReadWatcher.StopWatchingFileDescriptor();
michael@0 104 }
michael@0 105 if (flags & DBUS_WATCH_WRITABLE) {
michael@0 106 mWriteWatcher.StopWatchingFileDescriptor();
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 // DBus utility functions, used as function pointers in DBus setup
michael@0 111
michael@0 112 void
michael@0 113 DBusWatcher::FreeFunction(void* aData)
michael@0 114 {
michael@0 115 delete static_cast<DBusWatcher*>(aData);
michael@0 116 }
michael@0 117
michael@0 118 dbus_bool_t
michael@0 119 DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
michael@0 120 {
michael@0 121 MOZ_ASSERT(!NS_IsMainThread());
michael@0 122
michael@0 123 RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
michael@0 124
michael@0 125 DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
michael@0 126 dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
michael@0 127
michael@0 128 if (dbus_watch_get_enabled(aWatch)) {
michael@0 129 dbusWatcher->StartWatching();
michael@0 130 }
michael@0 131
michael@0 132 return TRUE;
michael@0 133 }
michael@0 134
michael@0 135 void
michael@0 136 DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
michael@0 137 {
michael@0 138 MOZ_ASSERT(!NS_IsMainThread());
michael@0 139
michael@0 140 DBusWatcher* dbusWatcher =
michael@0 141 static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
michael@0 142 dbusWatcher->StopWatching();
michael@0 143 }
michael@0 144
michael@0 145 void
michael@0 146 DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
michael@0 147 {
michael@0 148 MOZ_ASSERT(!NS_IsMainThread());
michael@0 149
michael@0 150 DBusWatcher* dbusWatcher =
michael@0 151 static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
michael@0 152
michael@0 153 if (dbus_watch_get_enabled(aWatch)) {
michael@0 154 dbusWatcher->StartWatching();
michael@0 155 } else {
michael@0 156 dbusWatcher->StopWatching();
michael@0 157 }
michael@0 158 }
michael@0 159
michael@0 160 // I/O-loop callbacks
michael@0 161
michael@0 162 void
michael@0 163 DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
michael@0 164 {
michael@0 165 MOZ_ASSERT(!NS_IsMainThread());
michael@0 166
michael@0 167 dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
michael@0 168
michael@0 169 DBusDispatchStatus dbusDispatchStatus;
michael@0 170 do {
michael@0 171 dbusDispatchStatus =
michael@0 172 dbus_connection_dispatch(mConnection->GetConnection());
michael@0 173 } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
michael@0 174 }
michael@0 175
michael@0 176 void
michael@0 177 DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
michael@0 178 {
michael@0 179 MOZ_ASSERT(!NS_IsMainThread());
michael@0 180
michael@0 181 dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
michael@0 182 }
michael@0 183
michael@0 184 //
michael@0 185 // Notification
michael@0 186 //
michael@0 187
michael@0 188 class Notification
michael@0 189 {
michael@0 190 public:
michael@0 191 Notification(DBusReplyCallback aCallback, void* aData)
michael@0 192 : mCallback(aCallback),
michael@0 193 mData(aData)
michael@0 194 { }
michael@0 195
michael@0 196 // Callback function for DBus replies. Only run it on I/O thread.
michael@0 197 //
michael@0 198 static void Handle(DBusPendingCall* aCall, void* aData)
michael@0 199 {
michael@0 200 MOZ_ASSERT(!NS_IsMainThread());
michael@0 201 MOZ_ASSERT(MessageLoop::current());
michael@0 202
michael@0 203 nsAutoPtr<Notification> ntfn(static_cast<Notification*>(aData));
michael@0 204
michael@0 205 // The reply can be non-null if the timeout has been reached.
michael@0 206 DBusMessage* reply = dbus_pending_call_steal_reply(aCall);
michael@0 207
michael@0 208 if (reply) {
michael@0 209 ntfn->RunCallback(reply);
michael@0 210 dbus_message_unref(reply);
michael@0 211 }
michael@0 212
michael@0 213 dbus_pending_call_cancel(aCall);
michael@0 214 dbus_pending_call_unref(aCall);
michael@0 215 }
michael@0 216
michael@0 217 private:
michael@0 218 void RunCallback(DBusMessage* aMessage)
michael@0 219 {
michael@0 220 if (mCallback) {
michael@0 221 mCallback(aMessage, mData);
michael@0 222 }
michael@0 223 }
michael@0 224
michael@0 225 DBusReplyCallback mCallback;
michael@0 226 void* mData;
michael@0 227 };
michael@0 228
michael@0 229 //
michael@0 230 // RawDBusConnection
michael@0 231 //
michael@0 232
michael@0 233 bool RawDBusConnection::sDBusIsInit(false);
michael@0 234
michael@0 235 RawDBusConnection::RawDBusConnection()
michael@0 236 {
michael@0 237 }
michael@0 238
michael@0 239 RawDBusConnection::~RawDBusConnection()
michael@0 240 {
michael@0 241 }
michael@0 242
michael@0 243 nsresult RawDBusConnection::EstablishDBusConnection()
michael@0 244 {
michael@0 245 if (!sDBusIsInit) {
michael@0 246 dbus_bool_t success = dbus_threads_init_default();
michael@0 247 NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
michael@0 248 sDBusIsInit = true;
michael@0 249 }
michael@0 250 DBusError err;
michael@0 251 dbus_error_init(&err);
michael@0 252 mConnection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
michael@0 253 if (dbus_error_is_set(&err)) {
michael@0 254 dbus_error_free(&err);
michael@0 255 return NS_ERROR_FAILURE;
michael@0 256 }
michael@0 257 dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
michael@0 258 return NS_OK;
michael@0 259 }
michael@0 260
michael@0 261 bool RawDBusConnection::Watch()
michael@0 262 {
michael@0 263 MOZ_ASSERT(!NS_IsMainThread());
michael@0 264 MOZ_ASSERT(MessageLoop::current());
michael@0 265
michael@0 266 dbus_bool_t success =
michael@0 267 dbus_connection_set_watch_functions(mConnection,
michael@0 268 DBusWatcher::AddWatchFunction,
michael@0 269 DBusWatcher::RemoveWatchFunction,
michael@0 270 DBusWatcher::ToggleWatchFunction,
michael@0 271 this, nullptr);
michael@0 272 NS_ENSURE_TRUE(success == TRUE, false);
michael@0 273
michael@0 274 return true;
michael@0 275 }
michael@0 276
michael@0 277 void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
michael@0 278 {
michael@0 279 if (ptr) {
michael@0 280 dbus_connection_close(ptr);
michael@0 281 dbus_connection_unref(ptr);
michael@0 282 }
michael@0 283 }
michael@0 284
michael@0 285 bool RawDBusConnection::Send(DBusMessage* aMessage)
michael@0 286 {
michael@0 287 MOZ_ASSERT(aMessage);
michael@0 288 MOZ_ASSERT(!NS_IsMainThread());
michael@0 289 MOZ_ASSERT(MessageLoop::current());
michael@0 290
michael@0 291 dbus_bool_t success = dbus_connection_send(mConnection,
michael@0 292 aMessage,
michael@0 293 nullptr);
michael@0 294 if (success != TRUE) {
michael@0 295 dbus_message_unref(aMessage);
michael@0 296 return false;
michael@0 297 }
michael@0 298 return true;
michael@0 299 }
michael@0 300
michael@0 301 bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
michael@0 302 void* aData,
michael@0 303 int aTimeout,
michael@0 304 DBusMessage* aMessage)
michael@0 305 {
michael@0 306 MOZ_ASSERT(aMessage);
michael@0 307 MOZ_ASSERT(!NS_IsMainThread());
michael@0 308 MOZ_ASSERT(MessageLoop::current());
michael@0 309
michael@0 310 nsAutoPtr<Notification> ntfn(new Notification(aCallback, aData));
michael@0 311 NS_ENSURE_TRUE(ntfn, false);
michael@0 312
michael@0 313 DBusPendingCall* call;
michael@0 314
michael@0 315 dbus_bool_t success = dbus_connection_send_with_reply(mConnection,
michael@0 316 aMessage,
michael@0 317 &call,
michael@0 318 aTimeout);
michael@0 319 NS_ENSURE_TRUE(success == TRUE, false);
michael@0 320
michael@0 321 success = dbus_pending_call_set_notify(call, Notification::Handle,
michael@0 322 ntfn, nullptr);
michael@0 323 NS_ENSURE_TRUE(success == TRUE, false);
michael@0 324
michael@0 325 ntfn.forget();
michael@0 326 dbus_message_unref(aMessage);
michael@0 327
michael@0 328 return true;
michael@0 329 }
michael@0 330
michael@0 331 bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
michael@0 332 void* aData,
michael@0 333 int aTimeout,
michael@0 334 const char* aDestination,
michael@0 335 const char* aPath,
michael@0 336 const char* aIntf,
michael@0 337 const char* aFunc,
michael@0 338 int aFirstArgType,
michael@0 339 ...)
michael@0 340 {
michael@0 341 MOZ_ASSERT(!NS_IsMainThread());
michael@0 342 va_list args;
michael@0 343
michael@0 344 va_start(args, aFirstArgType);
michael@0 345 DBusMessage* msg = BuildDBusMessage(aDestination, aPath, aIntf, aFunc,
michael@0 346 aFirstArgType, args);
michael@0 347 va_end(args);
michael@0 348
michael@0 349 if (!msg) {
michael@0 350 return false;
michael@0 351 }
michael@0 352
michael@0 353 return SendWithReply(aCallback, aData, aTimeout, msg);
michael@0 354 }
michael@0 355
michael@0 356 DBusMessage* RawDBusConnection::BuildDBusMessage(const char* aDestination,
michael@0 357 const char* aPath,
michael@0 358 const char* aIntf,
michael@0 359 const char* aFunc,
michael@0 360 int aFirstArgType,
michael@0 361 va_list aArgs)
michael@0 362 {
michael@0 363 DBusMessage* msg = dbus_message_new_method_call(aDestination,
michael@0 364 aPath, aIntf,
michael@0 365 aFunc);
michael@0 366 if (!msg) {
michael@0 367 CHROMIUM_LOG("Could not allocate D-Bus message object!");
michael@0 368 return nullptr;
michael@0 369 }
michael@0 370
michael@0 371 /* append arguments */
michael@0 372 if (!dbus_message_append_args_valist(msg, aFirstArgType, aArgs)) {
michael@0 373 CHROMIUM_LOG("Could not append argument to method call!");
michael@0 374 dbus_message_unref(msg);
michael@0 375 return nullptr;
michael@0 376 }
michael@0 377
michael@0 378 return msg;
michael@0 379 }
michael@0 380
michael@0 381 }
michael@0 382 }

mercurial