Skip to content

Commit

Permalink
Fix a bug in dbus::Bus::AddFilterFunction().
Browse files Browse the repository at this point in the history
We should not reject the same function if it's associated with different data.

BUG=99258
TEST=adde a unit test and confirmed it passed.

Review URL: http://codereview.chromium.org/8161005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104208 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
satorux@chromium.org committed Oct 6, 2011
1 parent b1e2d36 commit 12e2599
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 20 deletions.
30 changes: 19 additions & 11 deletions dbus/bus.cc
Original file line number Diff line number Diff line change
Expand Up @@ -439,37 +439,45 @@ void Bus::Send(DBusMessage* request, uint32* serial) {
CHECK(success) << "Unable to allocate memory";
}

void Bus::AddFilterFunction(DBusHandleMessageFunction filter_function,
bool Bus::AddFilterFunction(DBusHandleMessageFunction filter_function,
void* user_data) {
DCHECK(connection_);
AssertOnDBusThread();

if (filter_functions_added_.find(filter_function) !=
std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
std::make_pair(filter_function, user_data);
if (filter_functions_added_.find(filter_data_pair) !=
filter_functions_added_.end()) {
LOG(ERROR) << "Filter function already exists: " << filter_function;
return;
VLOG(1) << "Filter function already exists: " << filter_function
<< " with associated data: " << user_data;
return false;
}

const bool success = dbus_connection_add_filter(
connection_, filter_function, user_data, NULL);
CHECK(success) << "Unable to allocate memory";
filter_functions_added_.insert(filter_function);
filter_functions_added_.insert(filter_data_pair);
return true;
}

void Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function,
bool Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function,
void* user_data) {
DCHECK(connection_);
AssertOnDBusThread();

if (filter_functions_added_.find(filter_function) ==
std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
std::make_pair(filter_function, user_data);
if (filter_functions_added_.find(filter_data_pair) ==
filter_functions_added_.end()) {
LOG(ERROR) << "Requested to remove an unknown filter function: "
<< filter_function;
return;
VLOG(1) << "Requested to remove an unknown filter function: "
<< filter_function
<< " with associated data: " << user_data;
return false;
}

dbus_connection_remove_filter(connection_, filter_function, user_data);
filter_functions_added_.erase(filter_function);
filter_functions_added_.erase(filter_data_pair);
return true;
}

void Bus::AddMatch(const std::string& match_rule, DBusError* error) {
Expand Down
14 changes: 9 additions & 5 deletions dbus/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <map>
#include <set>
#include <string>
#include <utility>
#include <dbus/dbus.h>

#include "base/callback.h"
Expand Down Expand Up @@ -284,22 +285,24 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
virtual void Send(DBusMessage* request, uint32* serial);

// Adds the message filter function. |filter_function| will be called
// when incoming messages are received.
// when incoming messages are received. Returns true on success.
//
// When a new incoming message arrives, filter functions are called in
// the order that they were added until the the incoming message is
// handled by a filter function.
//
// The same filter function must not be added more than once.
// The same filter function associated with the same user data cannot be
// added more than once. Returns false for this case.
//
// BLOCKING CALL.
virtual void AddFilterFunction(DBusHandleMessageFunction filter_function,
virtual bool AddFilterFunction(DBusHandleMessageFunction filter_function,
void* user_data);

// Removes the message filter previously added by AddFilterFunction().
// Returns true on success.
//
// BLOCKING CALL.
virtual void RemoveFilterFunction(DBusHandleMessageFunction filter_function,
virtual bool RemoveFilterFunction(DBusHandleMessageFunction filter_function,
void* user_data);

// Adds the match rule. Messages that match the rule will be processed
Expand Down Expand Up @@ -444,7 +447,8 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
// are properly cleaned up before destruction of the bus object.
std::set<std::string> match_rules_added_;
std::set<std::string> registered_object_paths_;
std::set<DBusHandleMessageFunction> filter_functions_added_;
std::set<std::pair<DBusHandleMessageFunction, void*> >
filter_functions_added_;

// ObjectProxyTable is used to hold the object proxies created by the
// bus object. Key is a concatenated string of service name + object path,
Expand Down
32 changes: 32 additions & 0 deletions dbus/bus_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@

#include "testing/gtest/include/gtest/gtest.h"

namespace {

// Used to test AddFilterFunction().
DBusHandlerResult DummyHandler(DBusConnection* connection,
DBusMessage* raw_message,
void* user_data) {
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

} // namespace

TEST(BusTest, GetObjectProxy) {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
Expand Down Expand Up @@ -89,3 +100,24 @@ TEST(BusTest, ShutdownAndBlockWithDBusThread) {
EXPECT_TRUE(bus->shutdown_completed());
dbus_thread.Stop();
}

TEST(BusTest, AddFilterFunction) {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
// Should connect before calling AddFilterFunction().
bus->Connect();

int data1 = 100;
int data2 = 200;
ASSERT_TRUE(bus->AddFilterFunction(&DummyHandler, &data1));
// Cannot add the same function with the same data.
ASSERT_FALSE(bus->AddFilterFunction(&DummyHandler, &data1));
// Can add the same function with different data.
ASSERT_TRUE(bus->AddFilterFunction(&DummyHandler, &data2));

ASSERT_TRUE(bus->RemoveFilterFunction(&DummyHandler, &data1));
ASSERT_FALSE(bus->RemoveFilterFunction(&DummyHandler, &data1));
ASSERT_TRUE(bus->RemoveFilterFunction(&DummyHandler, &data2));

bus->ShutdownAndBlock();
}
14 changes: 10 additions & 4 deletions dbus/object_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,11 @@ void ObjectProxy::ConnectToSignal(const std::string& interface_name,
void ObjectProxy::Detach() {
bus_->AssertOnDBusThread();

if (filter_added_)
bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
if (filter_added_) {
if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
LOG(ERROR) << "Failed to remove filter function";
}
}

for (size_t i = 0; i < match_rules_.size(); ++i) {
ScopedDBusError error;
Expand Down Expand Up @@ -277,8 +280,11 @@ void ObjectProxy::ConnectToSignalInternal(
// We should add the filter only once. Otherwise, HandleMessage() will
// be called more than once.
if (!filter_added_) {
bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
filter_added_ = true;
if (bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
filter_added_ = true;
} else {
LOG(ERROR) << "Failed to add filter function";
}
}
// Add a match rule so the signal goes through HandleMessage().
//
Expand Down

0 comments on commit 12e2599

Please sign in to comment.