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