2 Copyright (C) 2012 Intel Corporation
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "abstractdbusinterface.h"
21 #include <abstractroutingengine.h>
23 #include <boost/algorithm/string.hpp>
24 #include <boost/algorithm/string/predicate.hpp>
26 #include <listplusplus.h>
28 #include "varianttype.h"
30 #include "dbussignaller.h"
32 static DBusSignaller* signaller = nullptr;
34 unordered_map<string, AbstractDBusInterface*> AbstractDBusInterface::objectMap;
35 PropertyList AbstractDBusInterface::mimplementedProperties;
37 const uint getPid(const char *owner)
39 GError* error = nullptr;
40 GDBusProxy* dbus = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
41 "org.freedesktop.DBus",
43 "org.freedesktop.DBus",
49 throw std::runtime_error(error->message);
54 GVariant* pid = g_dbus_proxy_call_sync(dbus, "GetConnectionUnixProcessID", g_variant_new("(s)", owner), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
58 throw std::runtime_error(error->message);
63 g_variant_get(pid,"(u)",&thePid);
70 static void handleMyMethodCall(GDBusConnection *connection,
72 const gchar *object_path,
73 const gchar *interface_name,
74 const gchar *method_name,
76 GDBusMethodInvocation *invocation,
80 std::string method = method_name;
81 AbstractDBusInterface* iface = static_cast<AbstractDBusInterface*>(user_data);
83 if(DebugOut::getDebugThreshhold() >= 6)
85 DebugOut(6)<<"DBus method call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interface_name<<" method: "<<method<<endl;
86 DebugOut(6)<<"DBus method call path: "<<object_path<<endl;
91 if(method == "GetHistory")
96 g_variant_get(parameters, "(dd)", &beginTime, &endTime);
98 auto propertyMap = iface->getProperties();
100 PropertyList propertyList;
102 for(auto itr = propertyMap.begin(); itr != propertyMap.end(); itr++)
104 AbstractProperty* prop = (*itr).second;
106 if(!contains(propertyList, prop->ambPropertyName()))
107 propertyList.push_back(prop->ambPropertyName());
110 std::string ifaceName = iface->interfaceName();
112 AsyncRangePropertyRequest request;
114 request.properties = propertyList;
115 request.timeBegin = beginTime;
116 request.timeEnd = endTime;
117 request.zone = iface->zone();
118 //request.sourceUuid = iface->source();
120 request.completed = [&invocation,&ifaceName](AsyncRangePropertyReply* r)
122 auto reply = amb::make_unique(r);
126 str<<"Error during request: "<<AsyncPropertyReply::errorToStr(reply->error);
127 ifaceName += ".Error";
128 g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), str.str().c_str());
132 if(!reply->values.size())
134 ifaceName += ".Error";
135 g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), "No results");
139 GVariantBuilder builder;
140 g_variant_builder_init(&builder, G_VARIANT_TYPE("a(svd)"));
143 for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
145 AbstractPropertyType* value = *itr;
147 g_variant_builder_add(&builder, "(svd)", value->name.c_str(), g_variant_ref(value->toVariant()),value->timestamp);
150 g_dbus_method_invocation_return_value(invocation,g_variant_new("(a(svd))",&builder));
153 iface->re->getRangePropertyAsync(request);
158 else if(boost::algorithm::starts_with(method, "Get"))
160 std::string propertyName = method.substr(3);
161 auto propertyMap = iface->getProperties();
162 if(propertyMap.find(propertyName) == propertyMap.end())
164 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
168 AbstractProperty* property = propertyMap[propertyName];
170 GError *error = NULL;
172 GVariant **params = g_new(GVariant*,4);
173 GVariant *val = g_variant_ref(property->value()->toVariant());
174 params[0] = g_variant_new("v", val);
175 params[1] = g_variant_new("d",property->timestamp);
176 params[2] = g_variant_new("i",property->value()->sequence);
177 params[3] = g_variant_new("i",property->updateFrequency());
179 GVariant *tuple_variant = g_variant_new_tuple(params,4);
181 g_dbus_method_invocation_return_value(invocation, tuple_variant);
184 g_variant_unref(val);
188 DebugOut(DebugOut::Error)<<error->message<<endl;
194 g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
197 AbstractDBusInterface::AbstractDBusInterface(string interfaceName, string objectName,
198 GDBusConnection* connection)
199 : mInterfaceName(interfaceName), mConnection(connection), mPropertyName(objectName), supported(false), zoneFilter(Zone::None), mTime(0), regId(0)
203 mObjectPath = "/" + objectName;
206 AbstractDBusInterface::~AbstractDBusInterface()
210 PropertyList impl = implementedProperties();
212 for(auto itr = impl.begin(); itr != impl.end(); itr++)
214 if(properties.find(*itr) != properties.end())
216 // Deleted in ~DBusSink()
217 //delete properties[*itr];
218 properties.erase(*itr);
222 objectMap.erase(mObjectPath);
226 void AbstractDBusInterface::addProperty(AbstractProperty* property)
228 string nameToLower = property->name;
229 boost::algorithm::to_lower<string>(nameToLower);
233 if(property->access() == AbstractProperty::Read)
235 else if(property->access() == AbstractProperty::Write)
237 else if(property->access() == AbstractProperty::ReadWrite)
238 access = "readwrite";
239 else throw -1; //FIXME: don't throw
241 std::string pn = property->name;
243 ///see which properties are supported:
245 "<property type='"+ string(property->signature()) + "' name='"+ pn +"' access='"+access+"' />"
246 "<method name='Get" + pn + "'>"
247 " <arg type='v' direction='out' name='value' />"
248 " <arg type='d' direction='out' name='timestamp' />"
249 " <arg type='i' direction='out' name='sequence' />"
250 " <arg type='i' direction='out' name='updateFrequency' />"
252 "<signal name='" + pn + "Changed' >"
253 " <arg type='v' name='" + nameToLower + "' direction='out' />"
254 " <arg type='d' name='imestamp' direction='out' />"
256 "<property type='i' name='" + property->name + "Sequence' access='read' />";
258 properties[property->name] = property;
260 if(!contains(mimplementedProperties, property->ambPropertyName()))
262 std::string pname = property->ambPropertyName();
263 mimplementedProperties.push_back(pname);
267 void AbstractDBusInterface::registerObject()
271 throw std::runtime_error("forgot to call setDBusConnection on AbstractDBusInterface");
274 if(introspectionXml.empty())
276 cerr<<"no interface to export: "<<mInterfaceName<<endl;
280 if(!boost::algorithm::ends_with(introspectionXml,"</node>"))
282 introspectionXml += "</interface>"
288 GDBusNodeInfo* introspection = g_dbus_node_info_new_for_xml(introspectionXml.c_str(), &error);
290 if(!introspection || error)
293 DebugOut(DebugOut::Error)<<"Error in "<<__FILE__<<" - "<<__FUNCTION__<<":"<<__LINE__<<endl;
294 DebugOut(DebugOut::Error)<<error->message<<endl;
295 DebugOut(DebugOut::Error)<<"probably bad xml:"<<endl;
296 DebugOut(DebugOut::Error)<<introspectionXml<<endl;
303 GDBusInterfaceInfo* mInterfaceInfo = g_dbus_node_info_lookup_interface(introspection, mInterfaceName.c_str());
306 const GDBusInterfaceVTable vtable = { handleMyMethodCall, AbstractDBusInterface::getProperty, AbstractDBusInterface::setProperty };
310 DebugOut()<<"registering DBus path: "<<mObjectPath<<endl;
312 regId = g_dbus_connection_register_object(mConnection, mObjectPath.c_str(), mInterfaceInfo, &vtable, this, NULL, &error2);
313 g_dbus_node_info_unref(introspection);
316 DebugOut(DebugOut::Error)<<error2->message<<endl;
317 g_error_free(error2);
322 DebugOut(DebugOut::Error)<<"We failed to register on DBus"<<endl;
326 void AbstractDBusInterface::unregisterObject()
330 DebugOut()<<__FUNCTION__<<endl;
331 g_dbus_connection_unregister_object(mConnection, regId);
337 void AbstractDBusInterface::updateValue(AbstractProperty *property)
339 if(mConnection == nullptr)
345 signaller->fireSignal(mConnection, mObjectPath, mInterfaceName, "PropertiesChanged", property);
348 std::list<AbstractDBusInterface *> AbstractDBusInterface::getObjectsForProperty(string object)
350 std::list<AbstractDBusInterface *> l;
351 for(auto itr = objectMap.begin(); itr != objectMap.end(); itr++)
353 AbstractDBusInterface * interface = (*itr).second;
354 if(interface->objectName() == object)
355 l.push_back(interface);
360 list<AbstractDBusInterface *> AbstractDBusInterface::interfaces()
362 std::list<AbstractDBusInterface*> ifaces;
364 for(auto itr = objectMap.begin(); itr != objectMap.end(); itr++)
366 ifaces.push_back((*itr).second);
372 std::vector<std::string> AbstractDBusInterface::supportedInterfaces()
374 std::vector<std::string> ifaces;
376 for(auto itr : objectMap)
378 if(itr.second->isSupported())
379 ifaces.push_back(itr.second->objectName());
385 bool AbstractDBusInterface::implementsProperty(string property)
387 for(auto itr = properties.begin(); itr != properties.end(); itr++)
389 if((*itr).first == property)
398 void AbstractDBusInterface::startRegistration()
400 //unregisterObject();
401 introspectionXml ="<node>" ;
403 "<interface name='"+ mInterfaceName + "' >"
404 "<property type='i' name='Zone' access='read' />"
405 "<property type='d' name='Time' access='read' />"
406 "<method name='GetHistory'>"
407 " <arg type='d' direction='in' name='beginTimestamp' />"
408 " <arg type='d' direction='in' name='endTimestamp' />"
409 " <arg type='a(svd)' direction='out' name='result' />"
413 GVariant* AbstractDBusInterface::getProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GError** error, gpointer userData)
415 if(DebugOut::getDebugThreshhold() >= 6)
417 DebugOut(6)<<"DBus GetProperty call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interfaceName<<" property: "<<propertyName<<endl;
418 DebugOut(6)<<"DBus GetProperty call path: "<<objectPath<<endl;
421 std::string pn = propertyName;
424 if(objectMap.find(objectPath) == objectMap.end())
426 DebugOut(DebugOut::Error)<<objectPath<<" is not a valid object path."<<endl;
429 double time = objectMap[objectPath]->time();
431 GVariant* value = g_variant_new("d", time);
435 if(boost::ends_with(pn, "Sequence"))
437 AbstractDBusInterface* t = static_cast<AbstractDBusInterface*>(userData);
439 int pos = pn.find("Sequence");
441 std::string p = pn.substr(0,pos);
443 AbstractProperty* theProperty = t->property(p);
447 DebugOut(DebugOut::Error)<<"Invalid Sequence property: "<<p<<endl;
451 int sequence = theProperty->sequence;
453 GVariant* value = g_variant_new("i", sequence);
459 if(objectMap.find(objectPath) == objectMap.end())
461 DebugOut(DebugOut::Error)<<objectPath<<" is not a valid object path."<<endl;
465 Zone::Type zone = objectMap[objectPath]->zone();
467 GVariant* value = g_variant_new("i",(int)zone);
471 if(objectMap.count(objectPath))
473 GVariant* value = objectMap[objectPath]->getProperty(propertyName);
478 DebugOut(DebugOut::Error)<<"No interface for" << interfaceName <<endl;
482 gboolean AbstractDBusInterface::setProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GVariant* value, GError** error, gpointer userData)
484 if(DebugOut::getDebugThreshhold() >= 6)
486 DebugOut(6)<<"DBus SetProperty call from: "<<sender<< " pid: " <<getPid(sender)<< " interface: "<<interfaceName<<" property: "<<propertyName<<endl;
487 DebugOut(6)<<"DBus SetProperty call path: "<<objectPath<<endl;
490 if(objectMap.count(objectPath))
492 objectMap[objectPath]->setProperty(propertyName, value);
499 void AbstractDBusInterface::setProperty(string propertyName, GVariant *value)
501 if(properties.count(propertyName))
503 properties[propertyName]->fromVariant(value);
511 GVariant *AbstractDBusInterface::getProperty(string propertyName)
513 if(properties.count(propertyName))
514 return properties[propertyName]->toVariant();
519 void AbstractDBusInterface::setTimeout(int timeout)
522 signaller = DBusSignaller::factory(timeout);