summaryrefslogtreecommitdiffstats
path: root/contrib/dbus/dbus_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/dbus/dbus_service.c')
-rw-r--r--contrib/dbus/dbus_service.c1161
1 files changed, 1161 insertions, 0 deletions
diff --git a/contrib/dbus/dbus_service.c b/contrib/dbus/dbus_service.c
new file mode 100644
index 0000000..47d55d5
--- /dev/null
+++ b/contrib/dbus/dbus_service.c
@@ -0,0 +1,1161 @@
+/* dbus_service.c
+ *
+ * D-BUS Service Utilities
+ *
+ * Provides MINIMAL utilities for construction of D-BUS "Services".
+ *
+ * Copyright(C) Jason Vas Dias, Red Hat Inc., 2005
+ * Modified by Adam Tkac, Red Hat Inc., 2007
+ *
+ * This program 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 at
+ * http://www.fsf.org/licensing/licenses/gpl.txt
+ * and included in this software distribution as the "LICENSE" file.
+ *
+ * This program 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.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/limits.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <signal.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <string.h>
+extern size_t strnlen(const char *s, size_t maxlen);
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+#include <search.h>
+#include <getopt.h>
+typedef void (*__free_fn_t) (void *__nodep);
+extern void tdestroy (void *__root, __free_fn_t __freefct);
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#define DBUS_API_SUBJECT_TO_CHANGE "Very Annoying and Silly!"
+#include <dbus/dbus.h>
+
+#include <named/dbus_service.h>
+#include <isc/result.h>
+
+typedef struct dbcs_s
+{
+ DBusConnection *connection;
+ DBusDispatchStatus dispatchStatus;
+ uint32_t status;
+ dbus_svc_WatchHandler wh;
+ void * wh_arg;
+ const char * unique_name;
+ dbus_svc_MessageHandler mh;
+ void * def_mh_obj;
+ dbus_svc_MessageHandler mf;
+ void * def_mf_obj;
+ dbus_svc_ShutdownHandler sh;
+ void * sh_obj;
+ dbus_svc_ErrorHandler eh;
+ dbus_svc_ErrorHandler dh;
+ /*{ glibc b-trees: */
+ void * roots;
+ void * timeouts;
+ void * watches;
+ void * filters;
+ /*}*/
+ int n;
+ fd_set r_fds;
+ fd_set s_r_fds;
+ fd_set w_fds;
+ fd_set s_w_fds;
+ fd_set e_fds;
+ fd_set s_e_fds;
+ DBusMessage *currentMessage;
+ int rejectMessage;
+} DBusConnectionState;
+
+typedef struct root_s
+{
+ char *path;
+ char *if_prefix;
+ DBUS_SVC cs;
+ dbus_svc_MessageHandler mh;
+ void *object;
+ void *tree;
+} Root;
+
+typedef struct mhn_s
+{
+ char *path;
+ dbus_svc_MessageHandler mh;
+ void *object;
+} MessageHandlerNode;
+
+typedef struct mfn_s
+{
+ DBusConnectionState *cs;
+ dbus_svc_MessageHandler mf;
+ void *obj;
+ int n_matches;
+ char **matches;
+} MessageFilterNode;
+
+typedef struct dbto_s
+{
+ DBusTimeout *to;
+ DBusConnectionState *cs;
+ struct timeval tv;
+} DBusConnectionTimeout;
+
+static void no_free( void *p){ p=0; }
+
+static int ptr_key_comparator( const void *p1, const void *p2 )
+{
+ return
+ ( (p1 == p2)
+ ? 0
+ :( (p1 > p2)
+ ? 1
+ : -1
+ )
+ );
+}
+
+static DBusHandlerResult
+default_message_filter
+( DBusConnection *connection,
+ DBusMessage *message,
+ void *p
+)
+{
+ DBusConnectionState *cs = p;
+ uint32_t type =dbus_message_get_type( message ),
+ serial =dbus_message_get_serial( message );
+ uint8_t reply =dbus_message_get_no_reply( message )==0;
+ const char
+ *path = dbus_message_get_path( message ),
+ *dest = dbus_message_get_destination( message ),
+ *member = dbus_message_get_member( message ),
+ *interface=dbus_message_get_interface( message ),
+ *sender =dbus_message_get_sender( message ),
+ *signature=dbus_message_get_signature( message );
+ connection = connection;
+ if(cs->mf)
+ return
+ (*(cs->mf))( cs, type, reply, serial, dest, path, member, interface, 0L,
+ sender, signature, message, 0L, 0L, 0L, cs->def_mf_obj
+ ) ;
+ return HANDLED;
+}
+
+uint8_t
+dbus_svc_add_filter
+( DBusConnectionState *cs, dbus_svc_MessageHandler mh, void *obj, int n_matches, ... )
+{
+ DBusError error;
+ va_list va;
+ char *m;
+
+ va_start(va, n_matches );
+
+ cs->mf = mh;
+ cs->def_mf_obj = obj;
+
+ if ( ! dbus_connection_add_filter (cs->connection, default_message_filter, cs, NULL))
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_add_filter: dbus_connection_add_filter failed");
+ va_end(va);
+ return( 0 );
+ }
+
+ if( n_matches )
+ {
+ memset(&error,'\0',sizeof(DBusError));
+ dbus_error_init(&error);
+ while( n_matches-- )
+ {
+ m = va_arg(va, char* ) ;
+
+ dbus_bus_add_match(cs->connection, m, &error);
+
+ if( dbus_error_is_set(&error))
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_add_filter: dbus_bus_add_match failed for %s: %s %s",
+ m, error.name, error.message
+ );
+ va_end(va);
+ return(0);
+ }
+ }
+ }
+ va_end(va);
+ return( 1 );
+}
+
+
+uint8_t
+dbus_svc_get_args_va(DBusConnectionState *cs, DBusMessage* msg, dbus_svc_DataType firstType, va_list va)
+{
+ DBusError error;
+ memset(&error,'\0',sizeof(DBusError));
+ dbus_error_init(&error);
+ if( (!dbus_message_get_args_valist(msg, &error, firstType, va)) || dbus_error_is_set(&error) )
+ {
+ if( dbus_error_is_set(&error) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_get_args failed: %s %s",error.name, error.message);
+ dbus_error_free(&error);
+ }else
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_get_args failed: dbus_message_get_args_valist failed");
+ return( 0 );
+ }
+ return( 1 );
+}
+
+uint8_t
+dbus_svc_get_args(DBusConnectionState *cs, DBusMessage* msg, dbus_svc_DataType firstType, ...)
+{
+ va_list va;
+ uint8_t r;
+ va_start(va, firstType);
+ r = dbus_svc_get_args_va( cs, msg, firstType, va);
+ va_end(va);
+ return r;
+}
+
+uint8_t
+dbus_svc_send_va
+( DBusConnectionState *cs,
+ dbus_svc_MessageType type,
+ int32_t reply_serial,
+ uint32_t *new_serial,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ dbus_svc_DataType firstType,
+ va_list va
+)
+{
+ DBusMessageIter iter;
+ char *e;
+ DBusMessage *msg =
+ dbus_svc_new_message
+ ( cs,
+ type,
+ reply_serial,
+ destination,
+ path,
+ interface,
+ member
+ );
+
+ if(msg == 0L)
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_svc_new_message failed");
+ return 0;
+ }
+
+ if( type != DBUS_MESSAGE_TYPE_ERROR )
+ {
+ if( !dbus_message_append_args_valist( msg, firstType, va ) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_append_args_valist failed");
+ return 0;
+ }
+ }else
+ {
+ if( firstType == DBUS_TYPE_STRING )
+ {
+ e = 0L;
+ e = va_arg( va, char* );
+ if( (e == 0L) || !dbus_message_set_error_name( msg, e ) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_set_error_name failed");
+ return 0;
+ }
+ firstType = va_arg(va, int);
+ if( firstType == DBUS_TYPE_STRING )
+ {
+ e = 0L;
+ e = va_arg( va, char* );
+ if( e == 0L )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: NULL error message");
+ return 0;
+ }
+ dbus_message_iter_init_append (msg, &iter);
+ if( !dbus_message_iter_append_basic
+ (&iter, DBUS_TYPE_STRING, &e)
+ )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_iter_append_basic failed");
+ return 0;
+ }
+ }
+ }else
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: unhandled type for error name: %c", firstType);
+ return 0;
+ }
+ }
+
+ if( !dbus_connection_send(cs->connection, msg, new_serial) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_send failed");
+ return 0;
+ }
+ if( cs->dh != 0L ) (*(cs->dh))("Sending message");
+ dbus_connection_flush(cs->connection);
+ return 1;
+}
+
+uint8_t
+dbus_svc_send
+( DBusConnectionState *cs,
+ dbus_svc_MessageType type,
+ int32_t reply_serial,
+ uint32_t *new_serial,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ dbus_svc_DataType firstType,
+ ...
+)
+{
+ uint8_t r;
+ va_list va;
+ va_start(va, firstType);
+ r = dbus_svc_send_va(cs, type, reply_serial, new_serial, destination, path,interface,member,firstType,va);
+ va_end(va);
+ return ( r ) ;
+}
+
+dbus_svc_MessageHandle
+dbus_svc_new_message
+( DBusConnectionState* cs,
+ dbus_svc_MessageType type,
+ int32_t reply_serial,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member
+)
+{
+ DBusMessage *msg = dbus_message_new(type);
+
+ if( msg == 0L)
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_reply_serial failed");
+ return 0;
+ }
+
+ if( reply_serial != -1 )
+ {
+ if( !dbus_message_set_reply_serial(msg,reply_serial) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_reply_serial failed");
+ return 0;
+ }
+ }
+
+ if( (destination !=0L) && !dbus_message_set_destination(msg, destination) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_destination failed");
+ return 0;
+ }
+
+ if( !dbus_message_set_path(msg, path) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_path failed");
+ return 0;
+ }
+
+ if( ! dbus_message_set_interface(msg,interface) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_interface failed - %s", interface);
+ return 0;
+ }
+
+ if( !dbus_message_set_member(msg,member) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_member failed");
+ return 0;
+ }
+
+ return msg;
+}
+
+extern uint8_t
+dbus_svc_send_message
+(
+ DBusConnectionState *cs,
+ dbus_svc_MessageHandle msg,
+ uint32_t *new_serial
+)
+{
+ if( !dbus_connection_send(cs->connection, msg, new_serial) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_send failed");
+ return 0;
+ }
+ if( cs->dh != 0L ) (*(cs->dh))("Sending message");
+ dbus_connection_flush(cs->connection);
+ return 1;
+}
+
+uint8_t
+dbus_svc_message_append_args(DBusConnectionState *cs, dbus_svc_MessageHandle msg, dbus_svc_DataType firstType, ...)
+{
+ va_list va;
+ va_start(va, firstType);
+ if( !dbus_message_append_args_valist( msg, firstType, va ) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_append_args failed");
+ va_end(va);
+ return 0;
+ }
+ va_end(va);
+ return ( 1 ) ;
+}
+
+dbus_svc_MessageHandle
+dbus_svc_call
+( DBusConnectionState *cs,
+ const char *destination,
+ const char *path,
+ const char *member,
+ const char *interface,
+ dbus_svc_DataType firstType,
+ ...
+)
+{
+ DBusMessage *message=0L, *reply=0L;
+ va_list va;
+ DBusError error;
+ int reply_timeout=20000;
+
+ va_start(va, firstType);
+
+ memset(&error,'\0',sizeof(DBusError));
+ dbus_error_init(&error);
+
+ if(( message =
+ dbus_message_new_method_call
+ ( destination,
+ path,
+ interface,
+ member
+ )
+ ) == 0L
+ )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_new_method_call failed");
+ va_end(va);
+ return(0L);
+ };
+
+ if( !dbus_message_append_args_valist( message, firstType, va ) )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_append_args_valist failed");
+ va_end(va);
+ return(0L);
+ }
+
+ if((reply =
+ dbus_connection_send_with_reply_and_block
+ (cs->connection,
+ message, reply_timeout,
+ &error
+ )
+ ) == 0L
+ )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_send_with_reply_and_block failed: %s %s",
+ error.name, error.message
+ );
+ va_end(va);
+ return(0L);
+ }
+ va_end(va);
+ return reply;
+}
+
+dbus_svc_MessageIterator
+dbus_svc_message_iterator_new( DBusConnectionState *cs, DBusMessage *msg)
+{
+ DBusMessageIter *iter = malloc( sizeof(DBusMessageIter) );
+ void *p =cs;
+ p++;
+ if( iter != 0L )
+ {
+ if( !dbus_message_iter_init( msg, iter ))
+ {
+ free( iter ) ;
+ iter = 0L;
+ }
+ }
+ return iter;
+}
+
+uint32_t
+dbus_svc_message_next_arg_type( DBusConnectionState *cs, dbus_svc_MessageIterator iter )
+{
+ void *p =cs;
+ p++;
+ return dbus_message_iter_get_arg_type( iter );
+}
+
+void
+dbus_svc_message_next_arg( DBusConnectionState *cs, dbus_svc_MessageIterator iter, void *value )
+{
+ void *p =cs;
+ p++;
+ dbus_message_iter_get_basic( iter, value );
+ dbus_message_iter_next( iter );
+}
+
+uint32_t
+dbus_svc_message_element_type(DBusConnectionState *cs , dbus_svc_MessageIterator iter)
+{
+ void *p =cs;
+ p++;
+ return dbus_message_iter_get_element_type(iter);
+}
+
+void
+dbus_svc_message_get_elements( DBusConnectionState *cs , dbus_svc_MessageIterator iter, uint32_t *n, void *array )
+{
+ void *p =cs;
+ p++;
+ dbus_message_iter_get_fixed_array( iter, n, array);
+}
+
+void dbus_svc_message_iterator_free( DBusConnectionState *cs, dbus_svc_MessageIterator iter )
+{
+ void *p =cs;
+ p++;
+ free( iter );
+}
+
+uint8_t dbus_svc_message_type( DBusMessage *msg )
+{
+ return dbus_message_get_type( msg );
+}
+
+static DBusConnectionState *
+dbcs_new( DBusConnection *connection )
+{
+ DBusConnectionState *dbcs = (DBusConnectionState *) malloc( sizeof(DBusConnectionState) );
+ if ( dbcs )
+ {
+ memset( dbcs, '\0', sizeof( DBusConnectionState ));
+ dbcs->connection = connection;
+ }
+ return(dbcs);
+}
+
+static DBusConnectionTimeout *
+timeout_new( DBusTimeout *timeout )
+{
+ DBusConnectionTimeout *to = (DBusConnectionTimeout *) malloc ( sizeof(DBusConnectionTimeout) );
+ if( to != 0L )
+ {
+ to->to = timeout;
+ dbus_timeout_set_data(timeout, to, 0L);
+ if( dbus_timeout_get_enabled(timeout) )
+ gettimeofday(&(to->tv),0L);
+ else
+ {
+ to->tv.tv_sec = 0 ;
+ to->tv.tv_usec = 0 ;
+ }
+ }
+ return( to );
+}
+
+static dbus_bool_t
+add_timeout( DBusTimeout *timeout, void *csp )
+{
+ DBusConnectionState *cs = csp;
+ DBusConnectionTimeout *to = timeout_new(timeout);
+ if( cs->dh != 0L ) (*(cs->dh))("add_timeout: %d", dbus_timeout_get_interval(timeout));
+ to->cs = cs;
+ if ( to )
+ {
+ if( tsearch((void*)to, &(cs->timeouts), ptr_key_comparator) != 0L )
+ return TRUE;
+ }
+ if( cs->eh != 0L ) (*(cs->eh))("add_timeout: out of memory");
+ return FALSE;
+}
+
+static void
+remove_timeout( DBusTimeout *timeout, void *csp )
+{
+ DBusConnectionState *cs = csp;
+ DBusConnectionTimeout *to = dbus_timeout_get_data(timeout);
+ if( (to != 0L) && (to->to == timeout) )
+ {
+ if( cs->dh != 0L ) (*(cs->dh))("remove_timeout: %d", dbus_timeout_get_interval(to->to));
+ if( tdelete((const void*)to, &(cs->timeouts), ptr_key_comparator) != 0L )
+ {
+ free(to);
+ }else
+ if( cs->eh != 0L ) (*(cs->eh))("remove_timeout: can't happen?!?: timeout data %p not found", to);
+ }else
+ if( cs->eh != 0L ) (*(cs->eh))("remove_timeout: can't happen?!?: timeout %p did not record data %p %p",
+ timeout, to, ((to != 0L) ? to->to : 0L)
+ );
+}
+
+static void
+toggle_timeout( DBusTimeout *timeout, void *csp )
+{
+ DBusConnectionState *cs = csp;
+ DBusConnectionTimeout **top = tfind( (const void*) dbus_timeout_get_data(timeout),
+ &(cs->timeouts),
+ ptr_key_comparator
+ ),
+ *to=0L;
+ if( (top != 0L) && ((to=*top) != 0L) && (to->to == timeout) )
+ {
+ if( cs->dh != 0L ) (*(cs->dh))("toggle_timeout: %d", dbus_timeout_get_interval(to->to));
+ if( dbus_timeout_get_enabled(timeout) )
+ gettimeofday(&(to->tv),0L);
+ else
+ {
+ to->tv.tv_sec = 0 ;
+ to->tv.tv_usec = 0 ;
+ }
+ }else
+ if( cs->eh != 0L ) (*(cs->eh))("toggle_timeout: can't happen?!?: timeout %p %s %p %p", timeout,
+ ((to==0L) ? "did not record data" : "not found"),
+ to, ((to != 0L) ? to->to : 0L)
+ );
+}
+
+static void
+process_timeout( const void *p, const VISIT which, const int level)
+{
+ DBusConnectionState *cs;
+ void * const *tpp = p;
+ DBusConnectionTimeout *to;
+ struct timeval tv;
+ float now, then, interval;
+ int l = level ? 1 : 0;
+ l=l;
+
+ gettimeofday(&tv,0L);
+
+ if( (tpp != 0L) && (*tpp != 0L) && ((which == postorder) || (which == leaf)) )
+ {
+ to = (DBusConnectionTimeout*)*tpp;
+ cs = to->cs;
+ if ( !dbus_timeout_get_enabled(to->to) )
+ return;
+ cs = dbus_timeout_get_data(to->to);
+ then = ((float)to->tv.tv_sec) + (((float)to->tv.tv_usec) / 1000000.0);
+ if( then != 0.0 )
+ {
+ interval = ((float)dbus_timeout_get_interval(to->to)) / 1000.0;
+ now = ((float)tv.tv_sec) + (( (float)tv.tv_usec) / 1000000.0);
+ if( (now - then) >= interval )
+ {
+ if( cs->dh != 0L ) (*(cs->dh))("handle_timeout: %d - %f %f %f", dbus_timeout_get_interval(to->to), then, now, interval);
+ dbus_timeout_handle( to->to );
+ to->tv=tv;
+ }
+ }else
+ {
+ to->tv = tv;
+ }
+ }
+}
+
+static void
+process_timeouts ( DBusConnectionState *cs )
+{
+ twalk( cs->timeouts, process_timeout );
+}
+
+static void
+set_watch_fds( DBusWatch *watch, DBusConnectionState *cs )
+{
+ uint8_t flags = dbus_watch_get_flags(watch);
+ int fd = dbus_watch_get_fd(watch);
+
+ if ( cs->n <= fd )
+ cs->n = fd + 1;
+
+ if ( dbus_watch_get_enabled(watch) )
+ {
+ if ( flags & DBUS_WATCH_READABLE )
+ {
+ FD_SET(fd , &(cs->r_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_ENABLE | WATCH_READ, cs->wh_arg );
+ }else
+ {
+ FD_CLR(fd , &(cs->r_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_READ, cs->wh_arg );
+ }
+
+ if ( flags & DBUS_WATCH_WRITABLE )
+ {
+ FD_SET(fd , &(cs->w_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_ENABLE | WATCH_WRITE, cs->wh_arg );
+ }else
+ {
+ FD_CLR(fd , &(cs->w_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_WRITE, cs->wh_arg );
+ }
+ if ( flags & DBUS_WATCH_ERROR )
+ {
+ FD_SET(fd , &(cs->e_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_ENABLE | WATCH_ERROR, cs->wh_arg );
+ }else
+ {
+ FD_CLR(fd , &(cs->e_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_ERROR, cs->wh_arg );
+ }
+ }else
+ {
+ if( FD_ISSET( fd, &(cs->r_fds)) )
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_READ, cs->wh_arg );
+ FD_CLR(fd , &(cs->r_fds));
+
+ if( FD_ISSET( fd, &(cs->w_fds)) )
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_WRITE, cs->wh_arg );
+ FD_CLR(fd , &(cs->w_fds));
+
+ if( FD_ISSET( fd, &(cs->e_fds)) )
+ if( cs->wh != 0L )
+ (*(cs->wh))( fd, WATCH_ERROR, cs->wh_arg );
+ FD_CLR(fd , &(cs->e_fds));
+ }
+}
+
+static dbus_bool_t
+add_watch ( DBusWatch *watch, void *csp )
+{
+ DBusConnectionState *cs = csp;
+
+ dbus_watch_set_data(watch, cs, no_free );
+ if( cs->dh != 0L ) (*(cs->dh))("add_watch: %d", dbus_watch_get_fd(watch));
+ if( tsearch((const void*)watch,&(cs->watches),ptr_key_comparator) == 0L )
+ {
+ if( cs->eh != 0L ) (*(cs->eh))("add_watch: out of memory");
+ return FALSE;
+ }
+ set_watch_fds(watch,cs);
+ return TRUE;
+}
+
+static void
+remove_watch ( DBusWatch *watch, void *csp )
+{
+ DBusConnectionState *cs = csp;
+ int fd = dbus_watch_get_fd(watch);
+ if( tdelete((const void*)watch, &(cs->watches), ptr_key_comparator) == 0L )
+ if( cs->eh != 0L ) (*(cs->eh))("remove_watch: can't happen?!?: watch not found");
+ if( cs->dh != 0L ) (*(cs->dh))("remove_watch: %d", dbus_watch_get_fd(watch));
+ FD_CLR(fd , &(cs->r_fds));
+ FD_CLR(fd , &(cs->w_fds));
+ FD_CLR(fd , &(cs->e_fds));
+ if( cs->wh != 0L )
+ (*(cs->wh))(dbus_watch_get_fd(watch), WATCH_READ | WATCH_WRITE | WATCH_ERROR, cs->wh_arg );
+}
+
+static void
+toggle_watch ( DBusWatch *watch, void *csp )
+{
+ DBusConnectionState *cs = csp;
+ if( cs->dh != 0L ) (*(cs->dh))("toggle_watch: %d", dbus_watch_get_fd(watch));
+ set_watch_fds(watch,cs);
+}
+
+static void
+process_watch( const void *p, const VISIT which, const int level)
+{
+ void * const *wpp=p;
+ DBusWatch *w;
+ int fd;
+ uint8_t flags;
+ DBusConnectionState *cs;
+ int l = level ? 1 : 0;
+ l=l;
+
+ if((wpp != 0L) && (*wpp != 0L) && ( (which == postorder) || (which == leaf) ) )
+ {
+ w = (DBusWatch*)*wpp;
+ cs = dbus_watch_get_data( w );
+ if( cs == 0 )
+ return;
+ if( ! dbus_watch_get_enabled(w) )
+ return;
+ fd = dbus_watch_get_fd( w );
+ flags = dbus_watch_get_flags( w );
+ if( cs->dh != 0L ) (*(cs->dh))("handle_watch: %d", dbus_watch_get_fd( w ));
+ if ( (flags & DBUS_WATCH_READABLE) && (FD_ISSET(fd, &(cs->s_r_fds))) )
+ dbus_watch_handle(w, DBUS_WATCH_READABLE);
+ if ( (flags & DBUS_WATCH_WRITABLE) && (FD_ISSET(fd, &(cs->s_w_fds))) )
+ dbus_watch_handle(w, DBUS_WATCH_READABLE);
+ if ( (flags & DBUS_WATCH_ERROR) && (FD_ISSET(fd, &(cs->s_e_fds))) )
+ dbus_watch_handle(w, DBUS_WATCH_ERROR);
+ }
+}
+
+static void
+process_watches ( DBusConnectionState *cs )
+{
+ twalk( cs->watches, process_watch );
+}
+
+void dbus_svc_handle_watch( DBusConnectionState *cs, int fd, dbus_svc_WatchFlags action )
+{
+ switch( action & 7 )
+ {
+ case WATCH_READ:
+ FD_SET(fd, &(cs->s_r_fds));
+ break;
+
+ case WATCH_WRITE:
+ FD_SET(fd, &(cs->s_w_fds));
+ break;
+
+ case WATCH_ERROR:
+ FD_SET(fd, &(cs->s_e_fds));
+ break;
+ }
+}
+
+static void
+dispatch_status
+( DBusConnection *connection,
+ DBusDispatchStatus new_status,
+ void *csp
+)
+{
+ connection=connection;
+ DBusConnectionState *cs = csp;
+ cs->dispatchStatus = new_status;
+}
+
+void
+dbus_svc_main_loop( DBusConnectionState *cs, void (*idle_handler)(DBusConnectionState *) )
+{
+ struct timeval timeout={0,200000};
+ int n_fds;
+
+ while( cs->status != SHUTDOWN )
+ {
+ cs->s_r_fds = cs->r_fds;
+ cs->s_w_fds = cs->w_fds;
+ cs->s_e_fds = cs->e_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec= 200000;
+
+ if ( (n_fds = select(cs->n, &(cs->s_r_fds), &(cs->s_w_fds), &(cs->s_e_fds), &timeout)) < 0 )
+ {
+ if (errno != EINTR)
+ {
+ if( cs->eh != 0L ) (*(cs->eh))( "select failed: %d : %s", errno, strerror(errno));
+ return;
+ }
+ }
+
+ if( n_fds > 0 )
+ process_watches(cs);
+
+ process_timeouts(cs);
+
+ if ( cs->dispatchStatus != DBUS_DISPATCH_COMPLETE )
+ dbus_connection_dispatch( cs->connection );
+
+ if( idle_handler != 0L )
+ (*idle_handler)(cs);
+ }
+}
+
+void dbus_svc_dispatch(DBusConnectionState *cs)
+{
+ process_watches(cs);
+
+ FD_ZERO(&(cs->s_r_fds));
+ FD_ZERO(&(cs->s_w_fds));
+ FD_ZERO(&(cs->s_e_fds));
+
+ process_timeouts(cs);
+
+ while ( cs->dispatchStatus != DBUS_DISPATCH_COMPLETE )
+ dbus_connection_dispatch( cs->connection );
+}
+
+void
+dbus_svc_quit( DBusConnectionState *cs )
+{
+ cs->status = SHUTDOWN;
+}
+
+static isc_result_t
+connection_setup
+( DBusConnection *connection,
+ DBUS_SVC *dbus,
+ dbus_svc_WatchHandler wh,
+ dbus_svc_ErrorHandler eh,
+ dbus_svc_ErrorHandler dh,
+ void *wh_arg
+)
+{
+ *dbus = dbcs_new( connection );
+
+ if ( *dbus == 0L )
+ {
+ if(eh)(*(eh))("connection_setup: out of memory");
+ goto fail;
+ }
+ (*dbus)->wh = wh;
+ (*dbus)->wh_arg = wh_arg;
+ (*dbus)->eh = eh;
+ (*dbus)->dh = dh;
+
+ if (!dbus_connection_set_watch_functions
+ ( (*dbus)->connection,
+ add_watch,
+ remove_watch,
+ toggle_watch,
+ *dbus,
+ no_free
+ )
+ )
+ {
+ if( (*dbus)->eh != 0L ) (*((*dbus)->eh))("connection_setup: dbus_connection_set_watch_functions failed");
+ goto fail;
+ }
+
+ if (!dbus_connection_set_timeout_functions
+ ( connection,
+ add_timeout,
+ remove_timeout,
+ toggle_timeout,
+ *dbus,
+ no_free
+ )
+ )
+ {
+ if( (*dbus)->eh != 0L ) (*((*dbus)->eh))("connection_setup: dbus_connection_set_timeout_functions failed");
+ goto fail;
+ }
+
+ dbus_connection_set_dispatch_status_function
+ ( connection,
+ dispatch_status,
+ *dbus,
+ no_free
+ );
+
+ if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
+ dbus_connection_ref(connection);
+
+ return ISC_R_SUCCESS;
+
+ fail:
+ if( *dbus != 0L )
+ free(*dbus);
+
+ dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
+ dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL);
+ dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL);
+
+ return ISC_R_FAILURE;
+}
+
+isc_result_t
+dbus_svc_init
+(
+ dbus_svc_DBUS_TYPE bus,
+ char *name,
+ DBUS_SVC *dbus,
+ dbus_svc_WatchHandler wh ,
+ dbus_svc_ErrorHandler eh ,
+ dbus_svc_ErrorHandler dh ,
+ void *wh_arg
+)
+{
+ DBusConnection *connection;
+ DBusError error;
+ char *session_bus_address=0L;
+
+ memset(&error,'\0',sizeof(DBusError));
+
+ dbus_error_init(&error);
+
+ switch( bus )
+ {
+ /* DBUS_PRIVATE_* bus types are the only type which allow reconnection if the dbus-daemon is restarted
+ */
+ case DBUS_PRIVATE_SYSTEM:
+
+ if ( (connection = dbus_connection_open_private("unix:path=/var/run/dbus/system_bus_socket", &error)) == 0L )
+ {
+ if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message);
+ return ISC_R_FAILURE;
+ }
+
+ if ( ! dbus_bus_register(connection,&error) )
+ {
+ if(eh)(*eh)("dbus_bus_register failed: %s %s", error.name, error.message);
+ dbus_connection_close(connection);
+ free(connection);
+ return ISC_R_FAILURE;
+ }
+ break;
+
+ case DBUS_PRIVATE_SESSION:
+
+ session_bus_address = getenv("DBUS_SESSION_BUS_ADDRESS");
+ if ( session_bus_address == 0L )
+ {
+ if(eh)(*eh)("dbus_svc_init failed: DBUS_SESSION_BUS_ADDRESS environment variable not set");
+ return ISC_R_FAILURE;
+ }
+
+ if ( (connection = dbus_connection_open_private(session_bus_address, &error)) == 0L )
+ {
+ if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message);
+ return ISC_R_FAILURE;
+ }
+
+ if ( ! dbus_bus_register(connection,&error) )
+ {
+ if(eh)(*eh)("dbus_bus_register failed: %s %s", error.name, error.message);
+ dbus_connection_close(connection);
+ free(connection);
+ return ISC_R_FAILURE;
+ }
+ break;
+
+ case DBUS_SYSTEM:
+ case DBUS_SESSION:
+
+ if ( (connection = dbus_bus_get (bus, &error)) == 0L )
+ {
+ if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message);
+ return ISC_R_FAILURE;
+ }
+ break;
+
+ default:
+ if(eh)(*eh)("dbus_svc_init failed: unknown bus type %d", bus);
+ return ISC_R_FAILURE;
+ }
+
+ dbus_connection_set_exit_on_disconnect(connection, FALSE);
+
+ if ( (connection_setup(connection, dbus, wh, eh, dh, wh_arg)) != ISC_R_SUCCESS)
+ {
+ if(eh)(*eh)("dbus_svc_init failed: connection_setup failed");
+ return ISC_R_FAILURE;
+ }
+
+ if( name == 0L )
+ return ISC_R_SUCCESS;
+
+ (*dbus)->unique_name = dbus_bus_get_unique_name(connection);
+
+ switch
+ ( dbus_bus_request_name
+ ( connection, name,
+#ifdef DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT
+ DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT ,
+#else
+ 0 ,
+#endif
+ &error
+ )
+ )
+ {
+ case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ break;
+ case DBUS_REQUEST_NAME_REPLY_EXISTS:
+ case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+ if(eh)(*eh)("dbus_svc_init: dbus_bus_request_name failed: Name already registered");
+ goto give_up;
+ default:
+ if(eh)(*eh)("dbus_svc_init: dbus_bus_request_name failed: %s %s", error.name, error.message);
+ goto give_up;
+ }
+ return ISC_R_SUCCESS;
+
+ give_up:
+ dbus_connection_close( connection );
+ dbus_connection_unref( connection );
+ if( *dbus )
+ {
+ dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
+ dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL);
+ dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL);
+ free(*dbus);
+ }
+ return ISC_R_FAILURE;
+}
+
+const char *dbus_svc_unique_name(DBusConnectionState *cs)
+{
+ return cs->unique_name;
+}
+
+void
+dbus_svc_shutdown ( DBusConnectionState *cs )
+{
+ if (!dbus_connection_set_watch_functions
+ ( cs->connection,
+ NULL, NULL, NULL, NULL, NULL
+ )
+ ) if( cs->eh != 0L ) (*(cs->eh))("connection_shutdown: dbus_connection_set_watch_functions: No Memory."
+ "Setting watch functions to NULL failed."
+ );
+
+ if (!dbus_connection_set_timeout_functions
+ ( cs->connection,
+ NULL, NULL, NULL, NULL, NULL
+ )
+ ) if( cs->eh != 0L ) (*(cs->eh))("connection_shutdown: dbus_connection_set_timeout_functions: No Memory."
+ "Setting timeout functions to NULL failed."
+ );
+
+ dbus_connection_set_dispatch_status_function (cs->connection, NULL, NULL, NULL);
+
+ tdestroy( cs->timeouts, free);
+ cs->timeouts=0L;
+ tdestroy( cs->watches, no_free);
+ cs->watches=0L;
+
+ dbus_connection_close( cs->connection );
+ dbus_connection_unref( cs->connection );
+
+ free( cs );
+}