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