147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef HAVE_DBUS_GLIB
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/dbus.h"
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <glib.h>
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/thread.h"
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Avoid static object construction/destruction on startup/shutdown.
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic pthread_once_t g_dbus_init_once = PTHREAD_ONCE_INIT;
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic LibDBusGlibSymbolTable *g_dbus_symbol = NULL;
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Releases DBus-Glib symbols.
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic void ReleaseDBusGlibSymbol() {
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (g_dbus_symbol != NULL) {
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    delete g_dbus_symbol;
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_dbus_symbol = NULL;
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Loads DBus-Glib symbols.
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic void InitializeDBusGlibSymbol() {
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // This is thread safe.
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (NULL == g_dbus_symbol) {
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_dbus_symbol = new LibDBusGlibSymbolTable();
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Loads dbus-glib
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (NULL == g_dbus_symbol || !g_dbus_symbol->Load()) {
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_WARNING) << "Failed to load dbus-glib symbol table.";
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ReleaseDBusGlibSymbol();
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Nothing we can do if atexit() failed. Just ignore its returned value.
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      atexit(ReleaseDBusGlibSymbol);
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orginline static LibDBusGlibSymbolTable *GetSymbols() {
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return DBusMonitor::GetDBusGlibSymbolTable();
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Implementation of class DBusSigMessageData
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusSigMessageData::DBusSigMessageData(DBusMessage *message)
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : TypedMessageData<DBusMessage *>(message) {
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  GetSymbols()->dbus_message_ref()(data());
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusSigMessageData::~DBusSigMessageData() {
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  GetSymbols()->dbus_message_unref()(data());
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Implementation of class DBusSigFilter
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Builds a DBus filter string from given DBus path, interface and member.
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstd::string DBusSigFilter::BuildFilterString(const std::string &path,
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                             const std::string &interface,
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                             const std::string &member) {
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::string ret(DBUS_TYPE "='" DBUS_SIGNAL "'");
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!path.empty()) {
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += ("," DBUS_PATH "='");
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += path;
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += "'";
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!interface.empty()) {
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += ("," DBUS_INTERFACE "='");
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += interface;
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += "'";
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!member.empty()) {
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += ("," DBUS_MEMBER "='");
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += member;
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret += "'";
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return ret;
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Forwards the message to the given instance.
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusHandlerResult DBusSigFilter::DBusCallback(DBusConnection *dbus_conn,
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                              DBusMessage *message,
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                              void *instance) {
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(instance);
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (instance) {
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return static_cast<DBusSigFilter *>(instance)->Callback(message);
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Posts a message to caller thread.
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusHandlerResult DBusSigFilter::Callback(DBusMessage *message) {
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (caller_thread_) {
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    caller_thread_->Post(this, DSM_SIGNAL, new DBusSigMessageData(message));
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Don't "eat" the message here. Let it pop up.
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// From MessageHandler.
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid DBusSigFilter::OnMessage(Message *message) {
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (message != NULL && DSM_SIGNAL == message->message_id) {
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DBusSigMessageData *msg =
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        static_cast<DBusSigMessageData *>(message->pdata);
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (msg) {
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ProcessSignal(msg->data());
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      delete msg;
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Definition of private class DBusMonitoringThread.
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// It creates a worker-thread to listen signals on DBus. The worker-thread will
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// be running in a priate GMainLoop forever until either Stop() has been invoked
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// or it hits an error.
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass DBusMonitor::DBusMonitoringThread : public rtc::Thread {
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  explicit DBusMonitoringThread(DBusMonitor *monitor,
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                GMainContext *context,
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                GMainLoop *mainloop,
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                std::vector<DBusSigFilter *> *filter_list)
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      : monitor_(monitor),
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        context_(context),
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        mainloop_(mainloop),
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        connection_(NULL),
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        idle_source_(NULL),
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        filter_list_(filter_list) {
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(monitor_);
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(context_);
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(mainloop_);
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(filter_list_);
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual ~DBusMonitoringThread() {
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Stop();
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Override virtual method of Thread. Context: worker-thread.
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void Run() {
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(NULL == connection_);
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Setup DBus connection and start monitoring.
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitor_->OnMonitoringStatusChanged(DMS_INITIALIZING);
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!Setup()) {
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "DBus monitoring setup failed.";
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      monitor_->OnMonitoringStatusChanged(DMS_FAILED);
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CleanUp();
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return;
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitor_->OnMonitoringStatusChanged(DMS_RUNNING);
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_main_loop_run(mainloop_);
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitor_->OnMonitoringStatusChanged(DMS_STOPPED);
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Done normally. Clean up DBus connection.
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CleanUp();
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Override virtual method of Thread. Context: caller-thread.
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void Stop() {
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(NULL == idle_source_);
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Add an idle source and let the gmainloop quit on idle.
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    idle_source_ = g_idle_source_new();
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (idle_source_) {
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_source_set_callback(idle_source_, &Idle, this, NULL);
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_source_attach(idle_source_, context_);
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "g_idle_source_new() failed.";
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      QuitGMainloop();  // Try to quit anyway.
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Thread::Stop();  // Wait for the thread.
18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Registers all DBus filters.
18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void RegisterAllFilters() {
18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(NULL != GetSymbols()->dbus_g_connection_get_connection()(
18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        connection_));
19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (std::vector<DBusSigFilter *>::iterator it = filter_list_->begin();
19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org         it != filter_list_->end(); ++it) {
19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      DBusSigFilter *filter = (*it);
19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (!filter) {
19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_ERROR) << "DBusSigFilter list corrupted.";
19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        continue;
19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      GetSymbols()->dbus_bus_add_match()(
20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          GetSymbols()->dbus_g_connection_get_connection()(connection_),
20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          filter->filter().c_str(), NULL);
20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (!GetSymbols()->dbus_connection_add_filter()(
20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org              GetSymbols()->dbus_g_connection_get_connection()(connection_),
20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org              &DBusSigFilter::DBusCallback, filter, NULL)) {
20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_ERROR) << "dbus_connection_add_filter() failed."
20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                      << "Filter: " << filter->filter();
20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        continue;
20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Unregisters all DBus filters.
21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void UnRegisterAllFilters() {
21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(NULL != GetSymbols()->dbus_g_connection_get_connection()(
21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        connection_));
21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (std::vector<DBusSigFilter *>::iterator it = filter_list_->begin();
21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org         it != filter_list_->end(); ++it) {
22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      DBusSigFilter *filter = (*it);
22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (!filter) {
22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_ERROR) << "DBusSigFilter list corrupted.";
22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        continue;
22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      GetSymbols()->dbus_connection_remove_filter()(
22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          GetSymbols()->dbus_g_connection_get_connection()(connection_),
22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          &DBusSigFilter::DBusCallback, filter);
22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Sets up the monitoring thread.
23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool Setup() {
23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_main_context_push_thread_default(context_);
23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Start connection to dbus.
23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // If dbus daemon is not running, returns false immediately.
23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    connection_ = GetSymbols()->dbus_g_bus_get_private()(monitor_->type_,
23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        context_, NULL);
23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (NULL == connection_) {
24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "dbus_g_bus_get_private() unable to get connection.";
24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (NULL == GetSymbols()->dbus_g_connection_get_connection()(connection_)) {
24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "dbus_g_connection_get_connection() returns NULL. "
24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                    << "DBus daemon is probably not running.";
24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Application don't exit if DBus daemon die.
25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    GetSymbols()->dbus_connection_set_exit_on_disconnect()(
25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        GetSymbols()->dbus_g_connection_get_connection()(connection_), FALSE);
25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Connect all filters.
25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    RegisterAllFilters();
25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return true;
25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Cleans up the monitoring thread.
26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void CleanUp() {
26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (idle_source_) {
26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // We did an attach() with the GSource, so we need to destroy() it.
26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_source_destroy(idle_source_);
26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // We need to unref() the GSource to end the last reference we got.
26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_source_unref(idle_source_);
26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      idle_source_ = NULL;
26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (connection_) {
26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (GetSymbols()->dbus_g_connection_get_connection()(connection_)) {
27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        UnRegisterAllFilters();
27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        GetSymbols()->dbus_connection_close()(
27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            GetSymbols()->dbus_g_connection_get_connection()(connection_));
27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      GetSymbols()->dbus_g_connection_unref()(connection_);
27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      connection_ = NULL;
27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_main_loop_unref(mainloop_);
27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    mainloop_ = NULL;
27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_main_context_unref(context_);
28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    context_ = NULL;
28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Handles callback on Idle. We only add this source when ready to stop.
28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static gboolean Idle(gpointer data) {
28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    static_cast<DBusMonitoringThread *>(data)->QuitGMainloop();
28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return TRUE;
28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // We only hit this when ready to quit.
29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void QuitGMainloop() {
29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_main_loop_quit(mainloop_);
29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DBusMonitor *monitor_;
29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  GMainContext *context_;
29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  GMainLoop *mainloop_;
29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DBusGConnection *connection_;
29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  GSource *idle_source_;
30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::vector<DBusSigFilter *> *filter_list_;
30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Implementation of class DBusMonitor
30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Returns DBus-Glib symbol handle. Initialize it first if hasn't.
30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgLibDBusGlibSymbolTable *DBusMonitor::GetDBusGlibSymbolTable() {
30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // This is multi-thread safe.
30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  pthread_once(&g_dbus_init_once, InitializeDBusGlibSymbol);
31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return g_dbus_symbol;
31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Creates an instance of DBusMonitor
31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusMonitor *DBusMonitor::Create(DBusBusType type) {
31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (NULL == DBusMonitor::GetDBusGlibSymbolTable()) {
31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return NULL;
31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return new DBusMonitor(type);
32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusMonitor::DBusMonitor(DBusBusType type)
32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : type_(type),
32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      status_(DMS_NOT_INITIALIZED),
32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      monitoring_thread_(NULL) {
32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(type_ == DBUS_BUS_SYSTEM || type_ == DBUS_BUS_SESSION);
32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusMonitor::~DBusMonitor() {
33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StopMonitoring();
33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DBusMonitor::AddFilter(DBusSigFilter *filter) {
33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (monitoring_thread_) {
33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!filter) {
33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  filter_list_.push_back(filter);
34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DBusMonitor::StartMonitoring() {
34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!monitoring_thread_) {
34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_type_init();
34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    g_thread_init(NULL);
34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    GetSymbols()->dbus_g_thread_init()();
34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    GMainContext *context = g_main_context_new();
35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (NULL == context) {
35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "g_main_context_new() failed.";
35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    GMainLoop *mainloop = g_main_loop_new(context, FALSE);
35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (NULL == mainloop) {
35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "g_main_loop_new() failed.";
35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_main_context_unref(context);
36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitoring_thread_ = new DBusMonitoringThread(this, context, mainloop,
36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                  &filter_list_);
36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (monitoring_thread_ == NULL) {
36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Failed to create DBus monitoring thread.";
36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_main_context_unref(context);
36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      g_main_loop_unref(mainloop);
36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitoring_thread_->Start();
37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DBusMonitor::StopMonitoring() {
37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (monitoring_thread_) {
37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitoring_thread_->Stop();
37947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    monitoring_thread_ = NULL;
38047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
38147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
38247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
38347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDBusMonitor::DBusMonitorStatus DBusMonitor::GetStatus() {
38547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return status_;
38647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
38747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid DBusMonitor::OnMonitoringStatusChanged(DBusMonitorStatus status) {
38947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  status_ = status;
39047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
39147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#undef LATE
39347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
39547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // HAVE_DBUS_GLIB
397