2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com)
21 #include "Connection.h"
24 #include <Commons/Exception.h>
31 Connection::Connection() :
33 m_messageDispatcher(NULL),
36 dbus_error_init(&m_error);
37 m_messageDispatcher = new MessageDispatcher(this);
40 Connection::~Connection()
42 assert(!m_connected && "DBus connection has not been closed.");
43 delete m_messageDispatcher;
44 if (dbus_error_is_set(&m_error)) {
45 dbus_error_free(&m_error);
49 void Connection::open(DBusBusType bus)
51 if (m_connected) { return; }
53 m_connection = dbus_bus_get(bus, &m_error);
54 if (!m_connection || dbus_error_is_set(&m_error)) {
55 std::string message = m_error.message;
56 dbus_error_free(&m_error);
57 ThrowMsg(WrtDeviceApis::Commons::InvalidArgumentException,
58 "Couldn't attach to DBus system bus: " << message);
61 dbus_connection_set_exit_on_disconnect(m_connection, FALSE);
63 for (FilterSetIterator it = m_filters.begin(); it != m_filters.end();
65 addFilterInternal(*it);
68 if (!dbus_connection_set_watch_functions(m_connection, addWatch,
69 removeWatch, toggleWatch, this,
71 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Couldn't set-up watch functions.");
74 if (!dbus_connection_add_filter(m_connection, filterMessage, this, NULL)) {
75 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
76 "Couldn't set signal handler callback.");
82 void Connection::close()
85 if (!m_connected) { return; }
87 dbus_connection_remove_filter(m_connection, filterMessage, this);
89 // Calls removeWatch() automagically.
90 if (!dbus_connection_set_watch_functions(m_connection, NULL, NULL, NULL,
92 DPL::Mutex::ScopedLock lock(&m_watchesMutex);
93 WatchSetIterator it = m_watches.begin();
94 for (; it != m_watches.end(); ++it) {
95 if (it->second->isEnabled()) {
96 m_messageDispatcher->removeDescriptor(it->second->getHandle(),
97 it->second->getType());
103 // TODO: think how to handle exception on filter removal; 1 - do nothing (now),
104 // 2 - remove the buggy one but throw an exception, 3 - remove the buggy one
105 // and don't throw any exception
106 for (FilterSetIterator it = m_filters.begin(); it != m_filters.end();
108 removeFilterInternal(*it);
111 dbus_connection_unref(m_connection);
116 void Connection::addFilter(const std::string& rule)
119 addFilterInternal(rule);
121 m_filters.insert(rule);
124 void Connection::removeFilter(const std::string& rule)
127 removeFilterInternal(rule);
129 m_filters.erase(rule);
132 void Connection::setWorkerThread(DPL::Thread* thread)
134 assert(!m_connected && "Connection has already been established.");
135 m_messageDispatcher->SwitchToThread(thread);
138 void Connection::addFilterInternal(const std::string& rule)
140 assert(m_connection && "Connection has to be established first.");
141 dbus_bus_add_match(m_connection, rule.c_str(), &m_error);
142 if (dbus_error_is_set(&m_error)) {
143 std::string message = m_error.message;
144 dbus_error_free(&m_error);
145 ThrowMsg(WrtDeviceApis::Commons::InvalidArgumentException, "Invalid rule: " << message);
149 void Connection::removeFilterInternal(const std::string& rule)
151 assert(m_connection && "Connection has to be established first.");
152 dbus_bus_remove_match(m_connection, rule.c_str(), &m_error);
153 if (dbus_error_is_set(&m_error)) {
154 std::string message = m_error.message;
155 dbus_error_free(&m_error);
156 ThrowMsg(WrtDeviceApis::Commons::InvalidArgumentException, "Invalid rule: " << message);
160 dbus_bool_t Connection::addWatch(DBusWatch* watch,
164 assert(data && "Connection should be passed as user data.");
165 Connection* this_ = static_cast<Connection*>(data);
166 WatchPtr wrapper(new Watch(watch));
167 if (wrapper->isEnabled()) {
168 this_->m_messageDispatcher->addDescriptor(wrapper->getHandle(),
171 DPL::Mutex::ScopedLock lock(&this_->m_watchesMutex);
172 this_->m_watches[wrapper->getHandle()] = wrapper;
176 void Connection::removeWatch(DBusWatch* watch,
180 assert(data && "Connection should be passed as user data.");
181 Connection* this_ = static_cast<Connection*>(data);
182 Watch wrapper(watch);
183 if (wrapper.isEnabled()) {
184 this_->m_messageDispatcher->removeDescriptor(wrapper.getHandle(),
187 DPL::Mutex::ScopedLock lock(&this_->m_watchesMutex);
188 this_->m_watches.erase(wrapper.getHandle());
191 void Connection::toggleWatch(DBusWatch* watch,
195 assert(data && "Connection should be passed as user data.");
196 Connection* this_ = static_cast<Connection*>(data);
197 Watch wrapper(watch);
198 if (wrapper.isEnabled()) {
199 this_->m_messageDispatcher->addDescriptor(wrapper.getHandle(),
202 this_->m_messageDispatcher->removeDescriptor(wrapper.getHandle(),
207 DBusHandlerResult Connection::filterMessage(DBusConnection* connection,
208 DBusMessage* message,
213 Connection* this_ = static_cast<Connection*>(data);
217 "DBUS message received from interface: " <<
218 dbus_message_get_interface(message));
219 msg.Reset(new Message(message));
221 LogError("DBus message not set, this should not happen!");
222 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
225 FilterSetIterator it = this_->m_filters.begin();
226 for (; it != this_->m_filters.end(); ++it) {
227 // TODO: extend following matching procedure to check not only
229 if ((*it).find(msg->getInterface()) != std::string::npos) {
230 MessageEvent event(msg);
231 this_->EmitEvent(event);
235 LogError("User-data not set, this should not happen!");
237 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
240 Connection::MessageDispatcher::MessageDispatcher(Connection* connection) :
241 m_connection(connection)
243 assert(m_connection && "Connection cannot be NULL.");
244 DPL::ControllerEventHandler<AddDescriptorSyncEvent>::Touch();
245 DPL::ControllerEventHandler<RemoveDescriptorSyncEvent>::Touch();
248 Connection::MessageDispatcher::~MessageDispatcher()
250 SwitchToThread(NULL);
253 void Connection::MessageDispatcher::addDescriptor(DPL::WaitableHandle handle,
254 DPL::WaitMode::Type mode)
257 DPL::WaitableEvent wait;
258 AddDescriptorSyncEvent event(handle, mode, &wait);
259 DPL::ControllerEventHandler<AddDescriptorSyncEvent>::PostEvent(event);
260 DPL::WaitForSingleHandle(wait.GetHandle());
263 void Connection::MessageDispatcher::removeDescriptor(DPL::WaitableHandle handle,
264 DPL::WaitMode::Type mode)
267 DPL::WaitableEvent wait;
268 RemoveDescriptorSyncEvent event(handle, mode, &wait);
269 DPL::ControllerEventHandler<RemoveDescriptorSyncEvent>::PostEvent(event);
270 DPL::WaitForSingleHandle(wait.GetHandle());
273 void Connection::MessageDispatcher::OnEventReceived(
274 const AddDescriptorSyncEvent& event)
277 DPL::WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
281 event.GetArg2()->Signal();
284 void Connection::MessageDispatcher::OnEventReceived(
285 const RemoveDescriptorSyncEvent& event)
288 DPL::WaitableHandleWatchSupport::InheritedContext()->
289 RemoveWaitableHandleWatch(this, event.GetArg0(), event.GetArg1());
290 event.GetArg2()->Signal();
293 void Connection::MessageDispatcher::OnWaitableHandleEvent(
294 DPL::WaitableHandle waitableHandle,
295 DPL::WaitMode::Type mode)
299 DPL::Mutex::ScopedLock lock(&m_connection->m_watchesMutex);
300 WatchSetIterator it = m_connection->m_watches.find(waitableHandle);
301 if (it != m_connection->m_watches.end()) {
303 (mode == DPL::WaitMode::Write ? DBUS_WATCH_WRITABLE
304 : DBUS_WATCH_READABLE);
305 while (!dbus_watch_handle(it->second->get(), flags)) {
306 LogError("Too few memory!");
307 // TODO: add some check-point to not loop infinitely
310 // TODO: not sure if there is point in dispatching connection when watch not found?
312 dbus_connection_ref(m_connection->m_connection);
313 while (dbus_connection_dispatch(m_connection->m_connection) ==
314 DBUS_DISPATCH_DATA_REMAINS) {
316 dbus_connection_unref(m_connection->m_connection);
319 Connection::Watch::Watch(DBusWatch* watch) : m_watch(watch)
321 assert(m_watch && "Watch cannot be NULL.");
324 DPL::WaitableHandle Connection::Watch::getHandle() const
326 return dbus_watch_get_unix_fd(m_watch);
329 DPL::WaitMode::Type Connection::Watch::getType() const
331 if ((dbus_watch_get_flags(m_watch) & DBUS_WATCH_WRITABLE) != 0) {
332 return DPL::WaitMode::Write;
334 return DPL::WaitMode::Read;
337 bool Connection::Watch::isEnabled() const
339 return (TRUE == dbus_watch_get_enabled(m_watch));
342 DBusWatch* Connection::Watch::get() const