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.
17 * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com)
20 #include "Connection.h"
23 #include <Commons/Exception.h>
24 #include <dpl/log/log.h>
27 namespace WrtDeviceApis {
29 Connection::Connection() :
31 m_messageDispatcher(NULL),
34 dbus_error_init(&m_error);
35 m_messageDispatcher = new MessageDispatcher(this);
38 Connection::~Connection()
40 assert(!m_connected && "DBus connection has not been closed.");
41 delete m_messageDispatcher;
42 if (dbus_error_is_set(&m_error)) {
43 dbus_error_free(&m_error);
47 void Connection::open(DBusBusType bus)
49 if (m_connected) { return; }
51 m_connection = dbus_bus_get(bus, &m_error);
52 if (!m_connection || dbus_error_is_set(&m_error)) {
53 std::string message = m_error.message;
54 dbus_error_free(&m_error);
55 ThrowMsg(Commons::PlatformException,
56 "Couldn't attach to DBus system bus: " << message);
59 dbus_connection_set_exit_on_disconnect(m_connection, FALSE);
61 for (FilterSetIterator it = m_filters.begin(); it != m_filters.end();
63 addFilterInternal(*it);
66 if (!dbus_connection_set_watch_functions(m_connection, addWatch,
67 removeWatch, toggleWatch, this,
69 ThrowMsg(Commons::PlatformException, "Couldn't set-up watch functions.");
72 if (!dbus_connection_add_filter(m_connection, filterMessage, this, NULL)) {
73 ThrowMsg(Commons::PlatformException,
74 "Couldn't set signal handler callback.");
80 void Connection::close()
83 if (!m_connected) { return; }
85 dbus_connection_remove_filter(m_connection, filterMessage, this);
87 // Calls removeWatch() automagically.
88 if (!dbus_connection_set_watch_functions(m_connection, NULL, NULL, NULL,
90 DPL::Mutex::ScopedLock lock(&m_watchesMutex);
91 WatchSetIterator it = m_watches.begin();
92 for (; it != m_watches.end(); ++it) {
93 if (it->second->isEnabled()) {
94 m_messageDispatcher->removeDescriptor(it->second->getHandle(),
95 it->second->getType());
101 // TODO: think how to handle exception on filter removal; 1 - do nothing (now),
102 // 2 - remove the buggy one but throw an exception, 3 - remove the buggy one
103 // and don't throw any exception
104 for (FilterSetIterator it = m_filters.begin(); it != m_filters.end();
106 removeFilterInternal(*it);
109 dbus_connection_unref(m_connection);
114 void Connection::addFilter(const std::string& rule)
117 addFilterInternal(rule);
119 m_filters.insert(rule);
122 void Connection::removeFilter(const std::string& rule)
125 removeFilterInternal(rule);
127 m_filters.erase(rule);
130 void Connection::setWorkerThread(DPL::Thread* thread)
132 assert(!m_connected && "Connection has already been established.");
133 m_messageDispatcher->SwitchToThread(thread);
136 void Connection::addFilterInternal(const std::string& rule)
138 assert(m_connection && "Connection has to be established first.");
139 dbus_bus_add_match(m_connection, rule.c_str(), &m_error);
140 if (dbus_error_is_set(&m_error)) {
141 std::string message = m_error.message;
142 dbus_error_free(&m_error);
143 ThrowMsg(Commons::InvalidArgumentException, "Invalid rule: " << message);
147 void Connection::removeFilterInternal(const std::string& rule)
149 assert(m_connection && "Connection has to be established first.");
150 dbus_bus_remove_match(m_connection, rule.c_str(), &m_error);
151 if (dbus_error_is_set(&m_error)) {
152 std::string message = m_error.message;
153 dbus_error_free(&m_error);
154 ThrowMsg(Commons::InvalidArgumentException, "Invalid rule: " << message);
158 dbus_bool_t Connection::addWatch(DBusWatch* watch, void* data)
161 assert(data && "Connection should be passed as user data.");
162 Connection* this_ = static_cast<Connection*>(data);
163 WatchPtr wrapper(new Watch(watch));
164 if (wrapper->isEnabled()) {
165 this_->m_messageDispatcher->addDescriptor(wrapper->getHandle(),
168 DPL::Mutex::ScopedLock lock(&this_->m_watchesMutex);
169 this_->m_watches[wrapper->getHandle()] = wrapper;
173 void Connection::removeWatch(DBusWatch* watch, void* data)
176 assert(data && "Connection should be passed as user data.");
177 Connection* this_ = static_cast<Connection*>(data);
178 Watch wrapper(watch);
179 if (wrapper.isEnabled()) {
180 this_->m_messageDispatcher->removeDescriptor(wrapper.getHandle(),
183 DPL::Mutex::ScopedLock lock(&this_->m_watchesMutex);
184 this_->m_watches.erase(wrapper.getHandle());
187 void Connection::toggleWatch(DBusWatch* watch, void* data)
190 assert(data && "Connection should be passed as user data.");
191 Connection* this_ = static_cast<Connection*>(data);
192 Watch wrapper(watch);
193 if (wrapper.isEnabled()) {
194 this_->m_messageDispatcher->addDescriptor(wrapper.getHandle(),
197 this_->m_messageDispatcher->removeDescriptor(wrapper.getHandle(),
202 DBusHandlerResult Connection::filterMessage(DBusConnection* /*connection*/,
203 DBusMessage* message,
208 Connection* this_ = static_cast<Connection*>(data);
212 "DBUS message received from interface: " <<
213 dbus_message_get_interface(message));
214 msg.Reset(new Message(message));
216 LogError("DBus message not set, this should not happen!");
217 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
220 LogDebug("____HERE");
221 FilterSetIterator it = this_->m_filters.begin();
222 for (; it != this_->m_filters.end(); ++it) {
223 // TODO: extend following matching procedure to check not only
225 if ((*it).find(msg->getInterface()) != std::string::npos) {
226 LogDebug("______emitting...");
227 MessageEvent event(msg);
228 this_->EmitEvent(event);
229 LogDebug("______done");
233 LogError("User-data not set, this should not happen!");
235 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
238 Connection::MessageDispatcher::MessageDispatcher(Connection* connection)
239 : m_connection(connection)
241 assert(m_connection && "Connection cannot be NULL.");
242 DPL::Event::ControllerEventHandler<AddDescriptorEvent>::Touch();
243 DPL::Event::ControllerEventHandler<RemoveDescriptorEvent>::Touch();
246 Connection::MessageDispatcher::~MessageDispatcher()
248 SwitchToThread(NULL);
251 void Connection::MessageDispatcher::addDescriptor(DPL::WaitableHandle handle,
252 DPL::WaitMode::Type mode)
255 AddDescriptorEvent event(handle, mode);
256 DPL::Event::ControllerEventHandler<AddDescriptorEvent>::PostSyncEvent(event);
259 void Connection::MessageDispatcher::removeDescriptor(DPL::WaitableHandle handle,
260 DPL::WaitMode::Type mode)
263 RemoveDescriptorEvent event(handle, mode);
264 DPL::Event::ControllerEventHandler<RemoveDescriptorEvent>::PostSyncEvent(event);
267 void Connection::MessageDispatcher::OnEventReceived(
268 const AddDescriptorEvent& event)
271 DPL::WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
277 void Connection::MessageDispatcher::OnEventReceived(
278 const RemoveDescriptorEvent& event)
281 DPL::WaitableHandleWatchSupport::InheritedContext()->
282 RemoveWaitableHandleWatch(this, event.GetArg0(), event.GetArg1());
285 void Connection::MessageDispatcher::OnWaitableHandleEvent(
286 DPL::WaitableHandle waitableHandle,
287 DPL::WaitMode::Type mode)
291 DPL::Mutex::ScopedLock lock(&m_connection->m_watchesMutex);
292 WatchSetIterator it = m_connection->m_watches.find(waitableHandle);
293 if (it != m_connection->m_watches.end()) {
295 (mode == DPL::WaitMode::Write ? DBUS_WATCH_WRITABLE
296 : DBUS_WATCH_READABLE);
297 while (!dbus_watch_handle(it->second->get(), flags)) {
298 LogError("Too few memory!");
299 // TODO: add some check-point to not loop infinitely
302 // TODO: not sure if there is point in dispatching connection when watch not found?
304 dbus_connection_ref(m_connection->m_connection);
305 while (dbus_connection_dispatch(m_connection->m_connection) ==
306 DBUS_DISPATCH_DATA_REMAINS) {
308 dbus_connection_unref(m_connection->m_connection);
311 Connection::Watch::Watch(DBusWatch* watch) : m_watch(watch)
313 assert(m_watch && "Watch cannot be NULL.");
316 DPL::WaitableHandle Connection::Watch::getHandle() const
318 return dbus_watch_get_unix_fd(m_watch);
321 DPL::WaitMode::Type Connection::Watch::getType() const
323 if ((dbus_watch_get_flags(m_watch) & DBUS_WATCH_WRITABLE) != 0) {
324 return DPL::WaitMode::Write;
326 return DPL::WaitMode::Read;
329 bool Connection::Watch::isEnabled() const
331 return (TRUE == dbus_watch_get_enabled(m_watch));
334 DBusWatch* Connection::Watch::get() const