2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
18 #include "Connection.h"
21 #include <Commons/Exception.h>
28 Connection::Connection() :
30 m_messageDispatcher(NULL),
33 dbus_error_init(&m_error);
34 m_messageDispatcher = new MessageDispatcher(this);
37 Connection::~Connection()
41 LoggerE("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_private(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 LoggerD("Couldn't set-up watch functions.");
72 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Couldn't set-up watch functions.");
75 if (!dbus_connection_add_filter(m_connection, filterMessage, this, NULL)) {
76 LoggerD("Couldn't set signal handler callback.");
77 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Couldn't set signal handler callback.");
83 void Connection::close()
86 if (!m_connected) { return; }
88 dbus_connection_remove_filter(m_connection, filterMessage, this);
90 // Calls removeWatch() automagically.
91 if (!dbus_connection_set_watch_functions(m_connection, NULL, NULL, NULL,
93 DPL::Mutex::ScopedLock lock(&m_watchesMutex);
94 WatchSetIterator it = m_watches.begin();
95 for (; it != m_watches.end(); ++it) {
96 if (it->second->isEnabled()) {
97 m_messageDispatcher->removeDescriptor(it->second->getHandle(),
98 it->second->getType());
104 // TODO: think how to handle exception on filter removal; 1 - do nothing (now),
105 // 2 - remove the buggy one but throw an exception, 3 - remove the buggy one
106 // and don't throw any exception
107 for (FilterSetIterator it = m_filters.begin(); it != m_filters.end();
109 removeFilterInternal(*it);
112 dbus_connection_close(m_connection);
113 dbus_connection_unref(m_connection);
118 void Connection::addFilter(const std::string& rule)
121 addFilterInternal(rule);
123 m_filters.insert(rule);
126 void Connection::removeFilter(const std::string& rule)
129 removeFilterInternal(rule);
131 m_filters.erase(rule);
134 void Connection::setWorkerThread(DPL::Thread* thread)
138 LoggerE("Connection has already been established.");
139 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Connection has already been established.");
141 m_messageDispatcher->SwitchToThread(thread);
144 void Connection::addFilterInternal(const std::string& rule)
148 LoggerE("Connection has to be established first.");
149 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Connection has to be established first.");
151 dbus_bus_add_match(m_connection, rule.c_str(), &m_error);
152 if (dbus_error_is_set(&m_error)) {
153 std::string message = m_error.message;
154 dbus_error_free(&m_error);
155 ThrowMsg(WrtDeviceApis::Commons::InvalidArgumentException, "Invalid rule: " << message);
159 void Connection::removeFilterInternal(const std::string& rule)
163 LoggerE("Connection has to be established first.");
167 dbus_bus_remove_match(m_connection, rule.c_str(), &m_error);
168 if (dbus_error_is_set(&m_error)) {
169 std::string message = m_error.message;
170 dbus_error_free(&m_error);
171 LoggerD("removeFilterInternal error : " << message);
176 dbus_bool_t Connection::addWatch(DBusWatch* watch,
182 LoggerE("Connection should be passed as user data.");
183 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Connection should be passed as user data.");
185 Connection* this_ = static_cast<Connection*>(data);
186 WatchPtr wrapper(new Watch(watch));
187 if (wrapper->isEnabled()) {
188 this_->m_messageDispatcher->addDescriptor(wrapper->getHandle(),
191 DPL::Mutex::ScopedLock lock(&this_->m_watchesMutex);
192 this_->m_watches[wrapper->getHandle()] = wrapper;
196 void Connection::removeWatch(DBusWatch* watch,
202 LoggerE("Connection should be passed as user data.");
203 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Connection should be passed as user data.");
205 Connection* this_ = static_cast<Connection*>(data);
206 Watch wrapper(watch);
207 if (wrapper.isEnabled()) {
208 this_->m_messageDispatcher->removeDescriptor(wrapper.getHandle(),
211 DPL::Mutex::ScopedLock lock(&this_->m_watchesMutex);
212 this_->m_watches.erase(wrapper.getHandle());
215 void Connection::toggleWatch(DBusWatch* watch,
221 LoggerE("Connection should be passed as user data.");
222 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Connection should be passed as user data.");
224 Connection* this_ = static_cast<Connection*>(data);
225 Watch wrapper(watch);
226 if (wrapper.isEnabled()) {
227 this_->m_messageDispatcher->addDescriptor(wrapper.getHandle(),
230 this_->m_messageDispatcher->removeDescriptor(wrapper.getHandle(),
235 DBusHandlerResult Connection::filterMessage(DBusConnection* connection,
236 DBusMessage* message,
241 Connection* this_ = static_cast<Connection*>(data);
245 "DBUS message received from interface: " <<
246 dbus_message_get_interface(message));
247 msg.Reset(new Message(message));
249 LoggerE("DBus message not set, this should not happen!");
250 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
252 FilterSetIterator it = this_->m_filters.begin();
253 for (; it != this_->m_filters.end(); ++it) {
254 // TODO: extend following matching procedure to check not only
256 if (!msg->getInterface().empty() && ((*it).find(msg->getInterface()) != std::string::npos))
258 MessageEvent event(msg);
259 this_->EmitEvent(event);
263 LoggerE("User-data not set, this should not happen!");
265 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
268 Connection::MessageDispatcher::MessageDispatcher(Connection* connection) :
269 m_connection(connection)
273 LoggerE("Connection cannot be NULL.");
274 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Connection cannot be NULL.");
276 DPL::Event::ControllerEventHandler<AddDescriptorSyncEvent>::Touch();
277 DPL::Event::ControllerEventHandler<RemoveDescriptorSyncEvent>::Touch();
280 Connection::MessageDispatcher::~MessageDispatcher()
282 SwitchToThread(NULL);
285 void Connection::MessageDispatcher::addDescriptor(DPL::WaitableHandle handle,
286 DPL::WaitMode::Type mode)
289 DPL::WaitableEvent wait;
290 AddDescriptorSyncEvent event(handle, mode, &wait);
291 DPL::Event::ControllerEventHandler<AddDescriptorSyncEvent>::PostEvent(event);
292 DPL::WaitForSingleHandle(wait.GetHandle());
295 void Connection::MessageDispatcher::removeDescriptor(DPL::WaitableHandle handle,
296 DPL::WaitMode::Type mode)
299 DPL::WaitableEvent wait;
300 RemoveDescriptorSyncEvent event(handle, mode, &wait);
301 DPL::Event::ControllerEventHandler<RemoveDescriptorSyncEvent>::PostEvent(event);
302 DPL::WaitForSingleHandle(wait.GetHandle());
305 void Connection::MessageDispatcher::OnEventReceived(
306 const AddDescriptorSyncEvent& event)
309 DPL::WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch(
313 event.GetArg2()->Signal();
316 void Connection::MessageDispatcher::OnEventReceived(
317 const RemoveDescriptorSyncEvent& event)
320 DPL::WaitableHandleWatchSupport::InheritedContext()->
321 RemoveWaitableHandleWatch(this, event.GetArg0(), event.GetArg1());
322 event.GetArg2()->Signal();
325 void Connection::MessageDispatcher::OnWaitableHandleEvent(
326 DPL::WaitableHandle waitableHandle,
327 DPL::WaitMode::Type mode)
331 DPL::Mutex::ScopedLock lock(&m_connection->m_watchesMutex);
332 WatchSetIterator it = m_connection->m_watches.find(waitableHandle);
333 if (it != m_connection->m_watches.end()) {
335 (mode == DPL::WaitMode::Write ? DBUS_WATCH_WRITABLE
336 : DBUS_WATCH_READABLE);
337 while (!dbus_watch_handle(it->second->get(), flags)) {
338 LoggerE("Too few memory!");
339 // TODO: add some check-point to not loop infinitely
342 // TODO: not sure if there is point in dispatching connection when watch not found?
344 dbus_connection_ref(m_connection->m_connection);
345 while (dbus_connection_dispatch(m_connection->m_connection) ==
346 DBUS_DISPATCH_DATA_REMAINS) {
348 dbus_connection_unref(m_connection->m_connection);
351 Connection::Watch::Watch(DBusWatch* watch) : m_watch(watch)
355 LoggerE("Watch cannot be NULL.");
359 DPL::WaitableHandle Connection::Watch::getHandle() const
361 return dbus_watch_get_unix_fd(m_watch);
364 DPL::WaitMode::Type Connection::Watch::getType() const
366 if ((dbus_watch_get_flags(m_watch) & DBUS_WATCH_WRITABLE) != 0) {
367 return DPL::WaitMode::Write;
369 return DPL::WaitMode::Read;
372 bool Connection::Watch::isEnabled() const
374 return (TRUE == dbus_watch_get_enabled(m_watch));
377 DBusWatch* Connection::Watch::get() const