Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_wearable / dbus / src / connection.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file    connection.cpp
18  * @author  Zbigniew Kostrzewa (z.kostrzewa@samsung.com)
19  * @version 1.0
20  * @brief
21  */
22 #include <stddef.h>
23 #include <dpl/log/log.h>
24 #include <dpl/dbus/connection.h>
25 #include <dpl/dbus/exception.h>
26 #include <dpl/dbus/object_proxy.h>
27
28 namespace DPL {
29 namespace DBus {
30 ConnectionPtr Connection::sessionBus()
31 {
32     return connectTo(G_BUS_TYPE_SESSION);
33 }
34
35 ConnectionPtr Connection::systemBus()
36 {
37     return connectTo(G_BUS_TYPE_SYSTEM);
38 }
39
40 ConnectionPtr Connection::connectTo(GBusType busType)
41 {
42     GError* error = NULL;
43
44     GDBusConnection* connection = g_bus_get_sync(busType,
45                                                  NULL,
46                                                  &error);
47     if (NULL == connection) {
48         std::string message;
49         if (NULL != error) {
50             message = error->message;
51             g_error_free(error);
52         }
53         ThrowMsg(DBus::Exception,
54                  "Couldn't connect to bus: " << message);
55     }
56
57     g_dbus_connection_set_exit_on_close(connection, FALSE);
58
59     return ConnectionPtr(new Connection(connection));
60 }
61
62 ConnectionPtr Connection::connectTo(const std::string& address)
63 {
64     GError* error = NULL;
65
66     GDBusConnection* connection = g_dbus_connection_new_for_address_sync(
67             address.c_str(),
68             G_DBUS_CONNECTION_FLAGS_NONE,
69             NULL,
70             NULL,
71             &error);
72     if (NULL == connection) {
73         std::string message;
74         if (NULL != error) {
75             message = error->message;
76             g_error_free(error);
77         }
78         ThrowMsg(DBus::Exception,
79                  "Couldn't connect to " << address << ": " << message);
80     }
81
82     return ConnectionPtr(new Connection(connection));
83 }
84
85 Connection::Connection(GDBusConnection* connection) :
86     m_connection(connection)
87 {
88     g_signal_connect(m_connection,
89                      "closed",
90                      G_CALLBACK(onConnectionClosed),
91                      this);
92 }
93
94 Connection::~Connection()
95 {
96     std::for_each(m_registeredServices.begin(),
97                   m_registeredServices.end(),
98                   [] (const RegisteredServices::value_type & value)
99                   {
100                       g_bus_unown_name(value.second);
101                   });
102
103     std::for_each(m_registeredObjects.begin(),
104                   m_registeredObjects.end(),
105                   [this] (const RegisteredObjects::value_type & value)
106                   {
107                       g_dbus_connection_unregister_object(
108                           m_connection,
109                           value.second.registrationId);
110                   });
111
112     if (!g_dbus_connection_is_closed(m_connection)) {
113         GError* error = NULL;
114
115         if (FALSE ==
116             g_dbus_connection_flush_sync(m_connection, NULL, &error))
117         {
118             LogPedantic("Could not flush the connection"
119                         << " <" << error->message << ">");
120             g_error_free(error);
121         }
122     }
123
124     g_object_unref(m_connection);
125 }
126
127 void Connection::registerService(const std::string& serviceName)
128 {
129     guint regId = g_bus_own_name_on_connection(m_connection,
130                                                serviceName.c_str(),
131                                                G_BUS_NAME_OWNER_FLAGS_NONE,
132                                                onServiceNameAcquired,
133                                                onServiceNameLost,
134                                                this,
135                                                NULL);
136     if (0 >= regId) {
137         ThrowMsg(DBus::Exception, "Error while registering service.");
138     }
139
140     m_registeredServices.insert(RegisteredServices::value_type(serviceName,
141                                                                regId));
142 }
143
144 void Connection::unregisterService(const std::string& serviceName)
145 {
146     auto it = m_registeredServices.find(serviceName);
147     if (m_registeredServices.end() == it) {
148         ThrowMsg(DBus::Exception, "Service not registered.");
149     }
150
151     g_bus_unown_name(it->second);
152
153     m_registeredServices.erase(it);
154 }
155
156 void Connection::registerObject(const ObjectPtr& object)
157 {
158     GError* error = NULL;
159
160     guint regId = g_dbus_connection_register_object(
161             m_connection,
162             object->getPath().c_str(),
163             object->getInterface()->getInfo(),
164             object->getInterface()->getVTable(),
165             // TODO This is ugly, fix this!
166             object->getInterface().get(),
167             NULL,
168             &error);
169     if (0 == regId) {
170         std::string message;
171         if (NULL != error) {
172             message = error->message;
173             LogPedantic(error->message << " " << error->code);
174             g_error_free(error);
175         }
176         ThrowMsg(DBus::Exception, "Error while registering an object: "
177                  << message);
178     }
179
180     m_registeredObjects.insert(RegisteredObjects::value_type(
181                                    object->getPath(),
182                                    ObjectRegistration(regId, object)));
183 }
184
185 void Connection::unregisterObject(const std::string& objectPath)
186 {
187     auto it = m_registeredObjects.find(objectPath);
188     if (m_registeredObjects.end() == it) {
189         ThrowMsg(DBus::Exception, "Object not registered.");
190     }
191
192     gboolean result = g_dbus_connection_unregister_object(
193             m_connection,
194             it->second.registrationId);
195     if (FALSE == result) {
196         ThrowMsg(DBus::Exception, "Unregistering object failed.");
197     }
198     m_registeredObjects.erase(it);
199 }
200
201 ObjectProxyPtr Connection::createObjectProxy(const std::string& serviceName,
202                                              const std::string& objectPath)
203 {
204     if (g_dbus_connection_is_closed(m_connection)) {
205         ThrowMsg(DBus::ConnectionClosedException, "Connection closed.");
206     }
207
208     return ObjectProxyPtr(
209                new ObjectProxy(m_connection, serviceName, objectPath));
210 }
211
212 void Connection::onServiceNameAcquired(GDBusConnection* /*connection*/,
213                                        const gchar* serviceName,
214                                        gpointer data)
215 {
216     AssertMsg(data, "Connection should not be NULL");
217
218     Connection* self = static_cast<Connection*>(data);
219
220     LogPedantic("Emitting service name acquired event: " << serviceName);
221
222     ConnectionEvents::ServiceNameAcquiredEvent event(serviceName);
223     self->DPL::Event::EventSupport<ConnectionEvents::ServiceNameAcquiredEvent>
224         ::
225         EmitEvent(event, DPL::Event::EmitMode::Queued);
226 }
227
228 void Connection::onServiceNameLost(GDBusConnection* /*connection*/,
229                                    const gchar* serviceName,
230                                    gpointer data)
231 {
232     AssertMsg(data, "Connection should not be NULL");
233
234     Connection* self = static_cast<Connection*>(data);
235
236     LogPedantic("Emitting service name lost event: " << serviceName);
237
238     ConnectionEvents::ServiceNameLostEvent event(serviceName);
239     self->DPL::Event::EventSupport<ConnectionEvents::ServiceNameLostEvent>::
240         EmitEvent(event, DPL::Event::EmitMode::Queued);
241 }
242
243 void Connection::onConnectionClosed(GDBusConnection* /*connection*/,
244                                     gboolean peerVanished,
245                                     GError* error,
246                                     gpointer data)
247 {
248     AssertMsg(NULL != data, "Connection cannot be NULL");
249
250     Connection* self = static_cast<Connection*>(data);
251
252     if ((NULL == error) && (FALSE == peerVanished)) {
253         // Connection closed by this.
254     } else if (NULL != error) {
255         std::string message = error->message;
256
257         g_error_free(error);
258
259         if (TRUE == peerVanished) {
260             // Connection closed by remote host.
261             ConnectionEvents::ConnectionBrokenEvent event(message);
262             self->DPL::Event::EventSupport<ConnectionEvents::
263                                                ConnectionBrokenEvent>::
264                 EmitEvent(event, DPL::Event::EmitMode::Queued);
265         } else {
266             // Invalid or malformed data on connection.
267             ConnectionEvents::ConnectionInvalidEvent event(message);
268             self->DPL::Event::EventSupport<ConnectionEvents::
269                                                ConnectionInvalidEvent>::
270                 EmitEvent(event, DPL::Event::EmitMode::Queued);
271         }
272     }
273 }
274 }
275 }