Reorganise to remove redundant folder
[profile/ivi/common-api-dbus-runtime.git] / src / CommonAPI / DBus / DBusServiceRegistry.cpp
1 /* This Source Code Form is subject to the terms of the Mozilla Public\r
2  * License, v. 2.0. If a copy of the MPL was not distributed with this\r
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\r
4 #include <utility>\r
5 #include <sstream>\r
6 #include <iostream>\r
7 #include <string>\r
8 #include <tuple>\r
9 #include <unistd.h>\r
10 \r
11 #include "DBusServiceRegistry.h"\r
12 #include "DBusInputStream.h"\r
13 #include "DBusDaemonProxy.h"\r
14 #include "DBusConnection.h"\r
15 #include "DBusUtils.h"\r
16 \r
17 \r
18 namespace CommonAPI {\r
19 namespace DBus {\r
20 \r
21 \r
22 DBusServiceRegistry::DBusServiceRegistry(std::shared_ptr<DBusConnection> dbusConnection) :\r
23                 dbusConnection_(dbusConnection),\r
24                 ready(false),\r
25                 serviceStatusEvent_(std::shared_ptr<DBusServiceRegistry>(this)),\r
26                 readyPromise_(),\r
27                 readyMutex_()\r
28 {\r
29     readyFuture_ = readyPromise_.get_future();\r
30     cacheAllServices();\r
31     dbusNameOwnerChangedEventSubscription_ =\r
32                     dbusConnection_->getDBusDaemonProxy()->getNameOwnerChangedEvent().subscribe(\r
33                                     std::bind(&DBusServiceRegistry::onDBusNameOwnerChangedEvent,\r
34                                                     this,\r
35                                                     std::placeholders::_1,\r
36                                                     std::placeholders::_2,\r
37                                                     std::placeholders::_3));\r
38     std::thread(std::bind(&DBusServiceRegistry::isReadyBlocking, this)).detach();\r
39 }\r
40 \r
41 void DBusServiceRegistry::registerAvailabilityListener(const std::string& service, const std::function<void(bool)>& listener) {\r
42     availabilityCallbackList.insert({service, listener});\r
43 \r
44 }\r
45 \r
46 DBusServiceStatusEvent& DBusServiceRegistry::getServiceStatusEvent() {\r
47     return serviceStatusEvent_;\r
48 }\r
49 \r
50 DBusServiceRegistry::~DBusServiceRegistry() {\r
51     dbusConnection_->getDBusDaemonProxy()->getNameOwnerChangedEvent().unsubscribe(dbusNameOwnerChangedEventSubscription_);\r
52 }\r
53 \r
54 std::future<bool>& DBusServiceRegistry::getReadyFuture() {\r
55     return readyFuture_;\r
56 }\r
57 \r
58 bool DBusServiceRegistry::isReadyBlocking() {\r
59     if (!ready) {\r
60         readyMutex_.lock();\r
61         auto status = readyFuture_.wait_for(std::chrono::seconds(5));\r
62         if (checkReady(status)) {\r
63             ready = true;\r
64         } else {\r
65             ready = true;\r
66             readyPromise_.set_value(true);\r
67         }\r
68         readyMutex_.unlock();\r
69     }\r
70     return ready;\r
71 }\r
72 \r
73 bool DBusServiceRegistry::isReady() {\r
74         return ready;\r
75 }\r
76 \r
77 std::vector<std::string> DBusServiceRegistry::getAvailableServiceInstances(const std::string& serviceInterfaceName,\r
78                                                                            const std::string& serviceDomainName) {\r
79         if (!isReadyBlocking()) {\r
80                 return std::vector<std::string>();\r
81         }\r
82 \r
83     if (serviceDomainName != "local" || !dbusConnection_->isConnected()) {\r
84         return std::vector<std::string>();\r
85     }\r
86 \r
87     std::vector<std::string> addressesOfKnownServiceInstances;\r
88     auto knownServiceInstancesIteratorPair = dbusCachedProvidersForInterfaces_.equal_range(serviceInterfaceName);\r
89 \r
90     while(knownServiceInstancesIteratorPair.first != knownServiceInstancesIteratorPair.second) {\r
91         const DBusServiceInstanceId dbusServiceInstanceId = knownServiceInstancesIteratorPair.first->second;\r
92         addressesOfKnownServiceInstances.push_back(findInstanceIdMapping(dbusServiceInstanceId));\r
93         ++knownServiceInstancesIteratorPair.first;\r
94     }\r
95 \r
96     return addressesOfKnownServiceInstances;\r
97 }\r
98 \r
99 void DBusServiceRegistry::onManagedPathsList(const CallStatus& status, DBusObjectToInterfaceDict managedObjects,\r
100         std::list<std::string>::iterator iter, std::shared_ptr<std::list<std::string>> list) {\r
101 \r
102     auto objectPathIterator = managedObjects.begin();\r
103 \r
104     while (objectPathIterator != managedObjects.end()) {\r
105         const std::string& serviceObjPath = objectPathIterator->first;\r
106         auto interfaceNameIterator = objectPathIterator->second.begin();\r
107 \r
108         while (interfaceNameIterator != objectPathIterator->second.end()) {\r
109             const std::string& interfaceName = interfaceNameIterator->first;\r
110             dbusCachedProvidersForInterfaces_.insert( { interfaceName, { *iter, serviceObjPath } });\r
111             ++interfaceNameIterator;\r
112         }\r
113         ++objectPathIterator;\r
114     }\r
115 \r
116     list->erase(iter);\r
117 \r
118     if (list->size() == 0) {\r
119         readyMutex_.lock();\r
120         if (!ready) {\r
121             readyPromise_.set_value(true);\r
122             ready = true;\r
123         }\r
124         readyMutex_.unlock();\r
125     }\r
126 }\r
127 \r
128 bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& address) {\r
129         std::vector<std::string> parts = split(address, ':');\r
130         return isServiceInstanceAlive(parts[2], parts[1], parts[0]);\r
131 }\r
132 \r
133 \r
134 bool DBusServiceRegistry::isServiceInstanceAlive(const std::string& serviceInstanceID,\r
135                                                  const std::string& serviceInterfaceName,\r
136                                                  const std::string& serviceDomainName ) {\r
137         if (!isReadyBlocking()) {\r
138                 return false;\r
139         }\r
140 \r
141     if (serviceDomainName != "local" || !dbusConnection_->isConnected()) {\r
142         return false;\r
143     }\r
144 \r
145     DBusServiceInstanceId serviceInstanceId = findInstanceIdMapping(serviceInstanceID);\r
146 \r
147     auto knownInstancesForInterfaceIteratorPair = dbusCachedProvidersForInterfaces_.equal_range(serviceInterfaceName);\r
148 \r
149     while(knownInstancesForInterfaceIteratorPair.first != knownInstancesForInterfaceIteratorPair.second) {\r
150         DBusServiceInstanceId knownServiceId = knownInstancesForInterfaceIteratorPair.first->second;\r
151         if(knownServiceId == serviceInstanceId) {\r
152             return true;\r
153         }\r
154         ++knownInstancesForInterfaceIteratorPair.first;\r
155     }\r
156 \r
157     return false;\r
158 }\r
159 \r
160 void DBusServiceRegistry::getManagedObjects(const std::string& dbusWellKnownBusName) {\r
161     auto callMessage = DBusMessage::createMethodCall(\r
162                     dbusWellKnownBusName.c_str(),\r
163                     "/",\r
164                     "org.freedesktop.DBus.ObjectManager",\r
165                     "GetManagedObjects",\r
166                     "");\r
167     dbusConnection_->sendDBusMessageWithReplyAsync(\r
168                     callMessage,\r
169                     DBusProxyAsyncCallbackHandler<DBusObjectToInterfaceDict>::create(\r
170                                     std::bind(\r
171                                                     &DBusServiceRegistry::onManagedPaths,\r
172                                                     this,\r
173                                                     std::placeholders::_1,\r
174                                                     std::placeholders::_2,\r
175                                                     dbusWellKnownBusName)), 100);\r
176 \r
177 }\r
178 \r
179 void DBusServiceRegistry::onManagedPaths(const CallStatus& status, DBusObjectToInterfaceDict managedObjects,\r
180                 std::string dbusWellKnownBusName) {\r
181 \r
182         auto objectPathIterator = managedObjects.begin();\r
183 \r
184         while (objectPathIterator != managedObjects.end()) {\r
185                 const std::string& serviceObjPath = objectPathIterator->first;\r
186                 auto interfaceNameIterator = objectPathIterator->second.begin();\r
187 \r
188                 while (interfaceNameIterator != objectPathIterator->second.end()) {\r
189                         const std::string& interfaceName = interfaceNameIterator->first;\r
190                         dbusCachedProvidersForInterfaces_.insert( { interfaceName, { dbusWellKnownBusName, serviceObjPath } });\r
191                         updateListeners(dbusWellKnownBusName, serviceObjPath, interfaceName, true);\r
192                         ++interfaceNameIterator;\r
193                 }\r
194 \r
195                 ++objectPathIterator;\r
196         }\r
197 }\r
198 \r
199 void DBusServiceRegistry::updateListeners(const std::string& conName, const std::string& objName, const std::string& intName , bool available) {\r
200     auto found = availabilityCallbackList.equal_range(findCommonAPIAddressForDBusAddress(conName, objName, intName));\r
201     auto foundIter = found.first;\r
202     while (foundIter != found.second) {\r
203         foundIter->second(true);\r
204         foundIter++;\r
205     }\r
206 \r
207 }\r
208 \r
209 void DBusServiceRegistry::addProvidedServiceInstancesToCache(const std::string& dbusNames) {\r
210         getManagedObjects(dbusNames);\r
211 }\r
212 \r
213 void DBusServiceRegistry::addProvidedServiceInstancesToCache(std::vector<std::string>& dbusNames) {\r
214 \r
215     std::shared_ptr<std::list<std::string>> dbusList = std::make_shared<std::list<std::string>>(dbusNames.begin(), dbusNames.end());\r
216 \r
217     auto iter = dbusList->begin();\r
218 \r
219     while (iter != dbusList->end()) {\r
220 \r
221             auto callMessage = DBusMessage::createMethodCall(\r
222                             iter->c_str(),\r
223                             "/",\r
224                             "org.freedesktop.DBus.ObjectManager",\r
225                             "GetManagedObjects",\r
226                             "");\r
227             dbusConnection_->sendDBusMessageWithReplyAsync(\r
228                             callMessage,\r
229                             DBusProxyAsyncCallbackHandler<DBusObjectToInterfaceDict>::create(\r
230                                             std::bind(\r
231                                                             &DBusServiceRegistry::onManagedPathsList,\r
232                                                             this,\r
233                                                             std::placeholders::_1,\r
234                                                             std::placeholders::_2,\r
235                                                             iter,\r
236                                                             dbusList)), 10);\r
237             iter++;\r
238     }\r
239 }\r
240 \r
241 \r
242 DBusServiceInstanceId DBusServiceRegistry::findInstanceIdMapping(const std::string& instanceId) const {\r
243     DBusServiceInstanceId instanceDescriptor;\r
244     findFallbackInstanceIdMapping(instanceId, instanceDescriptor.first, instanceDescriptor.second);\r
245     return instanceDescriptor;\r
246 }\r
247 \r
248 std::string DBusServiceRegistry::findInstanceIdMapping(const DBusServiceInstanceId& dbusInstanceId) const {\r
249     return findFallbackInstanceIdMapping(dbusInstanceId.first, dbusInstanceId.second);\r
250 }\r
251 \r
252 inline const bool isServiceName(const std::string& name) {\r
253     return name[0] != ':';\r
254 }\r
255 \r
256 void DBusServiceRegistry::onDBusNameOwnerChangedEvent(const std::string& affectedName,\r
257                                                       const std::string& oldOwner,\r
258                                                       const std::string& newOwner) {\r
259     if (isServiceName(affectedName)) {\r
260         if(!oldOwner.empty()) {\r
261             removeProvidedServiceInstancesFromCache(affectedName);\r
262         }\r
263 \r
264         if (!newOwner.empty()) {\r
265             addProvidedServiceInstancesToCache(affectedName);\r
266         }\r
267     }\r
268 }\r
269 \r
270 \r
271 void DBusServiceRegistry::removeProvidedServiceInstancesFromCache(const std::string& dbusWellKnownBusName) {\r
272     auto providersForInterfacesIteratorPair = dbusCachedProvidersForInterfaces_.equal_range(dbusWellKnownBusName);\r
273 \r
274     //Iteriere über (interfaceName, (serviceInstanceId))\r
275     while(providersForInterfacesIteratorPair.first != providersForInterfacesIteratorPair.second) {\r
276 \r
277         DBusServiceInstanceId dbusInstanceId = providersForInterfacesIteratorPair.first->second;\r
278         if(dbusInstanceId.first == dbusWellKnownBusName) {\r
279             auto toErase = providersForInterfacesIteratorPair.first;\r
280             ++providersForInterfacesIteratorPair.first;\r
281             dbusCachedProvidersForInterfaces_.erase(toErase);\r
282         }\r
283 \r
284         ++providersForInterfacesIteratorPair.first;\r
285     }\r
286 }\r
287 \r
288 void DBusServiceRegistry::onListNames(const CommonAPI::CallStatus& callStatus, std::vector<std::string> existingBusConnections) {\r
289 \r
290         if (callStatus == CallStatus::SUCCESS) {\r
291                 std::vector<std::string> dbusLivingServiceBusNames;\r
292                 for (const std::string& connectionName : existingBusConnections) {\r
293                         const bool isWellKnownName = (connectionName[0] != ':');\r
294 \r
295                         if (isWellKnownName) {\r
296                                 dbusLivingServiceBusNames.push_back(connectionName);\r
297                         }\r
298                 }\r
299                 addProvidedServiceInstancesToCache(dbusLivingServiceBusNames);\r
300         }\r
301 }\r
302 \r
303 void DBusServiceRegistry::cacheAllServices() {\r
304     CommonAPI::CallStatus callStatus;\r
305     std::vector<std::string> existingBusConnections;\r
306     dbusConnection_->getDBusDaemonProxy()->listNames(callStatus, existingBusConnections);\r
307     onListNames(callStatus, existingBusConnections);\r
308 }\r
309 \r
310 \r
311 }// namespace DBus\r
312 } // namespace CommonAPI\r