Reorganise to remove redundant folder
[profile/ivi/common-api-dbus-runtime.git] / src / CommonAPI / DBus / DBusConnection.cpp
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include "DBusConnection.h"
5 #include "DBusInputStream.h"
6
7 #include <sstream>
8 #include <cassert>
9 #include <future>
10
11 #include <iostream>
12
13 namespace CommonAPI {
14 namespace DBus {
15
16
17 DBusObjectPathVTable DBusConnection::libdbusObjectPathVTable_ = {
18                 NULL, // no need to handle unregister callbacks
19                 &DBusConnection::onLibdbusObjectPathMessageThunk
20 };
21
22 void DBusConnection::dispatch() {
23     while (!stopDispatching_ && readWriteDispatch(10)) {
24     }
25 }
26
27 DBusConnection::DBusConnection(BusType busType) :
28                 busType_(busType),
29                 libdbusConnection_(NULL),
30                 isLibdbusSignalFilterAdded_(false),
31                 stopDispatching_(false) {
32     dbus_threads_init_default();
33 }
34
35 DBusConnection::DBusConnection(::DBusConnection* libDbusConnection) :
36                 busType_(WRAPPED),
37                 libdbusConnection_(libDbusConnection),
38                 isLibdbusSignalFilterAdded_(false),
39                 stopDispatching_(false)  {
40     dbus_threads_init_default();
41 }
42
43 DBusConnection::~DBusConnection() {
44     if (isConnected()) {
45         disconnect();
46     }
47     dispatchThread_.join();
48 }
49
50 bool DBusConnection::connect() {
51     DBusError dbusError;
52     return connect(dbusError);
53 }
54
55 bool DBusConnection::connect(DBusError& dbusError) {
56     assert(!dbusError);
57
58     if (isConnected())
59         return true;
60
61     const ::DBusBusType libdbusType = static_cast<DBusBusType>(busType_);
62
63     libdbusConnection_ = dbus_bus_get_private(libdbusType, &dbusError.libdbusError_);
64     if (dbusError)
65         return false;
66
67     assert(libdbusConnection_);
68     dbus_connection_set_exit_on_disconnect(libdbusConnection_, false);
69
70     dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::AVAILABLE);
71
72     initLibdbusObjectPathHandlerAfterConnect();
73
74     initLibdbusSignalFilterAfterConnect();
75
76     dispatchThread_ = std::thread(std::bind(&DBusConnection::dispatch, this));
77
78     return true;
79 }
80
81 void DBusConnection::disconnect() {
82     if (isConnected()) {
83         stopDispatching_ = true;
84         if (!dbusSignalMatchRulesMap_.empty()) {
85             dbus_connection_remove_filter(libdbusConnection_, &onLibdbusSignalFilterThunk, this);
86         }
87
88         dbus_connection_close(libdbusConnection_);
89         dbus_connection_unref(libdbusConnection_);
90         libdbusConnection_ = NULL;
91
92         dbusConnectionStatusEvent_.notifyListeners(AvailabilityStatus::NOT_AVAILABLE);
93     }
94 }
95
96 bool DBusConnection::isConnected() const {
97     return (libdbusConnection_ != NULL);
98 }
99
100 DBusConnectionStatusEvent& DBusConnection::getConnectionStatusEvent() {
101     return dbusConnectionStatusEvent_;
102 }
103
104 const std::shared_ptr<DBusServiceRegistry>& DBusConnection::getDBusServiceRegistry() {
105     if (!dbusServiceRegistry_) {
106         dbusServiceRegistry_ = std::make_shared<DBusServiceRegistry>(this->shared_from_this());
107     }
108
109     return dbusServiceRegistry_;
110 }
111
112 const std::shared_ptr<DBusDaemonProxy>& DBusConnection::getDBusDaemonProxy() {
113     if (!dbusDaemonProxy_) {
114         dbusDaemonProxy_ = std::make_shared<DBusDaemonProxy>(this->shared_from_this());
115     }
116
117     return dbusDaemonProxy_;
118 }
119
120 const std::shared_ptr<DBusObjectManager>& DBusConnection::getDBusObjectManager() {
121     if (!dbusObjectManager_) {
122         dbusObjectManager_ = std::make_shared<DBusObjectManager>(this->shared_from_this());
123     }
124
125     return dbusObjectManager_;
126 }
127
128 bool DBusConnection::requestServiceNameAndBlock(const std::string& serviceName) const {
129     DBusError dbusError;
130     const int libdbusStatus = dbus_bus_request_name(libdbusConnection_,
131                                                     serviceName.c_str(),
132                                                     DBUS_NAME_FLAG_DO_NOT_QUEUE,
133                                                     &dbusError.libdbusError_);
134     const bool isServiceNameAcquired = (libdbusStatus == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
135
136     return isServiceNameAcquired;
137 }
138
139 bool DBusConnection::releaseServiceName(const std::string& serviceName) const {
140     DBusError dbusError;
141     const int libdbusStatus = dbus_bus_release_name(libdbusConnection_,
142                                                     serviceName.c_str(),
143                                                     &dbusError.libdbusError_);
144     const bool isServiceNameReleased = (libdbusStatus == DBUS_RELEASE_NAME_REPLY_RELEASED);
145
146     return isServiceNameReleased;
147 }
148
149 bool DBusConnection::sendDBusMessage(const DBusMessage& dbusMessage, uint32_t* allocatedSerial) const {
150     assert(dbusMessage);
151     assert(isConnected());
152
153     dbus_uint32_t* libdbusSerial = static_cast<dbus_uint32_t*>(allocatedSerial);
154     const bool result = dbus_connection_send(libdbusConnection_, dbusMessage.libdbusMessage_, libdbusSerial);
155
156     return result;
157 }
158
159 void DBusConnection::onLibdbusPendingCallNotifyThunk(::DBusPendingCall* libdbusPendingCall, void *userData) {
160         assert(userData);
161         assert(libdbusPendingCall);
162
163         auto dbusMessageReplyAsyncHandler = reinterpret_cast<DBusMessageReplyAsyncHandler*>(userData);
164
165         ::DBusMessage* libdbusMessage = dbus_pending_call_steal_reply(
166                         libdbusPendingCall);
167         const bool increaseLibdbusMessageReferenceCount = false;
168         DBusMessage dbusMessage(libdbusMessage, increaseLibdbusMessageReferenceCount);
169
170         dbusMessageReplyAsyncHandler->onDBusMessageReply(CallStatus::SUCCESS, dbusMessage);
171
172         // libdbus calls the Cleanup method below
173         dbus_pending_call_unref(libdbusPendingCall);
174 }
175
176 void DBusConnection::onLibdbusDataCleanup(void* userData) {
177         auto dbusMessageReplyAsyncHandler = reinterpret_cast<DBusMessageReplyAsyncHandler*>(userData);
178         delete dbusMessageReplyAsyncHandler;
179 }
180
181 std::future<CallStatus> DBusConnection::sendDBusMessageWithReplyAsync(
182                 const DBusMessage& dbusMessage,
183                 std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler,
184                 int timeoutMilliseconds) const {
185
186     assert(dbusMessage);
187     assert(isConnected());
188
189     DBusPendingCall* libdbusPendingCall;
190     dbus_bool_t libdbusSuccess;
191
192     libdbusSuccess = dbus_connection_send_with_reply(
193                     libdbusConnection_,
194                     dbusMessage.libdbusMessage_,
195                     &libdbusPendingCall,
196                     timeoutMilliseconds);
197
198     if (!libdbusSuccess || !libdbusPendingCall) {
199         dbusMessageReplyAsyncHandler->onDBusMessageReply(CallStatus::CONNECTION_FAILED, dbusMessage);
200         return dbusMessageReplyAsyncHandler->getFuture();
201     }
202
203     libdbusSuccess = dbus_pending_call_set_notify(
204                     libdbusPendingCall,
205                     onLibdbusPendingCallNotifyThunk,
206                     dbusMessageReplyAsyncHandler.get(),
207                     onLibdbusDataCleanup);
208
209     if (!libdbusSuccess) {
210         dbusMessageReplyAsyncHandler->onDBusMessageReply(CallStatus::OUT_OF_MEMORY, dbusMessage);
211         dbus_pending_call_unref(libdbusPendingCall);
212         return dbusMessageReplyAsyncHandler->getFuture();
213     }
214
215     return dbusMessageReplyAsyncHandler.release()->getFuture();
216 }
217
218
219 DBusMessage DBusConnection::sendDBusMessageWithReplyAndBlock(const DBusMessage& dbusMessage,
220                                                              DBusError& dbusError,
221                                                              int timeoutMilliseconds) const {
222     assert(dbusMessage);
223     assert(!dbusError);
224     assert(isConnected());
225
226     ::DBusMessage* libdbusMessageReply = dbus_connection_send_with_reply_and_block(libdbusConnection_,
227                                                                                    dbusMessage.libdbusMessage_,
228                                                                                    timeoutMilliseconds,
229                                                                                    &dbusError.libdbusError_);
230     if (dbusError)
231         return DBusMessage();
232
233     const bool increaseLibdbusMessageReferenceCount = false;
234     return DBusMessage(libdbusMessageReply, increaseLibdbusMessageReferenceCount);
235 }
236
237
238 bool DBusConnection::readWriteDispatch(int timeoutMilliseconds) {
239     if(isConnected()) {
240         const dbus_bool_t libdbusSuccess = dbus_connection_read_write_dispatch(libdbusConnection_,
241                                                                                timeoutMilliseconds);
242         return libdbusSuccess;
243     }
244     return false;
245 }
246
247 DBusProxyConnection::DBusSignalHandlerToken DBusConnection::addSignalMemberHandler(const std::string& objectPath,
248                                                                                    const std::string& interfaceName,
249                                                                                    const std::string& interfaceMemberName,
250                                                                                    const std::string& interfaceMemberSignature,
251                                                                                    DBusSignalHandler* dbusSignalHandler) {
252     DBusSignalHandlerPath dbusSignalHandlerPath(
253                     objectPath,
254                     interfaceName,
255                     interfaceMemberName,
256                     interfaceMemberSignature);
257     const bool isFirstSignalMemberHandler = dbusSignalHandlerTable_.find(dbusSignalHandlerPath) == dbusSignalHandlerTable_.end();
258
259     dbusSignalHandlerTable_.insert(DBusSignalHandlerTable::value_type(dbusSignalHandlerPath, dbusSignalHandler));
260
261     if (isFirstSignalMemberHandler)
262         addLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName);
263
264     return dbusSignalHandlerPath;
265 }
266
267 void DBusConnection::removeSignalMemberHandler(const DBusSignalHandlerToken& dbusSignalHandlerToken) {
268     auto equalRangeIteratorPair = dbusSignalHandlerTable_.equal_range(dbusSignalHandlerToken);
269
270     // the range can't be empty!
271     assert(equalRangeIteratorPair.first != equalRangeIteratorPair.second);
272
273     // advance to the next element
274     equalRangeIteratorPair.first++;
275
276     // check if the first element was the only element
277     const bool isLastSignalMemberHandler = equalRangeIteratorPair.first == equalRangeIteratorPair.second;
278
279     if (isLastSignalMemberHandler) {
280         const std::string& objectPath = std::get<0>(dbusSignalHandlerToken);
281         const std::string& interfaceName = std::get<1>(dbusSignalHandlerToken);
282         const std::string& interfaceMemberName = std::get<2>(dbusSignalHandlerToken);
283
284         removeLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName);
285     }
286
287     dbusSignalHandlerTable_.erase(dbusSignalHandlerToken);
288 }
289
290 void DBusConnection::registerObjectPath(const std::string& objectPath) {
291     assert(!objectPath.empty());
292     assert(objectPath[0] == '/');
293
294     auto handlerIterator = libdbusRegisteredObjectPaths_.find(objectPath);
295     const bool foundRegisteredObjectPathHandler = handlerIterator != libdbusRegisteredObjectPaths_.end();
296
297     if (foundRegisteredObjectPathHandler) {
298         uint32_t& referenceCount = handlerIterator->second;
299
300         referenceCount++;
301
302         return;
303     }
304
305     libdbusRegisteredObjectPaths_.insert(LibdbusRegisteredObjectPathHandlersTable::value_type(objectPath, 1));
306
307     if (isConnected()) {
308         DBusError dbusError;
309         const dbus_bool_t libdbusSuccess = dbus_connection_try_register_object_path(libdbusConnection_,
310                                                                                     objectPath.c_str(),
311                                                                                     &libdbusObjectPathVTable_,
312                                                                                     this,
313                                                                                     &dbusError.libdbusError_);
314         assert(libdbusSuccess);
315         assert(!dbusError);
316     }
317 }
318
319 void DBusConnection::unregisterObjectPath(const std::string& objectPath) {
320     assert(!objectPath.empty());
321     assert(objectPath[0] == '/');
322
323     auto handlerIterator = libdbusRegisteredObjectPaths_.find(objectPath);
324     const bool foundRegisteredObjectPathHandler = handlerIterator != libdbusRegisteredObjectPaths_.end();
325
326     assert(foundRegisteredObjectPathHandler);
327
328     uint32_t& referenceCount = handlerIterator->second;
329     if (referenceCount > 1) {
330         referenceCount--;
331         return;
332     }
333
334     libdbusRegisteredObjectPaths_.erase(handlerIterator);
335
336     if (isConnected()) {
337         dbus_bool_t libdbusSuccess = dbus_connection_unregister_object_path(libdbusConnection_,
338                                                                             objectPath.c_str());
339         assert(libdbusSuccess);
340     }
341 }
342
343 void DBusConnection::addLibdbusSignalMatchRule(const std::string& objectPath,
344                                                const std::string& interfaceName,
345                                                const std::string& interfaceMemberName) {
346     DBusSignalMatchRuleTuple dbusSignalMatchRuleTuple(objectPath, interfaceName, interfaceMemberName);
347     auto matchRuleIterator = dbusSignalMatchRulesMap_.find(dbusSignalMatchRuleTuple);
348     const bool matchRuleFound = matchRuleIterator != dbusSignalMatchRulesMap_.end();
349
350     if (matchRuleFound) {
351         uint32_t& matchRuleReferenceCount = matchRuleIterator->second.first;
352         matchRuleReferenceCount++;
353         return;
354     }
355
356     const bool isFirstMatchRule = dbusSignalMatchRulesMap_.empty();
357
358     // generate D-Bus match rule string
359     std::ostringstream matchRuleStringStream;
360
361     matchRuleStringStream << "type='signal'";
362     matchRuleStringStream << ",path='" << objectPath << "'";
363     matchRuleStringStream << ",interface='" << interfaceName << "'";
364     matchRuleStringStream << ",member='" << interfaceMemberName << "'";
365
366     // add the match rule string to the map with reference count set to 1
367     std::string matchRuleString = matchRuleStringStream.str();
368     auto success = dbusSignalMatchRulesMap_.insert(
369                     DBusSignalMatchRulesMap::value_type(dbusSignalMatchRuleTuple,
370                                                         DBusSignalMatchRuleMapping(1, matchRuleString)));
371     assert(success.second);
372
373     // if not connected the filter and the rules will be added as soon as the connection is established
374     if (isConnected()) {
375         // add the libdbus message signal filter
376         if (isFirstMatchRule) {
377             const dbus_bool_t libdbusSuccess = dbus_connection_add_filter(libdbusConnection_,
378                                                                           &onLibdbusSignalFilterThunk,
379                                                                           this,
380                                                                           NULL);
381             assert(libdbusSuccess);
382         }
383
384         // finally add the match rule
385         DBusError dbusError;
386         dbus_bus_add_match(libdbusConnection_, matchRuleString.c_str(), &dbusError.libdbusError_);
387         assert(!dbusError);
388     }
389 }
390
391 void DBusConnection::removeLibdbusSignalMatchRule(const std::string& objectPath,
392                                                   const std::string& interfaceName,
393                                                   const std::string& interfaceMemberName) {
394     DBusSignalMatchRuleTuple dbusSignalMatchRuleTuple(objectPath, interfaceName, interfaceMemberName);
395     auto matchRuleIterator = dbusSignalMatchRulesMap_.find(dbusSignalMatchRuleTuple);
396     const bool matchRuleFound = matchRuleIterator != dbusSignalMatchRulesMap_.end();
397
398     assert(matchRuleFound);
399
400     uint32_t& matchRuleReferenceCount = matchRuleIterator->second.first;
401     if (matchRuleReferenceCount > 1) {
402         matchRuleReferenceCount--;
403         return;
404     }
405
406     const std::string& matchRuleString = matchRuleIterator->second.second;
407     DBusError dbusError;
408     dbus_bus_remove_match(libdbusConnection_, matchRuleString.c_str(), &dbusError.libdbusError_);
409     assert(!dbusError);
410
411     dbusSignalMatchRulesMap_.erase(matchRuleIterator);
412
413     const bool isLastMatchRule = dbusSignalMatchRulesMap_.empty();
414     if (isLastMatchRule)
415         dbus_connection_remove_filter(libdbusConnection_, &onLibdbusSignalFilterThunk, this);
416 }
417
418 void DBusConnection::initLibdbusObjectPathHandlerAfterConnect() {
419     assert(isConnected());
420
421     // nothing to do if there aren't any registered object path handlers
422     if (libdbusRegisteredObjectPaths_.empty())
423         return;
424
425     DBusError dbusError;
426     dbus_bool_t libdbusSuccess;
427
428     for (    auto handlerIterator = libdbusRegisteredObjectPaths_.begin();
429              handlerIterator != libdbusRegisteredObjectPaths_.end();
430              handlerIterator++) {
431         const std::string& objectPath = handlerIterator->first;
432
433         dbusError.clear();
434
435         libdbusSuccess = dbus_connection_try_register_object_path(libdbusConnection_,
436                                                                   objectPath.c_str(),
437                                                                   &libdbusObjectPathVTable_,
438                                                                   this,
439                                                                   &dbusError.libdbusError_);
440         assert(libdbusSuccess);
441         assert(!dbusError);
442     }
443 }
444
445 void DBusConnection::initLibdbusSignalFilterAfterConnect() {
446     assert(isConnected());
447
448     // nothing to do if there aren't any signal match rules
449     if (dbusSignalMatchRulesMap_.empty())
450         return;
451
452     // first we add the libdbus message signal filter
453     const dbus_bool_t libdbusSuccess = dbus_connection_add_filter(libdbusConnection_,
454                                                                   &onLibdbusSignalFilterThunk,
455                                                                   this,
456                                                                   NULL);
457     assert(libdbusSuccess);
458
459     // then we upload all match rules to the dbus-daemon
460     DBusError dbusError;
461     for (auto iterator = dbusSignalMatchRulesMap_.begin(); iterator != dbusSignalMatchRulesMap_.end(); iterator++) {
462         const std::string& matchRuleString = iterator->second.second;
463
464         dbusError.clear();
465         dbus_bus_add_match(libdbusConnection_, matchRuleString.c_str(), &dbusError.libdbusError_);
466         assert(!dbusError);
467     }
468 }
469
470 ::DBusHandlerResult DBusConnection::onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage) const {
471     assert(libdbusMessage);
472
473     // handle only method call messages
474     if (dbus_message_get_type(libdbusMessage) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
475         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
476     }
477
478     bool isDBusMessageHandled = dbusObjectManager_->handleMessage(DBusMessage(libdbusMessage));
479     return isDBusMessageHandled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
480 }
481
482 ::DBusHandlerResult DBusConnection::onLibdbusSignalFilter(::DBusMessage* libdbusMessage) {
483     assert(libdbusMessage);
484
485     // handle only signal messages
486     if (dbus_message_get_type(libdbusMessage) != DBUS_MESSAGE_TYPE_SIGNAL)
487         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
488
489     const char* objectPath = dbus_message_get_path(libdbusMessage);
490     const char* interfaceName = dbus_message_get_interface(libdbusMessage);
491     const char* interfaceMemberName = dbus_message_get_member(libdbusMessage);
492     const char* interfaceMemberSignature = dbus_message_get_signature(libdbusMessage);
493
494     assert(objectPath);
495     assert(interfaceName);
496     assert(interfaceMemberName);
497     assert(interfaceMemberSignature);
498
499     DBusSignalHandlerPath dbusSignalHandlerPath(objectPath, interfaceName, interfaceMemberName, interfaceMemberSignature);
500     auto equalRangeIteratorPair = dbusSignalHandlerTable_.equal_range(dbusSignalHandlerPath);
501
502     if (equalRangeIteratorPair.first != equalRangeIteratorPair.second) {
503         DBusMessage dbusMessage(libdbusMessage);
504
505         while (equalRangeIteratorPair.first != equalRangeIteratorPair.second) {
506             DBusSignalHandler* dbusSignalHandler = equalRangeIteratorPair.first->second;
507             const SubscriptionStatus dbusSignalHandlerSubscriptionStatus = dbusSignalHandler->onSignalDBusMessage(dbusMessage);
508
509             if (dbusSignalHandlerSubscriptionStatus == SubscriptionStatus::CANCEL) {
510                 auto dbusSignalHandlerSubscription = equalRangeIteratorPair.first;
511                 equalRangeIteratorPair.first++;
512                 dbusSignalHandlerTable_.erase(dbusSignalHandlerSubscription);
513             } else
514                 equalRangeIteratorPair.first++;
515         }
516
517         return DBUS_HANDLER_RESULT_HANDLED;
518     }
519
520     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
521 }
522
523 ::DBusHandlerResult DBusConnection::onLibdbusSignalFilterThunk(::DBusConnection* libdbusConnection,
524                                                                ::DBusMessage* libdbusMessage,
525                                                                void* userData) {
526     assert(libdbusConnection);
527     assert(libdbusMessage);
528     assert(userData);
529
530     DBusConnection* dbusConnection = reinterpret_cast<DBusConnection*>(userData);
531
532     assert(dbusConnection->libdbusConnection_ == libdbusConnection);
533
534     return dbusConnection->onLibdbusSignalFilter(libdbusMessage);
535 }
536
537 ::DBusHandlerResult DBusConnection::onLibdbusObjectPathMessageThunk(::DBusConnection* libdbusConnection,
538                                                                     ::DBusMessage* libdbusMessage,
539                                                                     void* userData) {
540     assert(libdbusConnection);
541     assert(libdbusMessage);
542     assert(userData);
543
544     const DBusConnection* dbusConnection = reinterpret_cast<DBusConnection*>(userData);
545
546     assert(dbusConnection->libdbusConnection_ == libdbusConnection);
547
548     return dbusConnection->onLibdbusObjectPathMessage(libdbusMessage);
549 }
550
551 } // namespace DBus
552 } // namespace CommonAPI
553