2006-08-06 16:16:50 +00:00
/***
This file is part of PulseAudio .
2007-01-04 13:43:45 +00:00
2007-02-13 15:35:19 +00:00
Copyright 2006 Lennart Poettering
Copyright 2006 Shams E . King
2006-08-06 16:16:50 +00:00
PulseAudio is free software ; you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License as published
2009-03-03 20:23:02 +00:00
by the Free Software Foundation ; either version 2.1 of the License ,
2006-08-06 16:16:50 +00:00
or ( at your option ) any later version .
2007-01-04 13:43:45 +00:00
2006-08-06 16:16:50 +00:00
PulseAudio 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 .
2007-01-04 13:43:45 +00:00
2006-08-06 16:16:50 +00:00
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
USA .
* * */
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2009-01-29 03:30:50 +01:00
# include <stdarg.h>
2009-04-05 02:13:43 +03:00
# include <pulse/rtclock.h>
2006-08-07 20:29:31 +00:00
# include <pulse/timeval.h>
2009-07-21 00:02:27 +03:00
# include <pulse/utf8.h>
2009-04-05 02:13:43 +03:00
# include <pulse/xmalloc.h>
2009-04-06 04:20:12 +02:00
2009-04-05 02:13:43 +03:00
# include <pulsecore/core-rtclock.h>
2009-04-06 04:20:12 +02:00
# include <pulsecore/core-util.h>
2007-10-28 19:13:50 +00:00
# include <pulsecore/log.h>
2006-08-06 16:16:50 +00:00
# include "dbus-util.h"
2009-03-19 01:35:02 +02:00
struct pa_dbus_wrap_connection {
pa_mainloop_api * mainloop ;
2006-08-06 16:16:50 +00:00
DBusConnection * connection ;
pa_defer_event * dispatch_event ;
2009-04-05 02:13:43 +03:00
pa_bool_t use_rtclock : 1 ;
} ;
struct timeout_data {
pa_dbus_wrap_connection * c ;
DBusTimeout * timeout ;
2006-08-06 16:16:50 +00:00
} ;
2007-10-28 19:13:50 +00:00
static void dispatch_cb ( pa_mainloop_api * ea , pa_defer_event * ev , void * userdata ) {
DBusConnection * conn = userdata ;
2006-08-06 16:16:50 +00:00
if ( dbus_connection_dispatch ( conn ) = = DBUS_DISPATCH_COMPLETE ) {
/* no more data to process, disable the deferred */
ea - > defer_enable ( ev , 0 ) ;
}
}
/* DBusDispatchStatusFunction callback for the pa mainloop */
2007-10-28 19:13:50 +00:00
static void dispatch_status ( DBusConnection * conn , DBusDispatchStatus status , void * userdata ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = userdata ;
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
2006-08-06 16:16:50 +00:00
switch ( status ) {
2007-10-28 19:13:50 +00:00
2006-08-06 16:16:50 +00:00
case DBUS_DISPATCH_COMPLETE :
2009-03-19 01:35:02 +02:00
c - > mainloop - > defer_enable ( c - > dispatch_event , 0 ) ;
2006-08-06 16:16:50 +00:00
break ;
2007-10-28 19:13:50 +00:00
2006-08-06 16:16:50 +00:00
case DBUS_DISPATCH_DATA_REMAINS :
case DBUS_DISPATCH_NEED_MEMORY :
default :
2009-03-19 01:35:02 +02:00
c - > mainloop - > defer_enable ( c - > dispatch_event , 1 ) ;
2006-08-06 16:16:50 +00:00
break ;
}
}
2007-10-28 19:13:50 +00:00
static pa_io_event_flags_t get_watch_flags ( DBusWatch * watch ) {
unsigned int flags ;
pa_io_event_flags_t events = 0 ;
pa_assert ( watch ) ;
flags = dbus_watch_get_flags ( watch ) ;
2006-08-06 16:16:50 +00:00
/* no watch flags for disabled watches */
if ( ! dbus_watch_get_enabled ( watch ) )
return PA_IO_EVENT_NULL ;
if ( flags & DBUS_WATCH_READABLE )
events | = PA_IO_EVENT_INPUT ;
if ( flags & DBUS_WATCH_WRITABLE )
events | = PA_IO_EVENT_OUTPUT ;
2007-10-28 19:13:50 +00:00
return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR ;
2006-08-06 16:16:50 +00:00
}
/* pa_io_event_cb_t IO event handler */
2008-08-09 16:20:29 +02:00
static void handle_io_event ( pa_mainloop_api * ea , pa_io_event * e , int fd , pa_io_event_flags_t events , void * userdata ) {
2006-08-06 16:16:50 +00:00
unsigned int flags = 0 ;
2007-10-28 19:13:50 +00:00
DBusWatch * watch = userdata ;
2006-08-06 16:16:50 +00:00
2007-10-28 19:13:50 +00:00
# if HAVE_DBUS_WATCH_GET_UNIX_FD
pa_assert ( fd = = dbus_watch_get_unix_fd ( watch ) ) ;
# else
pa_assert ( fd = = dbus_watch_get_fd ( watch ) ) ;
# endif
2006-08-06 16:16:50 +00:00
if ( ! dbus_watch_get_enabled ( watch ) ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Asked to handle disabled watch: %p %i " , ( void * ) watch , fd ) ;
2006-08-06 16:16:50 +00:00
return ;
}
if ( events & PA_IO_EVENT_INPUT )
flags | = DBUS_WATCH_READABLE ;
if ( events & PA_IO_EVENT_OUTPUT )
flags | = DBUS_WATCH_WRITABLE ;
if ( events & PA_IO_EVENT_HANGUP )
flags | = DBUS_WATCH_HANGUP ;
if ( events & PA_IO_EVENT_ERROR )
flags | = DBUS_WATCH_ERROR ;
dbus_watch_handle ( watch , flags ) ;
}
/* pa_time_event_cb_t timer event handler */
2009-04-05 02:13:43 +03:00
static void handle_time_event ( pa_mainloop_api * ea , pa_time_event * e , const struct timeval * t , void * userdata ) {
struct timeval tv ;
struct timeout_data * d = userdata ;
2006-08-06 16:16:50 +00:00
2009-04-05 02:13:43 +03:00
pa_assert ( d ) ;
pa_assert ( d - > c ) ;
if ( dbus_timeout_get_enabled ( d - > timeout ) ) {
dbus_timeout_handle ( d - > timeout ) ;
2006-08-06 16:16:50 +00:00
/* restart it for the next scheduled time */
2009-04-05 02:13:43 +03:00
ea - > time_restart ( e , pa_timeval_rtstore ( & tv , pa_timeval_load ( t ) + dbus_timeout_get_interval ( d - > timeout ) * PA_USEC_PER_MSEC , d - > c - > use_rtclock ) ) ;
2006-08-06 16:16:50 +00:00
}
}
/* DBusAddWatchFunction callback for pa mainloop */
2007-10-28 19:13:50 +00:00
static dbus_bool_t add_watch ( DBusWatch * watch , void * data ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = data ;
2006-08-06 16:16:50 +00:00
pa_io_event * ev ;
2007-10-28 19:13:50 +00:00
pa_assert ( watch ) ;
pa_assert ( c ) ;
2006-08-06 16:16:50 +00:00
2007-10-28 19:13:50 +00:00
ev = c - > mainloop - > io_new (
c - > mainloop ,
# if HAVE_DBUS_WATCH_GET_UNIX_FD
dbus_watch_get_unix_fd ( watch ) ,
# else
dbus_watch_get_fd ( watch ) ,
# endif
get_watch_flags ( watch ) , handle_io_event , watch ) ;
dbus_watch_set_data ( watch , ev , NULL ) ;
2006-08-06 16:16:50 +00:00
return TRUE ;
}
/* DBusRemoveWatchFunction callback for pa mainloop */
2007-10-28 19:13:50 +00:00
static void remove_watch ( DBusWatch * watch , void * data ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = data ;
2007-10-28 19:13:50 +00:00
pa_io_event * ev ;
2006-08-06 16:16:50 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( watch ) ;
pa_assert ( c ) ;
if ( ( ev = dbus_watch_get_data ( watch ) ) )
2006-08-06 16:16:50 +00:00
c - > mainloop - > io_free ( ev ) ;
}
/* DBusWatchToggledFunction callback for pa mainloop */
2007-10-28 19:13:50 +00:00
static void toggle_watch ( DBusWatch * watch , void * data ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = data ;
2007-10-28 19:13:50 +00:00
pa_io_event * ev ;
pa_assert ( watch ) ;
2009-03-19 01:35:02 +02:00
pa_assert ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert_se ( ev = dbus_watch_get_data ( watch ) ) ;
2006-08-06 16:16:50 +00:00
/* get_watch_flags() checks if the watch is enabled */
c - > mainloop - > io_enable ( ev , get_watch_flags ( watch ) ) ;
}
2009-04-05 02:13:43 +03:00
static void time_event_destroy_cb ( pa_mainloop_api * a , pa_time_event * e , void * userdata ) {
pa_xfree ( userdata ) ;
}
2006-08-06 16:16:50 +00:00
/* DBusAddTimeoutFunction callback for pa mainloop */
2007-10-28 19:13:50 +00:00
static dbus_bool_t add_timeout ( DBusTimeout * timeout , void * data ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = data ;
2006-08-06 16:16:50 +00:00
pa_time_event * ev ;
2007-10-28 19:13:50 +00:00
struct timeval tv ;
2009-04-05 02:13:43 +03:00
struct timeout_data * d ;
2007-10-28 19:13:50 +00:00
pa_assert ( timeout ) ;
pa_assert ( c ) ;
2006-08-06 16:16:50 +00:00
if ( ! dbus_timeout_get_enabled ( timeout ) )
return FALSE ;
2009-04-05 02:13:43 +03:00
d = pa_xnew ( struct timeout_data , 1 ) ;
d - > c = c ;
d - > timeout = timeout ;
ev = c - > mainloop - > time_new ( c - > mainloop , pa_timeval_rtstore ( & tv , pa_rtclock_now ( ) + dbus_timeout_get_interval ( timeout ) * PA_USEC_PER_MSEC , c - > use_rtclock ) , handle_time_event , d ) ;
c - > mainloop - > time_set_destroy ( ev , time_event_destroy_cb ) ;
2006-08-06 16:16:50 +00:00
2007-10-28 19:13:50 +00:00
dbus_timeout_set_data ( timeout , ev , NULL ) ;
2006-08-06 16:16:50 +00:00
return TRUE ;
}
/* DBusRemoveTimeoutFunction callback for pa mainloop */
2007-10-28 19:13:50 +00:00
static void remove_timeout ( DBusTimeout * timeout , void * data ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = data ;
2007-10-28 19:13:50 +00:00
pa_time_event * ev ;
pa_assert ( timeout ) ;
pa_assert ( c ) ;
2006-08-06 16:16:50 +00:00
2007-10-28 19:13:50 +00:00
if ( ( ev = dbus_timeout_get_data ( timeout ) ) )
2006-08-06 16:16:50 +00:00
c - > mainloop - > time_free ( ev ) ;
}
/* DBusTimeoutToggledFunction callback for pa mainloop */
2007-10-28 19:13:50 +00:00
static void toggle_timeout ( DBusTimeout * timeout , void * data ) {
2009-04-05 02:13:43 +03:00
struct timeout_data * d = data ;
2007-10-28 19:13:50 +00:00
pa_time_event * ev ;
2009-04-05 02:13:43 +03:00
struct timeval tv ;
2007-10-28 19:13:50 +00:00
2009-04-05 02:13:43 +03:00
pa_assert ( d ) ;
pa_assert ( d - > c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( timeout ) ;
pa_assert_se ( ev = dbus_timeout_get_data ( timeout ) ) ;
2006-08-06 16:16:50 +00:00
if ( dbus_timeout_get_enabled ( timeout ) ) {
2009-04-05 02:13:43 +03:00
d - > c - > mainloop - > time_restart ( ev , pa_timeval_rtstore ( & tv , pa_rtclock_now ( ) + dbus_timeout_get_interval ( timeout ) * PA_USEC_PER_MSEC , d - > c - > use_rtclock ) ) ;
2007-10-28 19:13:50 +00:00
} else
2009-04-05 02:13:43 +03:00
d - > c - > mainloop - > time_restart ( ev , pa_timeval_rtstore ( & tv , PA_USEC_INVALID , d - > c - > use_rtclock ) ) ;
2006-08-06 16:16:50 +00:00
}
2007-10-28 19:13:50 +00:00
static void wakeup_main ( void * userdata ) {
2009-03-19 01:35:02 +02:00
pa_dbus_wrap_connection * c = userdata ;
2006-08-06 16:16:50 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
2006-08-06 16:16:50 +00:00
/* this will wakeup the mainloop and dispatch events, although
* it may not be the cleanest way of accomplishing it */
2009-03-19 01:35:02 +02:00
c - > mainloop - > defer_enable ( c - > dispatch_event , 1 ) ;
2006-08-06 16:16:50 +00:00
}
2009-04-05 02:13:43 +03:00
pa_dbus_wrap_connection * pa_dbus_wrap_connection_new ( pa_mainloop_api * m , pa_bool_t use_rtclock , DBusBusType type , DBusError * error ) {
2009-03-19 01:35:02 +02:00
DBusConnection * conn ;
2009-04-06 02:31:22 +02:00
pa_dbus_wrap_connection * pconn ;
2009-04-10 01:12:46 +02:00
char * id ;
2006-08-06 16:16:50 +00:00
2009-03-19 01:35:02 +02:00
pa_assert ( type = = DBUS_BUS_SYSTEM | | type = = DBUS_BUS_SESSION | | type = = DBUS_BUS_STARTER ) ;
2006-08-06 16:16:50 +00:00
2009-03-19 01:35:02 +02:00
if ( ! ( conn = dbus_bus_get_private ( type , error ) ) )
return NULL ;
2006-08-06 16:16:50 +00:00
2009-03-19 01:35:02 +02:00
pconn = pa_xnew ( pa_dbus_wrap_connection , 1 ) ;
pconn - > mainloop = m ;
pconn - > connection = conn ;
2009-04-05 02:13:43 +03:00
pconn - > use_rtclock = use_rtclock ;
2006-08-06 16:16:50 +00:00
2009-03-19 01:35:02 +02:00
dbus_connection_set_exit_on_disconnect ( conn , FALSE ) ;
dbus_connection_set_dispatch_status_function ( conn , dispatch_status , pconn , NULL ) ;
dbus_connection_set_watch_functions ( conn , add_watch , remove_watch , toggle_watch , pconn , NULL ) ;
dbus_connection_set_timeout_functions ( conn , add_timeout , remove_timeout , toggle_timeout , pconn , NULL ) ;
dbus_connection_set_wakeup_main_function ( conn , wakeup_main , pconn , NULL ) ;
pconn - > dispatch_event = pconn - > mainloop - > defer_new ( pconn - > mainloop , dispatch_cb , conn ) ;
2007-10-28 19:13:50 +00:00
2009-04-06 04:20:12 +02:00
pa_log_debug ( " Successfully connected to D-Bus %s bus %s as %s " ,
type = = DBUS_BUS_SYSTEM ? " system " : ( type = = DBUS_BUS_SESSION ? " session " : " starter " ) ,
2009-04-10 01:12:46 +02:00
pa_strnull ( ( id = dbus_connection_get_server_id ( conn ) ) ) ,
2009-04-06 04:20:12 +02:00
pa_strnull ( dbus_bus_get_unique_name ( conn ) ) ) ;
2009-04-10 01:12:46 +02:00
dbus_free ( id ) ;
2009-03-19 01:35:02 +02:00
return pconn ;
2006-08-06 16:16:50 +00:00
}
2009-06-29 18:35:06 +03:00
pa_dbus_wrap_connection * pa_dbus_wrap_connection_new_from_existing ( pa_mainloop_api * m , pa_bool_t use_rtclock , DBusConnection * conn ) {
2009-06-16 19:03:22 +03:00
pa_dbus_wrap_connection * pconn ;
pa_assert ( m ) ;
pa_assert ( conn ) ;
pconn = pa_xnew ( pa_dbus_wrap_connection , 1 ) ;
pconn - > mainloop = m ;
pconn - > connection = dbus_connection_ref ( conn ) ;
2009-06-29 18:35:06 +03:00
pconn - > use_rtclock = use_rtclock ;
2009-06-16 19:03:22 +03:00
dbus_connection_set_exit_on_disconnect ( conn , FALSE ) ;
dbus_connection_set_dispatch_status_function ( conn , dispatch_status , pconn , NULL ) ;
dbus_connection_set_watch_functions ( conn , add_watch , remove_watch , toggle_watch , pconn , NULL ) ;
dbus_connection_set_timeout_functions ( conn , add_timeout , remove_timeout , toggle_timeout , pconn , NULL ) ;
dbus_connection_set_wakeup_main_function ( conn , wakeup_main , pconn , NULL ) ;
pconn - > dispatch_event = pconn - > mainloop - > defer_new ( pconn - > mainloop , dispatch_cb , conn ) ;
return pconn ;
}
2009-03-19 01:35:02 +02:00
void pa_dbus_wrap_connection_free ( pa_dbus_wrap_connection * c ) {
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
2006-08-06 16:16:50 +00:00
if ( dbus_connection_get_is_connected ( c - > connection ) ) {
dbus_connection_close ( c - > connection ) ;
2009-03-19 01:35:02 +02:00
/* must process remaining messages, bit of a kludge to handle
2007-10-28 19:13:50 +00:00
* both unload and shutdown */
2009-04-06 02:31:22 +02:00
while ( dbus_connection_read_write_dispatch ( c - > connection , - 1 ) )
;
2006-08-06 16:16:50 +00:00
}
2007-10-28 19:13:50 +00:00
2009-03-19 01:35:02 +02:00
c - > mainloop - > defer_free ( c - > dispatch_event ) ;
2007-10-28 19:13:50 +00:00
dbus_connection_unref ( c - > connection ) ;
pa_xfree ( c ) ;
2006-08-06 16:16:50 +00:00
}
2009-03-19 01:35:02 +02:00
DBusConnection * pa_dbus_wrap_connection_get ( pa_dbus_wrap_connection * c ) {
pa_assert ( c ) ;
pa_assert ( c - > connection ) ;
2006-08-06 16:16:50 +00:00
2009-03-19 01:35:02 +02:00
return c - > connection ;
2006-08-06 16:16:50 +00:00
}
2009-01-29 03:30:50 +01:00
int pa_dbus_add_matches ( DBusConnection * c , DBusError * error , . . . ) {
const char * t ;
va_list ap ;
unsigned k = 0 ;
pa_assert ( c ) ;
pa_assert ( error ) ;
va_start ( ap , error ) ;
while ( ( t = va_arg ( ap , const char * ) ) ) {
dbus_bus_add_match ( c , t , error ) ;
if ( dbus_error_is_set ( error ) )
goto fail ;
k + + ;
}
va_end ( ap ) ;
return 0 ;
fail :
va_end ( ap ) ;
va_start ( ap , error ) ;
for ( ; k > 0 ; k - - ) {
DBusError e ;
pa_assert_se ( t = va_arg ( ap , const char * ) ) ;
dbus_error_init ( & e ) ;
dbus_bus_remove_match ( c , t , & e ) ;
dbus_error_free ( & e ) ;
}
va_end ( ap ) ;
return - 1 ;
}
void pa_dbus_remove_matches ( DBusConnection * c , . . . ) {
const char * t ;
va_list ap ;
DBusError error ;
pa_assert ( c ) ;
dbus_error_init ( & error ) ;
va_start ( ap , c ) ;
while ( ( t = va_arg ( ap , const char * ) ) ) {
dbus_bus_remove_match ( c , t , & error ) ;
dbus_error_free ( & error ) ;
}
va_end ( ap ) ;
}
2009-01-29 16:26:34 +01:00
2009-03-20 19:30:37 +01:00
pa_dbus_pending * pa_dbus_pending_new (
DBusConnection * c ,
DBusMessage * m ,
DBusPendingCall * pending ,
void * context_data ,
void * call_data ) {
2009-01-29 16:26:34 +01:00
pa_dbus_pending * p ;
pa_assert ( pending ) ;
p = pa_xnew ( pa_dbus_pending , 1 ) ;
2009-03-20 19:30:37 +01:00
p - > connection = c ;
2009-01-29 16:26:34 +01:00
p - > message = m ;
p - > pending = pending ;
p - > context_data = context_data ;
p - > call_data = call_data ;
PA_LLIST_INIT ( pa_dbus_pending , p ) ;
return p ;
}
void pa_dbus_pending_free ( pa_dbus_pending * p ) {
pa_assert ( p ) ;
2009-04-10 01:14:46 +02:00
if ( p - > pending ) {
dbus_pending_call_cancel ( p - > pending ) ;
dbus_pending_call_unref ( p - > pending ) ;
}
2009-01-29 16:26:34 +01:00
if ( p - > message )
dbus_message_unref ( p - > message ) ;
pa_xfree ( p ) ;
}
void pa_dbus_sync_pending_list ( pa_dbus_pending * * p ) {
pa_assert ( p ) ;
2009-03-20 19:30:37 +01:00
while ( * p & & dbus_connection_read_write_dispatch ( ( * p ) - > connection , - 1 ) )
;
2009-01-29 16:26:34 +01:00
}
void pa_dbus_free_pending_list ( pa_dbus_pending * * p ) {
pa_dbus_pending * i ;
pa_assert ( p ) ;
while ( ( i = * p ) ) {
PA_LLIST_REMOVE ( pa_dbus_pending , * p , i ) ;
pa_dbus_pending_free ( i ) ;
}
}
2009-07-21 00:02:27 +03:00
2009-07-27 20:01:39 +03:00
void pa_dbus_send_error ( DBusConnection * c , DBusMessage * in_reply_to , const char * name , const char * format , . . . ) {
va_list ap ;
char * message ;
2009-07-21 00:02:27 +03:00
DBusMessage * reply = NULL ;
pa_assert ( c ) ;
pa_assert ( in_reply_to ) ;
pa_assert ( name ) ;
2009-07-27 20:01:39 +03:00
pa_assert ( format ) ;
2009-07-21 00:02:27 +03:00
2009-07-27 20:01:39 +03:00
va_start ( ap , format ) ;
message = pa_vsprintf_malloc ( format , ap ) ;
va_end ( ap ) ;
2009-07-21 00:02:27 +03:00
pa_assert_se ( ( reply = dbus_message_new_error ( in_reply_to , name , message ) ) ) ;
pa_assert_se ( dbus_connection_send ( c , reply , NULL ) ) ;
dbus_message_unref ( reply ) ;
2009-07-27 20:01:39 +03:00
pa_xfree ( message ) ;
2009-07-21 00:02:27 +03:00
}
void pa_dbus_send_empty_reply ( DBusConnection * c , DBusMessage * in_reply_to ) {
DBusMessage * reply = NULL ;
pa_assert ( c ) ;
pa_assert ( in_reply_to ) ;
pa_assert_se ( ( reply = dbus_message_new_method_return ( in_reply_to ) ) ) ;
pa_assert_se ( dbus_connection_send ( c , reply , NULL ) ) ;
dbus_message_unref ( reply ) ;
}
void pa_dbus_send_basic_value_reply ( DBusConnection * c , DBusMessage * in_reply_to , int type , void * data ) {
DBusMessage * reply = NULL ;
pa_assert ( c ) ;
pa_assert ( in_reply_to ) ;
pa_assert ( dbus_type_is_basic ( type ) ) ;
pa_assert ( data ) ;
pa_assert_se ( ( reply = dbus_message_new_method_return ( in_reply_to ) ) ) ;
pa_assert_se ( dbus_message_append_args ( reply , type , data , DBUS_TYPE_INVALID ) ) ;
pa_assert_se ( dbus_connection_send ( c , reply , NULL ) ) ;
dbus_message_unref ( reply ) ;
}
static const char * signature_from_basic_type ( int type ) {
switch ( type ) {
case DBUS_TYPE_BOOLEAN : return DBUS_TYPE_BOOLEAN_AS_STRING ;
case DBUS_TYPE_BYTE : return DBUS_TYPE_BYTE_AS_STRING ;
case DBUS_TYPE_INT16 : return DBUS_TYPE_INT16_AS_STRING ;
case DBUS_TYPE_UINT16 : return DBUS_TYPE_UINT16_AS_STRING ;
case DBUS_TYPE_INT32 : return DBUS_TYPE_INT32_AS_STRING ;
case DBUS_TYPE_UINT32 : return DBUS_TYPE_UINT32_AS_STRING ;
case DBUS_TYPE_INT64 : return DBUS_TYPE_INT64_AS_STRING ;
case DBUS_TYPE_UINT64 : return DBUS_TYPE_UINT64_AS_STRING ;
case DBUS_TYPE_DOUBLE : return DBUS_TYPE_DOUBLE_AS_STRING ;
case DBUS_TYPE_STRING : return DBUS_TYPE_STRING_AS_STRING ;
case DBUS_TYPE_OBJECT_PATH : return DBUS_TYPE_OBJECT_PATH_AS_STRING ;
case DBUS_TYPE_SIGNATURE : return DBUS_TYPE_SIGNATURE_AS_STRING ;
default : pa_assert_not_reached ( ) ;
}
}
void pa_dbus_send_basic_variant_reply ( DBusConnection * c , DBusMessage * in_reply_to , int type , void * data ) {
DBusMessage * reply = NULL ;
DBusMessageIter msg_iter ;
DBusMessageIter variant_iter ;
pa_assert ( c ) ;
pa_assert ( in_reply_to ) ;
pa_assert ( dbus_type_is_basic ( type ) ) ;
pa_assert ( data ) ;
pa_assert_se ( ( reply = dbus_message_new_method_return ( in_reply_to ) ) ) ;
dbus_message_iter_init_append ( reply , & msg_iter ) ;
pa_assert_se ( dbus_message_iter_open_container ( & msg_iter , DBUS_TYPE_VARIANT , signature_from_basic_type ( type ) , & variant_iter ) ) ;
pa_assert_se ( dbus_message_iter_append_basic ( & variant_iter , type , data ) ) ;
pa_assert_se ( dbus_message_iter_close_container ( & msg_iter , & variant_iter ) ) ;
pa_assert_se ( dbus_connection_send ( c , reply , NULL ) ) ;
dbus_message_unref ( reply ) ;
}
/* Note: returns sizeof(char*) for strings, object paths and signatures. */
static unsigned basic_type_size ( int type ) {
switch ( type ) {
case DBUS_TYPE_BOOLEAN : return sizeof ( dbus_bool_t ) ;
case DBUS_TYPE_BYTE : return 1 ;
case DBUS_TYPE_INT16 : return sizeof ( dbus_int16_t ) ;
case DBUS_TYPE_UINT16 : return sizeof ( dbus_uint16_t ) ;
case DBUS_TYPE_INT32 : return sizeof ( dbus_int32_t ) ;
case DBUS_TYPE_UINT32 : return sizeof ( dbus_uint32_t ) ;
case DBUS_TYPE_INT64 : return sizeof ( dbus_int64_t ) ;
case DBUS_TYPE_UINT64 : return sizeof ( dbus_uint64_t ) ;
case DBUS_TYPE_DOUBLE : return sizeof ( double ) ;
case DBUS_TYPE_STRING :
case DBUS_TYPE_OBJECT_PATH :
case DBUS_TYPE_SIGNATURE : return sizeof ( char * ) ;
default : pa_assert_not_reached ( ) ;
}
}
void pa_dbus_send_basic_array_variant_reply ( DBusConnection * c , DBusMessage * in_reply_to , int item_type , void * array , unsigned n ) {
DBusMessage * reply = NULL ;
DBusMessageIter msg_iter ;
pa_assert ( c ) ;
pa_assert ( in_reply_to ) ;
pa_assert ( dbus_type_is_basic ( item_type ) ) ;
pa_assert ( array | | n = = 0 ) ;
pa_assert_se ( ( reply = dbus_message_new_method_return ( in_reply_to ) ) ) ;
dbus_message_iter_init_append ( reply , & msg_iter ) ;
pa_dbus_append_basic_array_variant ( & msg_iter , item_type , array , n ) ;
pa_assert_se ( dbus_connection_send ( c , reply , NULL ) ) ;
dbus_message_unref ( reply ) ;
}
void pa_dbus_append_basic_array ( DBusMessageIter * iter , int item_type , const void * array , unsigned n ) {
DBusMessageIter array_iter ;
unsigned i ;
unsigned item_size ;
pa_assert ( iter ) ;
pa_assert ( dbus_type_is_basic ( item_type ) ) ;
pa_assert ( array | | n = = 0 ) ;
item_size = basic_type_size ( item_type ) ;
pa_assert_se ( dbus_message_iter_open_container ( iter , DBUS_TYPE_ARRAY , signature_from_basic_type ( item_type ) , & array_iter ) ) ;
for ( i = 0 ; i < n ; + + i )
pa_assert_se ( dbus_message_iter_append_basic ( & array_iter , item_type , & ( ( uint8_t * ) array ) [ i * item_size ] ) ) ;
pa_assert_se ( dbus_message_iter_close_container ( iter , & array_iter ) ) ;
} ;
void pa_dbus_append_basic_variant ( DBusMessageIter * iter , int type , void * data ) {
DBusMessageIter variant_iter ;
pa_assert ( iter ) ;
pa_assert ( dbus_type_is_basic ( type ) ) ;
pa_assert ( data ) ;
pa_assert_se ( dbus_message_iter_open_container ( iter , DBUS_TYPE_VARIANT , signature_from_basic_type ( type ) , & variant_iter ) ) ;
pa_assert_se ( dbus_message_iter_append_basic ( & variant_iter , type , data ) ) ;
pa_assert_se ( dbus_message_iter_close_container ( iter , & variant_iter ) ) ;
}
void pa_dbus_append_basic_array_variant ( DBusMessageIter * iter , int item_type , const void * array , unsigned n ) {
DBusMessageIter variant_iter ;
char * array_signature ;
pa_assert ( iter ) ;
pa_assert ( dbus_type_is_basic ( item_type ) ) ;
pa_assert ( array | | n = = 0 ) ;
array_signature = pa_sprintf_malloc ( " a%c " , * signature_from_basic_type ( item_type ) ) ;
pa_assert_se ( dbus_message_iter_open_container ( iter , DBUS_TYPE_VARIANT , array_signature , & variant_iter ) ) ;
pa_dbus_append_basic_array ( & variant_iter , item_type , array , n ) ;
pa_assert_se ( dbus_message_iter_close_container ( iter , & variant_iter ) ) ;
pa_xfree ( array_signature ) ;
}
void pa_dbus_append_basic_variant_dict_entry ( DBusMessageIter * dict_iter , const char * key , int type , void * data ) {
DBusMessageIter dict_entry_iter ;
pa_assert ( dict_iter ) ;
pa_assert ( key ) ;
pa_assert ( dbus_type_is_basic ( type ) ) ;
pa_assert ( data ) ;
pa_assert_se ( dbus_message_iter_open_container ( dict_iter , DBUS_TYPE_DICT_ENTRY , NULL , & dict_entry_iter ) ) ;
pa_assert_se ( dbus_message_iter_append_basic ( & dict_entry_iter , DBUS_TYPE_STRING , & key ) ) ;
pa_dbus_append_basic_variant ( & dict_entry_iter , type , data ) ;
pa_assert_se ( dbus_message_iter_close_container ( dict_iter , & dict_entry_iter ) ) ;
}
void pa_dbus_append_basic_array_variant_dict_entry ( DBusMessageIter * dict_iter , const char * key , int item_type , const void * array , unsigned n ) {
DBusMessageIter dict_entry_iter ;
pa_assert ( dict_iter ) ;
pa_assert ( key ) ;
pa_assert ( dbus_type_is_basic ( item_type ) ) ;
pa_assert ( array | | n = = 0 ) ;
pa_assert_se ( dbus_message_iter_open_container ( dict_iter , DBUS_TYPE_DICT_ENTRY , NULL , & dict_entry_iter ) ) ;
pa_assert_se ( dbus_message_iter_append_basic ( & dict_entry_iter , DBUS_TYPE_STRING , & key ) ) ;
pa_dbus_append_basic_array_variant ( & dict_entry_iter , item_type , array , n ) ;
pa_assert_se ( dbus_message_iter_close_container ( dict_iter , & dict_entry_iter ) ) ;
}
int pa_dbus_get_basic_set_property_arg ( DBusConnection * c , DBusMessage * msg , int type , void * data ) {
DBusMessageIter msg_iter ;
DBusMessageIter variant_iter ;
pa_assert ( c ) ;
pa_assert ( msg ) ;
pa_assert ( dbus_type_is_basic ( type ) ) ;
pa_assert ( data ) ;
/* Skip the interface and property name arguments. */
if ( ! dbus_message_iter_init ( msg , & msg_iter ) | | ! dbus_message_iter_next ( & msg_iter ) | | ! dbus_message_iter_next ( & msg_iter ) ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Too few arguments. " ) ;
return - 1 ;
}
if ( dbus_message_iter_get_arg_type ( & msg_iter ) ! = DBUS_TYPE_VARIANT ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Message argument isn't a variant. " ) ;
return - 1 ;
}
dbus_message_iter_recurse ( & msg_iter , & variant_iter ) ;
2009-07-27 20:01:39 +03:00
if ( pa_dbus_get_basic_arg ( c , msg , & variant_iter , type , data ) < 0 )
return - 1 ;
return 0 ;
}
int pa_dbus_get_fixed_array_set_property_arg ( DBusConnection * c , DBusMessage * msg , int item_type , void * data , unsigned * n ) {
DBusMessageIter msg_iter ;
DBusMessageIter variant_iter ;
pa_assert ( c ) ;
pa_assert ( msg ) ;
pa_assert ( dbus_type_is_fixed ( item_type ) ) ;
pa_assert ( data ) ;
pa_assert ( n ) ;
/* Skip the interface and property name arguments. */
if ( ! dbus_message_iter_init ( msg , & msg_iter ) | | ! dbus_message_iter_next ( & msg_iter ) | | ! dbus_message_iter_next ( & msg_iter ) ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Too few arguments. " ) ;
2009-07-21 00:02:27 +03:00
return - 1 ;
}
2009-07-27 20:01:39 +03:00
if ( dbus_message_iter_get_arg_type ( & msg_iter ) ! = DBUS_TYPE_VARIANT ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Message argument isn't a variant. " ) ;
return - 1 ;
}
dbus_message_iter_recurse ( & msg_iter , & variant_iter ) ;
if ( pa_dbus_get_fixed_array_arg ( c , msg , & variant_iter , item_type , data , n ) < 0 )
return - 1 ;
2009-07-21 00:02:27 +03:00
return 0 ;
}
int pa_dbus_get_basic_arg ( DBusConnection * c , DBusMessage * msg , DBusMessageIter * iter , int type , void * data ) {
2009-07-27 20:01:39 +03:00
int arg_type ;
2009-07-21 00:02:27 +03:00
pa_assert ( c ) ;
pa_assert ( msg ) ;
pa_assert ( iter ) ;
pa_assert ( dbus_type_is_basic ( type ) ) ;
pa_assert ( data ) ;
2009-07-27 20:01:39 +03:00
arg_type = dbus_message_iter_get_arg_type ( iter ) ;
if ( arg_type ! = type ) {
if ( arg_type = = DBUS_TYPE_INVALID )
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Too few arguments. D-Bus type '%c' expected. " , ( char ) type ) ;
else
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong argument type: '%c'. Expected type '%c'. " , ( char ) arg_type , ( char ) type ) ;
2009-07-21 00:02:27 +03:00
return - 1 ;
}
dbus_message_iter_get_basic ( iter , data ) ;
2009-07-27 20:01:39 +03:00
dbus_message_iter_next ( iter ) ;
2009-07-21 00:02:27 +03:00
return 0 ;
}
int pa_dbus_get_fixed_array_arg ( DBusConnection * c , DBusMessage * msg , DBusMessageIter * iter , int item_type , void * array , unsigned * n ) {
DBusMessageIter array_iter ;
int signed_n ;
2009-07-27 20:01:39 +03:00
int arg_type ;
int element_type ;
2009-07-21 00:02:27 +03:00
pa_assert ( c ) ;
pa_assert ( msg ) ;
pa_assert ( iter ) ;
pa_assert ( dbus_type_is_fixed ( item_type ) ) ;
pa_assert ( array ) ;
pa_assert ( n ) ;
2009-07-27 20:01:39 +03:00
arg_type = dbus_message_iter_get_arg_type ( iter ) ;
if ( arg_type ! = DBUS_TYPE_ARRAY ) {
if ( arg_type = = DBUS_TYPE_INVALID )
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Too few arguments. An array of type '%c' was expected. " , ( char ) item_type ) ;
else
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong argument type: '%c'. An array of type '%c' was expected. " , ( char ) arg_type , ( char ) item_type ) ;
2009-07-21 00:02:27 +03:00
return - 1 ;
}
2009-07-27 20:01:39 +03:00
element_type = dbus_message_iter_get_element_type ( iter ) ;
if ( element_type ! = item_type ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong array element type: '%c'. Element type '%c' was expected. " , ( char ) element_type , ( char ) item_type ) ;
2009-07-21 00:02:27 +03:00
return - 1 ;
}
dbus_message_iter_recurse ( iter , & array_iter ) ;
dbus_message_iter_get_fixed_array ( & array_iter , array , & signed_n ) ;
2009-07-27 20:01:39 +03:00
dbus_message_iter_next ( iter ) ;
2009-07-21 00:02:27 +03:00
pa_assert ( signed_n > = 0 ) ;
* n = signed_n ;
return 0 ;
}
pa_proplist * pa_dbus_get_proplist_arg ( DBusConnection * c , DBusMessage * msg , DBusMessageIter * iter ) {
DBusMessageIter dict_iter ;
2009-08-03 19:36:19 +03:00
DBusMessageIter dict_entry_iter ;
int arg_type ;
2009-07-21 00:02:27 +03:00
pa_proplist * proplist = NULL ;
const char * key ;
const uint8_t * value ;
int value_length ;
pa_assert ( c ) ;
pa_assert ( msg ) ;
pa_assert ( iter ) ;
2009-08-03 19:36:19 +03:00
arg_type = dbus_message_iter_get_arg_type ( iter ) ;
if ( arg_type ! = DBUS_TYPE_ARRAY ) {
if ( arg_type = = DBUS_TYPE_INVALID )
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Too few arguments. An array was expected. " ) ;
else
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong argument type: '%c'. An array was expected. " , ( char ) arg_type ) ;
2009-07-21 00:02:27 +03:00
return NULL ;
}
2009-08-03 19:36:19 +03:00
arg_type = dbus_message_iter_get_element_type ( iter ) ;
if ( arg_type ! = DBUS_TYPE_DICT_ENTRY ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong array element type: '%c'. A dictionary entry was expected. " , ( char ) arg_type ) ;
2009-07-21 00:02:27 +03:00
return NULL ;
}
proplist = pa_proplist_new ( ) ;
dbus_message_iter_recurse ( iter , & dict_iter ) ;
2009-08-03 19:36:19 +03:00
while ( dbus_message_iter_get_arg_type ( & dict_iter ) ! = DBUS_TYPE_INVALID ) {
dbus_message_iter_recurse ( & dict_iter , & dict_entry_iter ) ;
arg_type = dbus_message_iter_get_arg_type ( & dict_entry_iter ) ;
if ( arg_type ! = DBUS_TYPE_STRING ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong dict key type: '%c'. A string was expected. " , ( char ) arg_type ) ;
2009-07-21 00:02:27 +03:00
goto fail ;
}
2009-08-03 19:36:19 +03:00
dbus_message_iter_get_basic ( & dict_entry_iter , & key ) ;
dbus_message_iter_next ( & dict_entry_iter ) ;
2009-07-21 00:02:27 +03:00
if ( strlen ( key ) < = 0 | | ! pa_ascii_valid ( key ) ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Invalid property list key. " ) ;
goto fail ;
}
2009-08-03 19:36:19 +03:00
arg_type = dbus_message_iter_get_arg_type ( & dict_entry_iter ) ;
if ( arg_type ! = DBUS_TYPE_ARRAY ) {
if ( arg_type = = DBUS_TYPE_INVALID )
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Dict value missing. " ) ;
else
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong dict value type: '%c'. An array was expected. " , ( char ) arg_type ) ;
2009-07-21 00:02:27 +03:00
goto fail ;
}
2009-08-03 19:36:19 +03:00
arg_type = dbus_message_iter_get_element_type ( & dict_entry_iter ) ;
if ( arg_type ! = DBUS_TYPE_BYTE ) {
pa_dbus_send_error ( c , msg , DBUS_ERROR_INVALID_ARGS , " Wrong dict value item type: '%c'. A byte was expected. " , ( char ) arg_type ) ;
2009-07-21 00:02:27 +03:00
goto fail ;
}
2009-08-03 19:36:19 +03:00
dbus_message_iter_get_fixed_array ( & dict_entry_iter , & value , & value_length ) ;
2009-07-21 00:02:27 +03:00
pa_assert ( value_length > = 0 ) ;
pa_assert_se ( pa_proplist_set ( proplist , key , value , value_length ) > = 0 ) ;
2009-08-03 19:36:19 +03:00
dbus_message_iter_next ( & dict_iter ) ;
2009-07-21 00:02:27 +03:00
}
2009-07-27 20:01:39 +03:00
dbus_message_iter_next ( iter ) ;
2009-07-21 00:02:27 +03:00
return proplist ;
fail :
if ( proplist )
pa_proplist_free ( proplist ) ;
return NULL ;
}