2 * Copyright 2017 Samsung Electronics Co., Ltd
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 //#include "Atspi.hpp"
23 #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
27 #define EINA_TRUE static_cast< Eina_Bool >( 1 )
28 #define EINA_FALSE static_cast< Eina_Bool >( 0 )
30 //#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0)
32 std::atomic< unsigned int > DBus::detail::CallId::LastId{0};
33 static std::function< void( const char*, size_t ) > debugPrinter;
34 static std::function< void( DBus::DBusAction ) > notificationCallback;
35 static std::mutex debugLock, notificationLock;
37 DBus::detail::CallOnDestructionList& DBus::detail::CallOnDestructionList::operator=( DBus::detail::CallOnDestructionList&& d )
39 for( auto& q : functions )
43 functions = std::move( d.functions );
48 void DBus::detail::CallOnDestructionList::add( const std::function< void() >& c )
50 functions.push_back( c );
53 void DBus::setDBusActionNotifier( std::function< void( DBus::DBusAction ) > callback )
55 std::lock_guard< std::mutex > lock( notificationLock );
56 notificationCallback = std::move( callback );
59 void DBus::detail::emitNotification( const char* bus, const char* path, const char* interface, const char* member, DBus::DBusActionType type )
61 std::lock_guard< std::mutex > lock( notificationLock );
62 if( notificationCallback )
64 notificationCallback( DBusAction{type, bus, path, interface, member} );
68 void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer )
70 std::lock_guard< std::mutex > lock( debugLock );
71 debugPrinter = std::move( printer );
74 void DBus::debugPrint( const char* file, size_t line, const char* format, ... )
76 std::function< void( const char*, size_t ) > debugPrintFunc;
78 std::lock_guard< std::mutex > lock( debugLock );
81 debugPrintFunc = debugPrinter;
83 std::vector< char > buf( 4096 );
87 offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) );
90 if( static_cast< size_t >( offset ) < buf.size() )
92 buf.resize( offset + 1 );
98 va_start( args, format );
99 int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args );
103 bool done = static_cast< size_t >( z ) + static_cast< size_t >( offset ) < buf.size();
104 buf.resize( static_cast< size_t >( z ) + static_cast< size_t >( offset ) );
108 debugPrintFunc( buf.data(), buf.size() );
111 std::shared_ptr< DBus::EldbusConnection > DBus::getDBusConnectionByName( const std::string& name )
114 auto z = getDBusConnectionByType( ConnectionType::SYSTEM );
115 auto connection = eldbus_address_connection_get( name.c_str() );
116 auto ptr = std::make_shared< EldbusConnection >( connection );
121 std::shared_ptr< DBus::EldbusConnection > DBus::getDBusConnectionByType( ConnectionType connectionType )
123 Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
125 switch( connectionType )
127 case ConnectionType::SYSTEM:
129 eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
132 case ConnectionType::SESSION:
134 eldbusType = ELDBUS_CONNECTION_TYPE_SESSION;
140 auto connection = eldbus_connection_get( eldbusType );
141 auto ptr = std::make_shared< EldbusConnection >( connection );
146 DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, ConnectionType tp ) : DBusClient( std::move( busName ), std::move( pathName ), std::move( interfaceName ), getDBusConnectionByType( tp ) )
150 struct caller_eldbus_object_unref
152 void operator()( Eldbus_Object* p ) const
154 eldbus_object_unref( p );
158 DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const std::shared_ptr< DBus::EldbusConnection >& conn )
161 connectionState.connection = getDBusConnectionByType( ConnectionType::SESSION );
163 connectionState.connection = conn;
165 std::ostringstream o;
166 o << "bus = " << busName << " path = " << pathName << " connection = " << eldbus_connection_unique_name_get( connectionState.connection->get() );
169 auto c = connectionState.connection;
170 connectionState.object = {
171 eldbus_object_get( connectionState.connection->get(), busName.c_str(), pathName.c_str() ),
172 [c]( Eldbus_Object* p ) {
173 eldbus_object_unref( p );
175 if( connectionState.object )
177 auto obj = connectionState.object;
178 connectionState.proxy = {
179 eldbus_proxy_get( connectionState.object.get(), interfaceName.c_str() ),
180 [obj]( Eldbus_Proxy* p ) {
181 eldbus_proxy_unref( p );
183 if( interfaceName != DBUS_INTERFACE_PROPERTIES )
185 auto obj = connectionState.object;
186 connectionState.propertiesProxy = {
187 eldbus_proxy_get( connectionState.object.get(), DBUS_INTERFACE_PROPERTIES ),
188 [obj]( Eldbus_Proxy* p ) {
189 eldbus_proxy_unref( p );
194 connectionState.propertiesProxy = connectionState.proxy;
197 connectionInfo = std::make_shared< ConnectionInfo >();
198 connectionInfo->busName = std::move( busName );
199 connectionInfo->pathName = std::move( pathName );
200 connectionInfo->interfaceName = std::move( interfaceName );
203 DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) )
207 DBus::DBusServer::DBusServer( const std::shared_ptr< DBus::EldbusConnection >& conn )
210 connection = getDBusConnectionByType( ConnectionType::SESSION );
215 DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) )
219 struct Implementation
221 Eldbus_Service_Interface_Desc dsc;
222 std::vector< Eldbus_Method > methods;
223 std::vector< Eldbus_Signal > signals;
224 std::vector< Eldbus_Property > properties;
225 DBus::detail::StringStorage strings;
227 std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap;
228 std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap;
229 std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap;
231 std::shared_ptr< DBus::EldbusConnection > connection;
234 static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries;
235 static std::mutex globalEntriesMutex;
236 static thread_local const char* currentObjectPath = "";
237 static thread_local std::shared_ptr< DBus::EldbusConnection > currentConnection;
239 class CurrentObjectSetter
242 CurrentObjectSetter( std::shared_ptr< DBus::EldbusConnection > con, const Eldbus_Message* m )
244 currentObjectPath = eldbus_message_path_get( m );
245 currentConnection = std::move( con );
247 ~CurrentObjectSetter()
249 currentObjectPath = "";
250 currentConnection = {};
252 CurrentObjectSetter( const CurrentObjectSetter& ) = delete;
253 CurrentObjectSetter( CurrentObjectSetter&& ) = delete;
254 void operator=( const CurrentObjectSetter& ) = delete;
255 void operator=( CurrentObjectSetter&& ) = delete;
258 std::string DBus::DBusServer::getCurrentObjectPath()
260 return currentObjectPath;
263 std::shared_ptr< DBus::EldbusConnection > DBus::DBusServer::getCurrentConnection()
265 return currentConnection;
268 static Eina_Bool property_get_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
269 const Eldbus_Message* message, Eldbus_Message** error )
271 Implementation* impl = nullptr;
273 std::lock_guard< std::mutex > lock( globalEntriesMutex );
274 auto it = globalEntries.find( iface );
275 if( it != globalEntries.end() )
276 impl = it->second.get();
281 auto it = impl->propertiesMap.find( propertyName );
282 if( it == impl->propertiesMap.end() || !it->second.getCallback )
285 CurrentObjectSetter currentObjectSetter( impl->connection, message );
286 auto reply = it->second.getCallback( message, iter );
290 *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.getError().message.c_str() );
297 static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
298 const Eldbus_Message* message )
300 Implementation* impl = nullptr;
302 std::lock_guard< std::mutex > lock( globalEntriesMutex );
303 auto it = globalEntries.find( iface );
304 if( it != globalEntries.end() )
305 impl = it->second.get();
309 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
312 auto it = impl->propertiesMap.find( propertyName );
313 if( it == impl->propertiesMap.end() || !it->second.setCallback )
315 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" );
318 CurrentObjectSetter currentObjectSetter( impl->connection, message );
319 auto reply = it->second.setCallback( message, iter );
321 Eldbus_Message* ret = nullptr;
324 ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.getError().message.c_str() );
328 ret = eldbus_message_method_return_new( message );
333 static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message )
335 Implementation* impl = nullptr;
337 std::lock_guard< std::mutex > lock( globalEntriesMutex );
338 auto it = globalEntries.find( iface );
339 if( it != globalEntries.end() )
340 impl = it->second.get();
344 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
347 std::string memberName = eldbus_message_member_get( message );
348 auto it = impl->methodsMap.find( memberName );
349 if( it == impl->methodsMap.end() )
351 auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" );
354 CurrentObjectSetter currentObjectSetter( impl->connection, message );
355 auto reply = it->second.callback( message );
359 static void addInterfaceImpl( bool fallback, const std::string& pathName,
360 const std::shared_ptr< DBus::EldbusConnection >& connection,
361 const std::string& interfaceName,
362 std::unordered_map< unsigned int, std::pair< const Eldbus_Service_Interface*, unsigned int > >& signalData,
363 DBus::detail::StringStorage& strings,
364 std::vector< DBus::DBusInterfaceDescription::MethodInfo >& dscrMethods,
365 std::vector< DBus::DBusInterfaceDescription::PropertyInfo >& dscrProperties,
366 std::vector< DBus::DBusInterfaceDescription::SignalInfo >& dscrSignals,
367 DBus::detail::CallOnDestructionList& destructors )
369 std::vector< Eldbus_Method > methods;
370 std::vector< Eldbus_Signal > signals;
371 std::vector< Eldbus_Property > properties;
372 std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap;
373 std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap;
374 std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap;
376 DBUS_DEBUG( "interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName( connection ).c_str() );
377 for( auto& ee : dscrMethods )
379 auto key = ee.memberName;
380 DBUS_DEBUG( "adding method %s", ee.memberName.c_str() );
381 for( auto& r : ee.in )
385 DBUS_DEBUG( "in %s '%s'", r.name, r.signature );
387 for( auto& r : ee.out )
391 DBUS_DEBUG( "out %s '%s'", r.name, r.signature );
393 auto& e = ( methodsMap[key] = std::move( ee ) );
394 methods.push_back( {} );
395 auto& m = methods.back();
396 m.member = e.memberName.c_str();
398 m.out = e.out.data();
399 m.cb = method_callback;
402 for( auto& ee : dscrProperties )
404 auto key = ee.memberName;
405 DBUS_DEBUG( "adding property %s", ee.memberName.c_str() );
406 auto& e = ( propertiesMap[key] = std::move( ee ) );
407 properties.push_back( {} );
408 auto& m = properties.back();
409 m.name = e.memberName.c_str();
410 m.type = e.typeSignature.c_str();
411 m.get_func = e.getCallback ? property_get_callback : nullptr;
412 m.set_func = e.setCallback ? property_set_callback : nullptr;
415 unsigned int signalIndex = 0;
416 std::vector< unsigned int > signalIds;
417 for( auto& ee : dscrSignals )
419 DBUS_DEBUG( "adding signal %s", ee.memberName.c_str() );
420 auto& e = ( signalsMap[ee.id.id] = std::move( ee ) );
421 signals.push_back( {} );
422 auto& m = signals.back();
423 m.name = e.memberName.c_str();
424 m.args = e.args.data();
426 signalData[e.id.id].second = signalIndex++;
427 signalIds.push_back( e.id.id );
430 dscrProperties.clear();
433 methods.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
434 signals.push_back( {nullptr, nullptr, 0} );
435 properties.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
437 auto impl = std::unique_ptr< Implementation >( new Implementation{
438 {interfaceName.c_str(),
444 std::move( methods ),
445 std::move( signals ),
446 std::move( properties ),
447 std::move( strings ),
448 std::move( methodsMap ),
449 std::move( propertiesMap ),
450 std::move( signalsMap ),
454 std::lock_guard< std::mutex > lock( globalEntriesMutex );
455 auto v = fallback ? eldbus_service_interface_fallback_register( connection->get(), pathName.c_str(), &impl->dsc ) : eldbus_service_interface_register( connection->get(), pathName.c_str(), &impl->dsc );
457 globalEntries[v] = std::move( impl );
458 DBUS_DEBUG( "registering interface %p (%d)", v, fallback ? 1 : 0 );
459 destructors.add( [=]() {
460 eldbus_service_interface_unregister( v );
461 std::lock_guard< std::mutex > lock( globalEntriesMutex );
462 globalEntries.erase( v );
463 DBUS_DEBUG( "unregistering interface %p (%d)", v, fallback ? 1 : 0 );
465 for( auto id : signalIds )
467 signalData[id].first = v;
472 std::shared_ptr< DBus::EldbusConnection > DBus::DBusServer::getConnection()
477 void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback )
479 addInterfaceImpl( fallback, pathName, connection, dscr.interfaceName, signalData, dscr.strings, dscr.methods, dscr.properties, dscr.signals, destructors );
482 std::string DBus::DBusServer::getBusName() const
484 return getConnectionName( connection );
487 std::string DBus::getConnectionName( const std::shared_ptr< DBus::EldbusConnection >& c )
489 return eldbus_connection_unique_name_get( c->get() );