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

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

mercurial