2009-08-01 19:51:07 +03:00
/* -*- Mode: C ; c-basic-offset: 2 -*- */
2008-09-07 01:48:05 +03:00
/*
2009-08-01 19:51:07 +03:00
* LADI Session Handler ( ladish )
2008-09-07 01:48:05 +03:00
*
2009-08-01 19:51:07 +03:00
* Copyright ( C ) 2008 , 2009 Nedko Arnaudov < nedko @ arnaudov . name >
* Copyright ( C ) 2008 Juuso Alasuutari < juuso . alasuutari @ gmail . com >
2008-09-07 01:48:05 +03:00
*
2009-08-01 19:51:07 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This file contains D - Bus object path helpers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2008-09-07 01:48:05 +03:00
*
2009-09-05 00:11:33 +03:00
* Licensed under the Academic Free License version 2.1
*
2009-08-01 19:51:07 +03:00
* LADI Session Handler is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
2008-09-07 01:48:05 +03:00
*
2009-08-01 19:51:07 +03:00
* LADI Session Handler is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with LADI Session Handler . If not , see < http : //www.gnu.org/licenses/>
* or write to the Free Software Foundation , Inc . ,
* 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
2008-09-07 01:48:05 +03:00
*/
2009-09-04 02:27:05 +03:00
# include "../common.h"
2009-07-12 22:56:19 +03:00
# include "object_path.h"
# include "../common/safety.h"
2009-07-13 00:15:44 +03:00
# include "introspection.h" /* g_dbus_interface_dtor_introspectable */
# include "error.h" /* lash_dbus_error() */
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
struct dbus_object_path * dbus_object_path_new ( const char * name , const interface_t * iface1_ptr , . . . )
2008-09-07 01:48:05 +03:00
{
2009-09-05 15:29:09 +03:00
struct dbus_object_path * opath_ptr ;
va_list ap ;
const interface_t * iface_src_ptr ;
struct dbus_object_path_interface * iface_dst_ptr ;
void * iface_context ;
size_t len ;
2008-09-07 01:48:05 +03:00
2009-07-13 00:15:44 +03:00
lash_debug ( " Creating object path " ) ;
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
opath_ptr = malloc ( sizeof ( struct dbus_object_path ) ) ;
if ( opath_ptr = = NULL )
2009-08-20 23:50:24 +03:00
{
2009-09-05 15:29:09 +03:00
lash_error ( " malloc() failed to allocate struct dbus_object_path. " ) ;
goto fail ;
2009-08-20 23:50:24 +03:00
}
2009-09-05 15:29:09 +03:00
opath_ptr - > name = strdup ( name ) ;
if ( opath_ptr - > name = = NULL )
{
lash_error ( " malloc() failed to allocate struct dbus_object_path. " ) ;
goto free ;
2009-07-13 00:15:44 +03:00
}
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
va_start ( ap , iface1_ptr ) ;
iface_src_ptr = iface1_ptr ;
len = 0 ;
while ( iface_src_ptr ! = NULL )
{
iface_context = va_arg ( ap , void * ) ;
iface_src_ptr = va_arg ( ap , const interface_t * ) ;
len + + ;
}
va_end ( ap ) ;
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
opath_ptr - > ifaces = malloc ( ( len + 2 ) * sizeof ( struct dbus_object_path_interface ) ) ;
if ( opath_ptr - > ifaces = = NULL )
{
lash_error ( " malloc failed to allocate interfaces array " ) ;
goto free_name ;
}
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
va_start ( ap , iface1_ptr ) ;
iface_src_ptr = iface1_ptr ;
iface_dst_ptr = opath_ptr - > ifaces ;
while ( iface_src_ptr ! = NULL )
{
iface_dst_ptr - > iface = iface_src_ptr ;
iface_dst_ptr - > iface_context = va_arg ( ap , void * ) ;
iface_src_ptr = va_arg ( ap , const interface_t * ) ;
iface_dst_ptr + + ;
len - - ;
2009-07-13 00:15:44 +03:00
}
2009-09-05 15:29:09 +03:00
va_end ( ap ) ;
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
assert ( len = = 0 ) ;
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
iface_dst_ptr - > iface = NULL ;
opath_ptr - > introspection = introspection_new ( opath_ptr ) ;
if ( opath_ptr - > introspection = = NULL )
2009-07-13 00:15:44 +03:00
{
2009-09-05 15:29:09 +03:00
lash_error ( " introspection_new() failed. " ) ;
goto free_ifaces ;
}
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
iface_dst_ptr - > iface = & g_dbus_interface_dtor_introspectable ;
iface_dst_ptr - > iface_context = opath_ptr - > introspection ;
iface_dst_ptr + + ;
iface_dst_ptr - > iface = NULL ;
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
return opath_ptr ;
free_ifaces :
free ( opath_ptr - > ifaces ) ;
free_name :
free ( opath_ptr - > name ) ;
free :
free ( opath_ptr ) ;
fail :
return NULL ;
2008-09-07 01:48:05 +03:00
}
2009-09-05 15:29:09 +03:00
void dbus_object_path_destroy ( DBusConnection * connection_ptr , struct dbus_object_path * opath_ptr )
2008-09-07 01:48:05 +03:00
{
2009-07-13 00:15:44 +03:00
lash_debug ( " Destroying object path " ) ;
2009-09-05 15:29:09 +03:00
if ( connection_ptr ! = NULL & & ! dbus_connection_unregister_object_path ( connection_ptr , opath_ptr - > name ) )
2009-08-01 19:07:16 +03:00
{
2009-09-05 15:29:09 +03:00
lash_error ( " dbus_connection_unregister_object_path() failed. " ) ;
2009-08-01 19:07:16 +03:00
}
2009-09-05 15:29:09 +03:00
introspection_destroy ( opath_ptr ) ;
free ( opath_ptr - > ifaces ) ;
free ( opath_ptr - > name ) ;
free ( opath_ptr ) ;
2008-09-07 01:48:05 +03:00
}
2009-09-05 15:29:09 +03:00
# define opath_ptr ((struct dbus_object_path *)data)
2008-09-07 01:48:05 +03:00
2009-09-05 15:29:09 +03:00
static DBusHandlerResult dbus_object_path_handler ( DBusConnection * connection , DBusMessage * message , void * data )
2008-09-07 01:48:05 +03:00
{
2009-09-05 15:29:09 +03:00
const char * iface_name ;
const struct dbus_object_path_interface * iface_ptr ;
2009-07-13 00:15:44 +03:00
method_call_t call ;
/* Check if the message is a method call. If not, ignore it. */
2009-09-05 15:29:09 +03:00
if ( dbus_message_get_type ( message ) ! = DBUS_MESSAGE_TYPE_METHOD_CALL )
{
2009-07-13 00:15:44 +03:00
goto handled ;
}
/* Get the invoked method's name and make sure it's non-NULL. */
2009-09-05 15:29:09 +03:00
call . method_name = dbus_message_get_member ( message ) ;
if ( call . method_name = = NULL )
{
lash_dbus_error ( & call , LASH_DBUS_ERROR_UNKNOWN_METHOD , " Received method call with empty method name " ) ;
2009-07-13 00:15:44 +03:00
goto send_return ;
}
/* Initialize our data. */
call . connection = connection ;
call . message = message ;
call . interface = NULL ; /* To be set by the default interface handler */
call . reply = NULL ;
/* Check if there's an interface specified for this method call. */
2009-09-05 15:29:09 +03:00
iface_name = dbus_message_get_interface ( message ) ;
if ( iface_name ! = NULL )
2009-08-21 23:13:19 +03:00
{
2009-09-05 15:29:09 +03:00
for ( iface_ptr = opath_ptr - > ifaces ; iface_ptr - > iface ! = NULL ; iface_ptr + + )
2009-08-21 23:13:19 +03:00
{
2009-09-05 15:29:09 +03:00
if ( strcmp ( iface_name , iface_ptr - > iface - > name ) = = 0 )
2009-08-21 23:13:19 +03:00
{
2009-09-05 15:29:09 +03:00
call . context = iface_ptr - > iface_context ;
if ( ! iface_ptr - > iface - > handler ( iface_ptr - > iface , & call ) )
2009-08-21 23:13:19 +03:00
{
2009-09-05 15:29:09 +03:00
/* unknown method */
break ;
2009-07-13 00:15:44 +03:00
}
2009-09-05 15:29:09 +03:00
goto send_return ;
2009-07-13 00:15:44 +03:00
}
}
}
else
{
2009-09-05 15:29:09 +03:00
/* No interface was specified so we have to try them all. D-Bus spec states:
*
* Optionally , the message has an INTERFACE field giving the interface the method is a part of .
* In the absence of an INTERFACE field , if two interfaces on the same object have a method with
* the same name , it is undefined which of the two methods will be invoked .
* Implementations may also choose to return an error in this ambiguous case .
* However , if a method name is unique implementations must not require an interface field .
*/
for ( iface_ptr = opath_ptr - > ifaces ; iface_ptr - > iface ! = NULL ; iface_ptr + + )
{
call . context = iface_ptr - > iface_context ;
if ( ! iface_ptr - > iface - > handler ( iface_ptr - > iface , & call ) )
{
/* known method */
2009-07-13 00:15:44 +03:00
goto send_return ;
}
}
}
2009-09-05 15:29:09 +03:00
lash_dbus_error ( & call , LASH_DBUS_ERROR_UNKNOWN_METHOD , " Method \" %s \" with signature \" %s \" on interface \" %s \" doesn't exist " , call . method_name , dbus_message_get_signature ( message ) , iface_name ) ;
2008-09-07 01:48:05 +03:00
send_return :
2009-07-13 00:15:44 +03:00
method_return_send ( & call ) ;
2008-09-07 01:48:05 +03:00
handled :
2009-07-13 00:15:44 +03:00
return DBUS_HANDLER_RESULT_HANDLED ;
2008-09-07 01:48:05 +03:00
}
2009-09-05 15:29:09 +03:00
static void dbus_object_path_handler_unregister ( DBusConnection * connection_ptr , void * data )
2008-09-07 01:48:05 +03:00
{
# ifdef LASH_DEBUG
2009-09-05 15:29:09 +03:00
lash_debug ( " Message handler of object path %s was unregistered " , ( opath_ptr & & path - > name ) ? opath_ptr - > name : " <unknown> " ) ;
2008-09-07 01:48:05 +03:00
# endif /* LASH_DEBUG */
}
2009-09-05 15:29:09 +03:00
# undef opath_ptr
bool dbus_object_path_register ( DBusConnection * connection_ptr , struct dbus_object_path * opath_ptr )
{
lash_debug ( " Registering object path " ) ;
DBusObjectPathVTable vtable =
{
dbus_object_path_handler_unregister ,
dbus_object_path_handler ,
NULL , NULL , NULL , NULL
} ;
dbus_connection_register_object_path ( connection_ptr , opath_ptr - > name , & vtable , opath_ptr ) ;
return true ;
}