[dbus] add overload 'value' for custom dbus property types
[profile/ivi/automotive-message-broker.git] / plugins / dbus / automotivemanager.cpp
1 #include "automotivemanager.h"
2 #include "abstractdbusinterface.h"
3 #include "listplusplus.h"
4
5 static const gchar introspection_xml[] =
6   "<node>"
7   "  <interface name='org.automotive.Manager'>"
8   "    <method name='FindObject'>"
9   "      <arg type='s' name='searchstring' direction='in'/>"
10   "      <arg type='ao' name='response' direction='out'/>"
11   "    </method>"
12   "    <method name='FindObjectForZone'>"
13   "      <arg type='s' name='searchstring' direction='in'/>"
14   "      <arg type='i' name='zone' direction='in'/>"
15   "      <arg type='o' name='response' direction='out'/>"
16   "    </method>"
17   "    <method name='FindObjectForSourceZone'>"
18   "      <arg type='s' name='searchstring' direction='in'/>"
19   "      <arg type='s' name='source' direction='in'/>"
20   "      <arg type='i' name='zone' direction='in'/>"
21   "      <arg type='o' name='response' direction='out'/>"
22   "    </method>"
23   "    <method name='List'>"
24   "      <arg type='as' name='response' direction='out'/>"
25   "    </method>"
26   "    <method name='ZonesForObjectName'>"
27   "      <arg type='s' name='searchstring' direction='in'/>"
28   "      <arg type='ai' name='response' direction='out'/>"
29   "    </method>"
30   "    <method name='SourcesForObjectName'>"
31   "      <arg type='s' name='searchstring' direction='in'/>"
32   "      <arg type='as' name='response' direction='out'/>"
33   "    </method>"
34   "    <method name='SupportsProperty'>"
35   "      <arg type='s' name='objectName' direction='in'/>"
36   "      <arg type='s' name='propertyName' direction='in'/>"
37   "      <arg type='b' name='response' direction='out'/>"
38   "    </method>"
39   "  </interface>"
40   "</node>";
41
42 static void handleMethodCall(GDBusConnection       *connection,
43                                                          const gchar           *sender,
44                                                          const gchar           *object_path,
45                                                          const gchar           *interface_name,
46                                                          const gchar           *method_name,
47                                                          GVariant              *parameters,
48                                                          GDBusMethodInvocation *invocation,
49                                                          gpointer               user_data)
50 {
51
52         AutomotiveManager* manager = static_cast<AutomotiveManager*>(user_data);
53
54         std::string method = method_name;
55
56         uint pid = getPid(sender);
57
58         if(DebugOut::getDebugThreshhold() >= 6)
59         {
60                 DebugOut(6)<<"DBus method call from: "<<sender<< " pid: " <<pid<< " interface: "<<interface_name<<" method: "<<method<<endl;
61                 DebugOut(6)<<"DBus method call path: "<<object_path<<endl;
62         }
63
64         if(method == "FindObject")
65         {
66                 gchar* arg;
67
68                 g_variant_get(parameters,"(s)",&arg);
69
70                 std::string objectToFind = arg;
71
72                 if(objectToFind == "")
73                 {
74                         g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
75                         return;
76                 }
77
78                 std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(objectToFind);
79
80                 if(!interfaces.size())
81                 {
82                         g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Object not found");
83                         return;
84                 }
85
86                 GVariantBuilder params;
87                 g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);
88
89                 bool hasItems = false;
90
91                 for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
92                 {
93                         AbstractDBusInterface* t = *itr;
94                         if(!t->isSupported())
95                                 continue;
96
97                         hasItems = true;
98
99                         if(!t->isRegistered())
100                                 t->registerObject();
101
102                         std::list<std::string> processes = manager->subscribedProcesses[t];
103
104                         if(!contains(processes,sender))
105                         {
106                                 DebugOut()<<"Referencing "<<t->objectPath()<<" with sender: "<<sender<<endl;
107                                 manager->subscribedProcesses[t].push_back(sender);
108                         }
109
110                         GVariant *newvar = g_variant_new("o",t->objectPath().c_str());
111                         g_variant_builder_add_value(&params, newvar);
112                 }
113
114                 if(hasItems)
115                         g_dbus_method_invocation_return_value(invocation, g_variant_new("(ao)",&params));
116                 else
117                         g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
118
119         }
120
121         else if(method == "FindObjectForZone")
122         {
123                 gchar* arg;
124                 int zone;
125
126                 g_variant_get(parameters,"(si)", &arg, &zone);
127
128                 std::string propertyToFind = arg;
129
130                 if(propertyToFind == "")
131                 {
132                         g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
133                         return;
134                 }
135
136                 std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);
137
138                 if(!interfaces.size())
139                 {
140                         g_dbus_method_invocation_return_dbus_error(invocation, "org.automotive.Manager.ObjectNotFound", "Property not found");
141                         return;
142                 }
143
144
145
146                 for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
147                 {
148                         AbstractDBusInterface* t = *itr;
149
150                         if(t->zone() == (Zone::Type)zone)
151                         {
152                                 if(!t->isRegistered())
153                                         t->registerObject();
154
155                                 std::list<std::string> processes = manager->subscribedProcesses[t];
156
157                                 if(!contains(processes,sender))
158                                 {
159                                         DebugOut()<<"Referencing "<<t->objectPath()<<" with sender: "<<sender<<endl;
160                                         manager->subscribedProcesses[t].push_back(sender);
161                                 }
162
163                                 g_dbus_method_invocation_return_value(invocation,g_variant_new("(o)", t->objectPath().c_str()));
164                                 return;
165                         }
166                 }
167
168                 g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.InvalidZone", "zone not found");
169         }
170
171         else if (method == "ZonesForObjectName")
172         {
173                 gchar* arg;
174
175                 g_variant_get(parameters,"(s)",&arg);
176
177                 std::string propertyToFind = arg;
178
179                 if(propertyToFind == "")
180                 {
181                         g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
182                         return;
183                 }
184
185                 std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);
186
187                 if(!interfaces.size())
188                 {
189                         g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
190                         return;
191                 }
192
193                 GVariantBuilder params;
194                 g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);
195
196                 for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
197                 {
198                         AbstractDBusInterface* t = *itr;
199                         GVariant *newvar = g_variant_new("i",t->zone());
200                         g_variant_builder_add_value(&params, newvar);
201
202                 }
203
204                 g_dbus_method_invocation_return_value(invocation,g_variant_new("(ai)",&params));
205         }
206
207         else if(method == "List")
208         {
209                 std::vector<std::string> supportedProperties = AbstractDBusInterface::supportedInterfaces();
210
211                 if(!supportedProperties.size())
212                 {
213                         g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.Error", "No supported objects");
214                         return;
215                 }
216
217                 std::sort(supportedProperties.begin(), supportedProperties.end());
218                 auto itr = std::unique(supportedProperties.begin(), supportedProperties.end());
219
220                 supportedProperties.erase(itr, supportedProperties.end());
221
222                 GVariantBuilder builder;
223                 g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
224
225                 for(auto objectName  : supportedProperties)
226                 {
227                         g_variant_builder_add(&builder, "s", objectName.c_str());
228                 }
229
230                 g_dbus_method_invocation_return_value(invocation,g_variant_new("(as)",&builder));
231         }
232         else if(method == "SourcesForObjectName")
233         {
234                 gchar* arg;
235
236                 g_variant_get(parameters,"(s)",&arg);
237
238                 std::string propertyToFind = arg;
239
240                 if(propertyToFind == "")
241                 {
242                         g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
243                         return;
244                 }
245
246                 std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);
247
248                 if(!interfaces.size())
249                 {
250                         g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
251                         return;
252                 }
253
254                 GVariantBuilder params;
255                 g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);
256
257                 for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
258                 {
259                         AbstractDBusInterface* t = *itr;
260                         string source = t->source();
261                         boost::algorithm::erase_all(source, "-");
262                         GVariant *newvar = g_variant_new("s", source.c_str());
263                         g_variant_builder_add_value(&params, newvar);
264
265                 }
266
267                 g_dbus_method_invocation_return_value(invocation,g_variant_new("(as)",&params));
268         }
269         else if(method == "FindObjectForSourceZone")
270         {
271                 gchar* arg;
272                 gchar* arg2;
273                 int zone;
274
275                 g_variant_get(parameters,"(ssi)", &arg, &arg2, &zone);
276
277                 std::string propertyToFind = arg;
278                 std::string source = arg2;
279
280                 if(propertyToFind == "" || source == "")
281                 {
282                         g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
283                         return;
284                 }
285
286                 std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);
287
288                 if(!interfaces.size())
289                 {
290                         g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
291                         return;
292                 }
293
294                 for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
295                 {
296                         AbstractDBusInterface* t = *itr;
297                         string targetSource = t->source();
298                         boost::algorithm::erase_all(targetSource, "-");
299                         if(t->zone() == (Zone::Type)zone && source == targetSource)
300                         {
301                                 if(!t->isRegistered())
302                                         t->registerObject();
303
304                                 std::list<std::string> processes = manager->subscribedProcesses[t];
305
306                                 if(!contains(processes,sender))
307                                 {
308                                         DebugOut()<<"Referencing "<<t->objectPath()<<" with sender: "<<sender<<endl;
309                                         manager->subscribedProcesses[t].push_back(sender);
310                                 }
311
312                                 g_dbus_method_invocation_return_value(invocation,g_variant_new("(o)", t->objectPath().c_str()));
313                                 return;
314                         }
315                 }
316
317                 g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
318         }
319         else if(method == "SupportsProperty")
320         {
321                 gchar* objectName;
322                 gchar* propertyToFindStr;
323
324                 g_variant_get(parameters,"(ss)",&objectName, &propertyToFindStr);
325
326                 auto objectNamePtr = amb::make_super(objectName);
327                 auto propertyToFindStrPtr = amb::make_super(propertyToFindStr);
328
329                 DebugOut(6) << "Checking " << objectNamePtr.get() << " for member: " << propertyToFindStrPtr.get() << endl;
330
331                 std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(objectNamePtr.get());
332
333                 for(auto i : interfaces)
334                 {
335                         if(i->hasPropertyDBus(propertyToFindStrPtr.get()))
336                         {
337                                 DebugOut(6) << "member " << propertyToFindStrPtr.get() << " of " << objectNamePtr.get() << " was found!!" << endl;
338                                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", true));
339                                 return;
340                         }
341                 }
342                 DebugOut(6) << "member " << propertyToFindStrPtr.get() << " of " << objectNamePtr.get() << " was not found." << endl;
343                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", false));
344         }
345         else
346         {
347                 g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
348         }
349 }
350
351 static void signalCallback( GDBusConnection *connection,
352                                                         const gchar *sender_name,
353                                                         const gchar *object_path,
354                                                         const gchar *interface_name,
355                                                         const gchar *signal_name,
356                                                         GVariant *parameters,
357                                                         gpointer user_data)
358 {
359         AutomotiveManager* manager = static_cast<AutomotiveManager*>(user_data);
360
361         if(!manager)
362         {
363                 DebugOut(DebugOut::Error)<<"Bad user_data"<<endl;
364                 return;
365         }
366
367         gchar* name=nullptr;
368         gchar* newOwner=nullptr;
369         gchar* oldOwner = nullptr;
370         g_variant_get(parameters,"(sss)",&name, &oldOwner, &newOwner);
371
372         std::list<AbstractDBusInterface*> toRemove;
373
374         if(std::string(newOwner) == "")
375         {
376                 for(auto &i : manager->subscribedProcesses)
377                 {
378                         AbstractDBusInterface* iface = i.first;
379
380                         for(auto itr = i.second.begin(); itr != i.second.end(); itr++)
381                         {
382                                 std::string n = *itr;
383                                 if(n == name)
384                                 {
385                                         DebugOut()<<"unreferencing "<<n<<" from the subscription of "<<iface->objectPath()<<endl;
386                                         itr = manager->subscribedProcesses[iface].erase(itr);
387                                         DebugOut()<<"new ref count: "<<manager->subscribedProcesses[iface].size()<<endl;
388                                 }
389                         }
390
391                         if(manager->subscribedProcesses[iface].empty())
392                         {
393                                 DebugOut()<<"No more subscribers.  Unregistering: "<<iface->objectPath()<<endl;
394                                 ///Defer removal to not screw up the list
395                                 toRemove.push_back(iface);
396                                 iface->unregisterObject();
397                         }
398                 }
399
400                 for(auto & i : toRemove)
401                 {
402                         manager->subscribedProcesses.erase(i);
403                 }
404         }
405
406         g_free(name);
407         g_free(newOwner);
408         g_free(oldOwner);
409 }
410
411 static GVariant* getProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GError** error, gpointer userData)
412 {
413         return NULL;
414 }
415
416 static gboolean setProperty(GDBusConnection * connection, const gchar * sender, const gchar *objectPath,
417                                                         const gchar *interfaceName, const gchar * propertyName, GVariant *value,
418                                                         GError** error, gpointer userData)
419 {
420         return false;
421 }
422
423 static const GDBusInterfaceVTable interfaceVTable =
424 {
425         handleMethodCall,
426         getProperty,
427         setProperty
428 };
429
430 AutomotiveManager::AutomotiveManager(GDBusConnection *connection)
431         :mConnection(connection)
432 {
433         GError* error = NULL;
434
435         GDBusNodeInfo* introspection = g_dbus_node_info_new_for_xml(introspection_xml, &error);
436         GDBusInterfaceInfo* mInterfaceInfo = g_dbus_node_info_lookup_interface(introspection, "org.automotive.Manager");
437
438         regId = g_dbus_connection_register_object(mConnection, "/", mInterfaceInfo, &interfaceVTable, this, NULL, &error);
439         g_dbus_node_info_unref(introspection);
440
441         auto errorPtr = amb::make_super(error);
442
443         if(errorPtr){
444                 DebugOut(DebugOut::Error) << "registering dbus object: " << "'org.automotive.Manager' " << errorPtr->message << endl;
445                 throw -1;
446         }
447
448         g_assert(regId > 0);
449
450         g_dbus_connection_signal_subscribe(mConnection, "org.freedesktop.DBus", "org.freedesktop.DBus",
451                                                                                                                                                                            "NameOwnerChanged", "/org/freedesktop/DBus", NULL, G_DBUS_SIGNAL_FLAGS_NONE,
452                                                                                                                                                                            signalCallback, this, NULL);
453 }
454
455 AutomotiveManager::~AutomotiveManager()
456 {
457         g_dbus_connection_unregister_object(mConnection, regId);
458 }