1/*	$NetBSD: dbus_service.c,v 1.2 2011/02/16 03:46:54 christos Exp $	*/
2
3/*  dbus_service.c
4 *
5 *  D-BUS Service Utilities
6 *
7 *  Provides MINIMAL utilities for construction of D-BUS "Services".
8 *
9 *  Copyright(C) Jason Vas Dias, Red Hat Inc., 2005
10 *  Modified by Adam Tkac, Red Hat Inc., 2007
11 *
12 *  This program is free software; you can redistribute it and/or modify
13 *  it under the terms of the GNU General Public License as published by
14 *  the Free Software Foundation at
15 *           http://www.fsf.org/licensing/licenses/gpl.txt
16 *  and included in this software distribution as the "LICENSE" file.
17 *
18 *  This program is distributed in the hope that it will be useful,
19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *  GNU General Public License for more details.
22 *
23 */
24
25#include <sys/types.h>
26#include <unistd.h>
27#include <linux/limits.h>
28#include <sys/time.h>
29#include <sys/socket.h>
30#include <sys/select.h>
31#include <sys/wait.h>
32#include <sys/ioctl.h>
33#include <time.h>
34#include <signal.h>
35#include <syslog.h>
36#include <fcntl.h>
37#include <string.h>
38extern size_t strnlen(const char *s, size_t maxlen);
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#include <netdb.h>
42#include <ifaddrs.h>
43#include <search.h>
44#include <getopt.h>
45typedef void (*__free_fn_t) (void *__nodep);
46extern void tdestroy (void *__root, __free_fn_t __freefct);
47#include <stdint.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <stdarg.h>
51#include <errno.h>
52#define  DBUS_API_SUBJECT_TO_CHANGE  "Very Annoying and Silly!"
53#include <dbus/dbus.h>
54
55#include <named/dbus_service.h>
56#include <isc/result.h>
57
58typedef struct dbcs_s
59{
60    DBusConnection *connection;
61    DBusDispatchStatus dispatchStatus;
62    uint32_t        status;
63    dbus_svc_WatchHandler wh;
64    void *          wh_arg;
65    const char    * unique_name;
66    dbus_svc_MessageHandler mh;
67    void          * def_mh_obj;
68    dbus_svc_MessageHandler mf;
69    void          * def_mf_obj;
70    dbus_svc_ShutdownHandler sh;
71    void          * sh_obj;
72    dbus_svc_ErrorHandler eh;
73    dbus_svc_ErrorHandler dh;
74    /*{ glibc b-trees: */
75    void *          roots;
76    void *          timeouts;
77    void *          watches;
78    void *          filters;
79    /*}*/
80    int             n;
81    fd_set          r_fds;
82    fd_set          s_r_fds;
83    fd_set          w_fds;
84    fd_set          s_w_fds;
85    fd_set          e_fds;
86    fd_set          s_e_fds;
87    DBusMessage     *currentMessage;
88    int             rejectMessage;
89} DBusConnectionState;
90
91typedef struct root_s
92{
93    char *path;
94    char *if_prefix;
95    DBUS_SVC cs;
96    dbus_svc_MessageHandler mh;
97    void *object;
98    void *tree;
99} Root;
100
101typedef struct mhn_s
102{
103    char *path;
104    dbus_svc_MessageHandler mh;
105    void *object;
106} MessageHandlerNode;
107
108typedef struct mfn_s
109{
110    DBusConnectionState *cs;
111    dbus_svc_MessageHandler mf;
112    void *obj;
113    int n_matches;
114    char **matches;
115} MessageFilterNode;
116
117typedef struct dbto_s
118{
119    DBusTimeout   *to;
120    DBusConnectionState *cs;
121    struct timeval tv;
122} DBusConnectionTimeout;
123
124static void no_free( void *p){ p=0; }
125
126static int ptr_key_comparator( const void *p1, const void *p2 )
127{
128    return
129	(  (p1 == p2)
130	   ? 0
131	   :( (p1 > p2)
132	      ? 1
133	      : -1
134	    )
135	);
136}
137
138static DBusHandlerResult
139default_message_filter
140(   DBusConnection     *connection,
141    DBusMessage        *message,
142    void               *p
143)
144{
145    DBusConnectionState *cs = p;
146    uint32_t type  =dbus_message_get_type( message ),
147	   serial  =dbus_message_get_serial( message );
148    uint8_t  reply =dbus_message_get_no_reply( message )==0;
149    const char
150	*path =    dbus_message_get_path( message ),
151	*dest =    dbus_message_get_destination( message ),
152	*member =  dbus_message_get_member( message ),
153	*interface=dbus_message_get_interface( message ),
154	*sender   =dbus_message_get_sender( message ),
155	*signature=dbus_message_get_signature( message );
156    connection = connection;
157    if(cs->mf)
158	return
159	(*(cs->mf))( cs, type, reply, serial, dest, path, member, interface, 0L,
160		    sender, signature, message, 0L, 0L, 0L, cs->def_mf_obj
161	          ) ;
162    return HANDLED;
163}
164
165uint8_t
166dbus_svc_add_filter
167(  DBusConnectionState *cs, dbus_svc_MessageHandler mh, void *obj, int n_matches, ... )
168{
169    DBusError error;
170    va_list va;
171    char *m;
172
173    va_start(va, n_matches );
174
175    cs->mf = mh;
176    cs->def_mf_obj = obj;
177
178    if ( ! dbus_connection_add_filter (cs->connection, default_message_filter, cs, NULL))
179    {
180	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_add_filter: dbus_connection_add_filter failed");
181	va_end(va);
182	return( 0 );
183    }
184
185    if( n_matches )
186    {
187	memset(&error,'\0',sizeof(DBusError));
188	dbus_error_init(&error);
189	while( n_matches-- )
190	{
191	    m = va_arg(va, char* ) ;
192
193	    dbus_bus_add_match(cs->connection, m, &error);
194
195	    if( dbus_error_is_set(&error))
196	    {
197		if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_add_filter: dbus_bus_add_match failed for %s: %s %s",
198					       m, error.name, error.message
199		                              );
200		va_end(va);
201		return(0);
202	    }
203	}
204    }
205    va_end(va);
206    return( 1 );
207}
208
209
210uint8_t
211dbus_svc_get_args_va(DBusConnectionState *cs, DBusMessage* msg, dbus_svc_DataType firstType, va_list va)
212{
213    DBusError error;
214    memset(&error,'\0',sizeof(DBusError));
215    dbus_error_init(&error);
216    if( (!dbus_message_get_args_valist(msg, &error, firstType, va)) || dbus_error_is_set(&error) )
217    {
218	if(  dbus_error_is_set(&error) )
219	{
220	    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_get_args failed: %s %s",error.name, error.message);
221	    dbus_error_free(&error);
222	}else
223	    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_get_args failed: dbus_message_get_args_valist failed");
224	return( 0 );
225    }
226    return( 1 );
227}
228
229uint8_t
230dbus_svc_get_args(DBusConnectionState *cs, DBusMessage* msg, dbus_svc_DataType firstType, ...)
231{
232    va_list va;
233    uint8_t r;
234    va_start(va, firstType);
235    r = dbus_svc_get_args_va( cs, msg, firstType, va);
236    va_end(va);
237    return r;
238}
239
240uint8_t
241dbus_svc_send_va
242(  DBusConnectionState *cs,
243   dbus_svc_MessageType type,
244   int32_t reply_serial,
245   uint32_t *new_serial,
246   const char *destination,
247   const char *path,
248   const char *interface,
249   const char *member,
250   dbus_svc_DataType firstType,
251   va_list va
252)
253{
254    DBusMessageIter iter;
255    char *e;
256    DBusMessage *msg =
257	dbus_svc_new_message
258	(   cs,
259	    type,
260	    reply_serial,
261	    destination,
262	    path,
263	    interface,
264	    member
265	);
266
267    if(msg == 0L)
268    {
269	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_svc_new_message failed");
270	return 0;
271    }
272
273    if( type != DBUS_MESSAGE_TYPE_ERROR )
274    {
275	if( !dbus_message_append_args_valist( msg, firstType, va ) )
276	{
277	    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_append_args_valist failed");
278	    return 0;
279	}
280    }else
281    {
282	if( firstType == DBUS_TYPE_STRING )
283	{
284	    e = 0L;
285	    e = va_arg( va, char* );
286	    if( (e == 0L) ||  !dbus_message_set_error_name( msg, e ) )
287	    {
288		if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_set_error_name failed");
289		return 0;
290	    }
291	    firstType = va_arg(va, int);
292	    if( firstType == DBUS_TYPE_STRING )
293	    {
294		e = 0L;
295		e =  va_arg( va, char* );
296		if( e == 0L )
297		{
298		    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: NULL error message");
299		    return 0;
300		}
301		dbus_message_iter_init_append (msg, &iter);
302		if( !dbus_message_iter_append_basic
303		    (&iter, DBUS_TYPE_STRING, &e)
304		  )
305		{
306		    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_iter_append_basic failed");
307		    return 0;
308		}
309	    }
310	}else
311	{
312	    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: unhandled type for error name: %c", firstType);
313	    return 0;
314	}
315    }
316
317    if( !dbus_connection_send(cs->connection, msg, new_serial) )
318    {
319	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_send failed");
320	return 0;
321    }
322    if( cs->dh != 0L ) (*(cs->dh))("Sending message");
323    dbus_connection_flush(cs->connection);
324    return 1;
325}
326
327uint8_t
328dbus_svc_send
329(  DBusConnectionState *cs,
330   dbus_svc_MessageType type,
331   int32_t reply_serial,
332   uint32_t *new_serial,
333   const char *destination,
334   const char *path,
335   const char *interface,
336   const char *member,
337   dbus_svc_DataType firstType,
338   ...
339)
340{
341    uint8_t r;
342    va_list va;
343    va_start(va, firstType);
344    r = dbus_svc_send_va(cs, type, reply_serial, new_serial, destination, path,interface,member,firstType,va);
345    va_end(va);
346    return ( r ) ;
347}
348
349dbus_svc_MessageHandle
350dbus_svc_new_message
351( DBusConnectionState* cs,
352  dbus_svc_MessageType type,
353  int32_t reply_serial,
354  const char *destination,
355  const char *path,
356  const char *interface,
357  const char *member
358)
359{
360    DBusMessage *msg = dbus_message_new(type);
361
362    if( msg == 0L)
363    {
364	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_reply_serial failed");
365	return 0;
366    }
367
368    if( reply_serial != -1 )
369    {
370	if( !dbus_message_set_reply_serial(msg,reply_serial) )
371	{
372	    if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_reply_serial failed");
373	    return 0;
374	}
375    }
376
377    if( (destination !=0L) && !dbus_message_set_destination(msg, destination) )
378    {
379	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_destination failed");
380	return 0;
381    }
382
383    if( !dbus_message_set_path(msg, path) )
384    {
385	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_path failed");
386	return 0;
387    }
388
389    if( ! dbus_message_set_interface(msg,interface) )
390    {
391	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_interface failed - %s", interface);
392	return 0;
393    }
394
395    if( !dbus_message_set_member(msg,member) )
396    {
397	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_member failed");
398	return 0;
399    }
400
401    return msg;
402}
403
404extern uint8_t
405dbus_svc_send_message
406(
407    DBusConnectionState *cs,
408    dbus_svc_MessageHandle msg,
409    uint32_t *new_serial
410)
411{
412    if( !dbus_connection_send(cs->connection, msg, new_serial) )
413    {
414	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_send failed");
415	return 0;
416    }
417    if( cs->dh != 0L ) (*(cs->dh))("Sending message");
418    dbus_connection_flush(cs->connection);
419    return 1;
420}
421
422uint8_t
423dbus_svc_message_append_args(DBusConnectionState *cs, dbus_svc_MessageHandle msg, dbus_svc_DataType firstType, ...)
424{
425    va_list va;
426    va_start(va, firstType);
427    if( !dbus_message_append_args_valist( msg, firstType, va ) )
428    {
429	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_append_args failed");
430	va_end(va);
431	return 0;
432    }
433    va_end(va);
434    return ( 1 ) ;
435}
436
437dbus_svc_MessageHandle
438dbus_svc_call
439( DBusConnectionState *cs,
440  const char *destination,
441  const char *path,
442  const char *member,
443  const char *interface,
444  dbus_svc_DataType firstType,
445  ...
446)
447{
448    DBusMessage *message=0L, *reply=0L;
449    va_list va;
450    DBusError error;
451    int reply_timeout=20000;
452
453    va_start(va, firstType);
454
455    memset(&error,'\0',sizeof(DBusError));
456    dbus_error_init(&error);
457
458    if(( message =
459	 dbus_message_new_method_call
460	 (  destination,
461	    path,
462	    interface,
463	    member
464	 )
465       ) == 0L
466      )
467    {
468	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_new_method_call failed");
469	va_end(va);
470	return(0L);
471    };
472
473    if( !dbus_message_append_args_valist( message, firstType, va ) )
474    {
475	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_append_args_valist failed");
476	va_end(va);
477	return(0L);
478    }
479
480    if((reply =
481	dbus_connection_send_with_reply_and_block
482	(cs->connection,
483	 message, reply_timeout,
484	 &error
485	)
486       ) == 0L
487      )
488    {
489	if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_send_with_reply_and_block failed: %s %s",
490		    error.name, error.message
491	           );
492	va_end(va);
493	return(0L);
494    }
495    va_end(va);
496    return reply;
497}
498
499dbus_svc_MessageIterator
500dbus_svc_message_iterator_new( DBusConnectionState *cs, DBusMessage *msg)
501{
502    DBusMessageIter *iter = malloc( sizeof(DBusMessageIter) );
503    void *p =cs;
504    p++;
505    if( iter != 0L )
506    {
507	if( !dbus_message_iter_init( msg, iter ))
508	{
509	    free( iter ) ;
510	    iter = 0L;
511	}
512    }
513    return iter;
514}
515
516uint32_t
517dbus_svc_message_next_arg_type( DBusConnectionState *cs, dbus_svc_MessageIterator iter )
518{
519    void *p =cs;
520    p++;
521    return dbus_message_iter_get_arg_type( iter );
522}
523
524void
525dbus_svc_message_next_arg( DBusConnectionState *cs, dbus_svc_MessageIterator iter, void *value )
526{
527    void *p =cs;
528    p++;
529    dbus_message_iter_get_basic( iter, value );
530    dbus_message_iter_next( iter );
531}
532
533uint32_t
534dbus_svc_message_element_type(DBusConnectionState *cs , dbus_svc_MessageIterator  iter)
535{
536    void *p =cs;
537    p++;
538    return dbus_message_iter_get_element_type(iter);
539}
540
541void
542dbus_svc_message_get_elements( DBusConnectionState *cs , dbus_svc_MessageIterator  iter, uint32_t *n, void *array )
543{
544    void *p =cs;
545    p++;
546    dbus_message_iter_get_fixed_array( iter, n, array);
547}
548
549void dbus_svc_message_iterator_free(  DBusConnectionState *cs, dbus_svc_MessageIterator iter )
550{
551    void *p =cs;
552    p++;
553    free( iter );
554}
555
556uint8_t dbus_svc_message_type(  DBusMessage *msg )
557{
558    return dbus_message_get_type( msg );
559}
560
561static DBusConnectionState *
562dbcs_new( DBusConnection *connection )
563{
564    DBusConnectionState *dbcs = (DBusConnectionState *) malloc( sizeof(DBusConnectionState) );
565    if ( dbcs )
566    {
567	memset( dbcs, '\0', sizeof( DBusConnectionState ));
568	dbcs->connection = connection;
569    }
570    return(dbcs);
571}
572
573static DBusConnectionTimeout *
574timeout_new( DBusTimeout *timeout )
575{
576    DBusConnectionTimeout *to = (DBusConnectionTimeout *) malloc ( sizeof(DBusConnectionTimeout) );
577    if( to != 0L )
578    {
579	to->to = timeout;
580	dbus_timeout_set_data(timeout, to, 0L);
581	if( dbus_timeout_get_enabled(timeout) )
582	    gettimeofday(&(to->tv),0L);
583	else
584	{
585	    to->tv.tv_sec = 0 ;
586	    to->tv.tv_usec = 0 ;
587	}
588    }
589    return( to );
590}
591
592static dbus_bool_t
593add_timeout( DBusTimeout *timeout, void *csp )
594{
595    DBusConnectionState   *cs = csp;
596    DBusConnectionTimeout *to = timeout_new(timeout);
597    if( cs->dh != 0L ) (*(cs->dh))("add_timeout: %d", dbus_timeout_get_interval(timeout));
598    to->cs = cs;
599    if ( to )
600    {
601	if( tsearch((void*)to, &(cs->timeouts), ptr_key_comparator) != 0L )
602	    return TRUE;
603    }
604    if( cs->eh != 0L ) (*(cs->eh))("add_timeout: out of memory");
605    return FALSE;
606}
607
608static void
609remove_timeout( DBusTimeout *timeout, void *csp )
610{
611    DBusConnectionState   *cs = csp;
612    DBusConnectionTimeout *to = dbus_timeout_get_data(timeout);
613    if( (to != 0L) && (to->to == timeout) )
614    {
615	if( cs->dh != 0L ) (*(cs->dh))("remove_timeout: %d", dbus_timeout_get_interval(to->to));
616	if( tdelete((const void*)to, &(cs->timeouts), ptr_key_comparator) != 0L )
617	{
618	    free(to);
619	}else
620	    if( cs->eh != 0L ) (*(cs->eh))("remove_timeout: can't happen?!?: timeout data %p not found", to);
621    }else
622	if( cs->eh != 0L ) (*(cs->eh))("remove_timeout: can't happen?!?: timeout %p did not record data %p %p",
623		    timeout, to, ((to != 0L) ? to->to : 0L)
624	           );
625}
626
627static void
628toggle_timeout( DBusTimeout *timeout, void *csp )
629{
630    DBusConnectionState   *cs = csp;
631    DBusConnectionTimeout **top = tfind( (const void*) dbus_timeout_get_data(timeout),
632				         &(cs->timeouts),
633				         ptr_key_comparator
634	                               ),
635	                   *to=0L;
636    if( (top != 0L) && ((to=*top) != 0L) && (to->to == timeout) )
637    {
638	if( cs->dh != 0L ) (*(cs->dh))("toggle_timeout: %d", dbus_timeout_get_interval(to->to));
639	if(  dbus_timeout_get_enabled(timeout) )
640	    gettimeofday(&(to->tv),0L);
641	else
642	{
643	    to->tv.tv_sec = 0 ;
644	    to->tv.tv_usec = 0 ;
645	}
646    }else
647	if( cs->eh != 0L ) (*(cs->eh))("toggle_timeout: can't happen?!?: timeout %p %s %p %p", timeout,
648		    ((to==0L) ? "did not record data" : "not found"),
649		    to, ((to != 0L) ? to->to : 0L)
650	           );
651}
652
653static void
654process_timeout( const void *p, const VISIT which, const int level)
655{
656    DBusConnectionState   *cs;
657    void * const *tpp = p;
658    DBusConnectionTimeout *to;
659    struct timeval tv;
660    float now, then, interval;
661    int l = level ? 1 : 0;
662    l=l;
663
664    gettimeofday(&tv,0L);
665
666    if( (tpp != 0L) && (*tpp != 0L) && ((which == postorder) || (which == leaf)) )
667    {
668	to = (DBusConnectionTimeout*)*tpp;
669	cs = to->cs;
670	if ( !dbus_timeout_get_enabled(to->to) )
671	    return;
672	cs = dbus_timeout_get_data(to->to);
673	then = ((float)to->tv.tv_sec) + (((float)to->tv.tv_usec)  / 1000000.0);
674	if( then != 0.0 )
675	{
676	    interval = ((float)dbus_timeout_get_interval(to->to)) / 1000.0;
677	    now = ((float)tv.tv_sec) + (( (float)tv.tv_usec) /   1000000.0);
678	    if( (now - then) >= interval )
679	    {
680		if( cs->dh != 0L ) (*(cs->dh))("handle_timeout: %d - %f %f %f",  dbus_timeout_get_interval(to->to), then, now, interval);
681		dbus_timeout_handle( to->to );
682		to->tv=tv;
683	    }
684	}else
685	{
686	    to->tv = tv;
687	}
688    }
689}
690
691static void
692process_timeouts ( DBusConnectionState *cs )
693{
694    twalk( cs->timeouts, process_timeout );
695}
696
697static void
698set_watch_fds( DBusWatch *watch, DBusConnectionState *cs )
699{
700    uint8_t flags = dbus_watch_get_flags(watch);
701    int fd = dbus_watch_get_fd(watch);
702
703    if ( cs->n <= fd )
704	cs->n = fd + 1;
705
706    if ( dbus_watch_get_enabled(watch) )
707    {
708	if ( flags & DBUS_WATCH_READABLE )
709	{
710	    FD_SET(fd , &(cs->r_fds));
711	    if( cs->wh != 0L )
712		(*(cs->wh))( fd, WATCH_ENABLE | WATCH_READ, cs->wh_arg );
713	}else
714	{
715	    FD_CLR(fd , &(cs->r_fds));
716	    if( cs->wh != 0L )
717		(*(cs->wh))( fd, WATCH_READ, cs->wh_arg );
718	}
719
720	if ( flags & DBUS_WATCH_WRITABLE )
721	{
722	    FD_SET(fd , &(cs->w_fds));
723	    if( cs->wh != 0L )
724		(*(cs->wh))( fd, WATCH_ENABLE | WATCH_WRITE, cs->wh_arg );
725	}else
726	{
727	    FD_CLR(fd , &(cs->w_fds));
728	    if( cs->wh != 0L )
729		(*(cs->wh))( fd, WATCH_WRITE, cs->wh_arg );
730	}
731	if ( flags & DBUS_WATCH_ERROR )
732	{
733	    FD_SET(fd , &(cs->e_fds));
734	    if( cs->wh != 0L )
735		(*(cs->wh))( fd, WATCH_ENABLE | WATCH_ERROR, cs->wh_arg );
736	}else
737	{
738	    FD_CLR(fd , &(cs->e_fds));
739	    if( cs->wh != 0L )
740		(*(cs->wh))( fd, WATCH_ERROR, cs->wh_arg );
741	}
742    }else
743    {
744	if( FD_ISSET( fd, &(cs->r_fds)) )
745	    if( cs->wh != 0L )
746		(*(cs->wh))( fd, WATCH_READ, cs->wh_arg );
747	FD_CLR(fd , &(cs->r_fds));
748
749	if( FD_ISSET( fd, &(cs->w_fds)) )
750	    if( cs->wh != 0L )
751		(*(cs->wh))( fd, WATCH_WRITE, cs->wh_arg );
752	FD_CLR(fd , &(cs->w_fds));
753
754	if( FD_ISSET( fd, &(cs->e_fds)) )
755	    if( cs->wh != 0L )
756		(*(cs->wh))( fd, WATCH_ERROR, cs->wh_arg );
757	FD_CLR(fd , &(cs->e_fds));
758    }
759}
760
761static dbus_bool_t
762add_watch ( DBusWatch *watch, void *csp )
763{
764    DBusConnectionState *cs = csp;
765
766    dbus_watch_set_data(watch, cs, no_free );
767    if( cs->dh != 0L ) (*(cs->dh))("add_watch: %d", dbus_watch_get_fd(watch));
768    if( tsearch((const void*)watch,&(cs->watches),ptr_key_comparator) == 0L )
769    {
770	if( cs->eh != 0L ) (*(cs->eh))("add_watch: out of memory");
771	return FALSE;
772    }
773    set_watch_fds(watch,cs);
774    return TRUE;
775}
776
777static void
778remove_watch ( DBusWatch *watch, void *csp )
779{
780    DBusConnectionState *cs = csp;
781    int  fd = dbus_watch_get_fd(watch);
782    if( tdelete((const void*)watch, &(cs->watches), ptr_key_comparator) == 0L )
783	if( cs->eh != 0L ) (*(cs->eh))("remove_watch: can't happen?!?: watch not found");
784    if( cs->dh != 0L ) (*(cs->dh))("remove_watch: %d", dbus_watch_get_fd(watch));
785    FD_CLR(fd , &(cs->r_fds));
786    FD_CLR(fd , &(cs->w_fds));
787    FD_CLR(fd , &(cs->e_fds));
788    if( cs->wh != 0L )
789	(*(cs->wh))(dbus_watch_get_fd(watch), WATCH_READ | WATCH_WRITE | WATCH_ERROR, cs->wh_arg );
790}
791
792static void
793toggle_watch ( DBusWatch *watch, void *csp )
794{
795    DBusConnectionState *cs = csp;
796    if( cs->dh != 0L ) (*(cs->dh))("toggle_watch: %d", dbus_watch_get_fd(watch));
797    set_watch_fds(watch,cs);
798}
799
800static void
801process_watch( const void *p, const VISIT which, const int level)
802{
803    void * const *wpp=p;
804    DBusWatch *w;
805    int fd;
806    uint8_t flags;
807    DBusConnectionState *cs;
808    int l = level ? 1 : 0;
809    l=l;
810
811    if((wpp != 0L) && (*wpp != 0L) && ( (which == postorder) || (which == leaf) ) )
812    {
813	w = (DBusWatch*)*wpp;
814	cs = dbus_watch_get_data( w );
815	if( cs == 0 )
816	    return;
817	if( ! dbus_watch_get_enabled(w) )
818	    return;
819	fd = dbus_watch_get_fd( w );
820	flags = dbus_watch_get_flags( w );
821	if( cs->dh != 0L ) (*(cs->dh))("handle_watch: %d", dbus_watch_get_fd( w ));
822	if ( (flags & DBUS_WATCH_READABLE) && (FD_ISSET(fd, &(cs->s_r_fds))) )
823	    dbus_watch_handle(w, DBUS_WATCH_READABLE);
824	if ( (flags & DBUS_WATCH_WRITABLE) && (FD_ISSET(fd, &(cs->s_w_fds))) )
825	    dbus_watch_handle(w, DBUS_WATCH_READABLE);
826	if ( (flags & DBUS_WATCH_ERROR) && (FD_ISSET(fd, &(cs->s_e_fds))) )
827	    dbus_watch_handle(w, DBUS_WATCH_ERROR);
828    }
829}
830
831static void
832process_watches ( DBusConnectionState *cs )
833{
834    twalk( cs->watches, process_watch );
835}
836
837void dbus_svc_handle_watch(  DBusConnectionState *cs, int fd, dbus_svc_WatchFlags action )
838{
839    switch( action & 7 )
840    {
841    case WATCH_READ:
842	FD_SET(fd, &(cs->s_r_fds));
843	break;
844
845    case WATCH_WRITE:
846	FD_SET(fd, &(cs->s_w_fds));
847	break;
848
849    case WATCH_ERROR:
850	FD_SET(fd, &(cs->s_e_fds));
851	break;
852    }
853}
854
855static void
856dispatch_status
857(   DBusConnection *connection,
858    DBusDispatchStatus new_status,
859    void *csp
860)
861{
862    connection=connection;
863    DBusConnectionState *cs = csp;
864    cs->dispatchStatus = new_status;
865}
866
867void
868dbus_svc_main_loop( DBusConnectionState *cs, void (*idle_handler)(DBusConnectionState *) )
869{
870    struct timeval timeout={0,200000};
871    int n_fds;
872
873    while( cs->status != SHUTDOWN )
874    {
875	cs->s_r_fds = cs->r_fds;
876	cs->s_w_fds = cs->w_fds;
877	cs->s_e_fds = cs->e_fds;
878
879	timeout.tv_sec = 0;
880	timeout.tv_usec= 200000;
881
882	if ( (n_fds = select(cs->n, &(cs->s_r_fds), &(cs->s_w_fds), &(cs->s_e_fds), &timeout)) < 0 )
883	{
884	    if (errno != EINTR)
885	    {
886		if( cs->eh != 0L ) (*(cs->eh))( "select failed: %d : %s", errno, strerror(errno));
887	        return;
888	    }
889	}
890
891	if( n_fds > 0 )
892	    process_watches(cs);
893
894	process_timeouts(cs);
895
896	if ( cs->dispatchStatus != DBUS_DISPATCH_COMPLETE )
897	    dbus_connection_dispatch( cs->connection );
898
899	if( idle_handler != 0L )
900	    (*idle_handler)(cs);
901    }
902}
903
904void dbus_svc_dispatch(DBusConnectionState *cs)
905{
906    process_watches(cs);
907
908    FD_ZERO(&(cs->s_r_fds));
909    FD_ZERO(&(cs->s_w_fds));
910    FD_ZERO(&(cs->s_e_fds));
911
912    process_timeouts(cs);
913
914    while ( cs->dispatchStatus != DBUS_DISPATCH_COMPLETE )
915	dbus_connection_dispatch( cs->connection );
916}
917
918void
919dbus_svc_quit( DBusConnectionState *cs )
920{
921    cs->status = SHUTDOWN;
922}
923
924static isc_result_t
925connection_setup
926(   DBusConnection *connection,
927    DBUS_SVC *dbus,
928    dbus_svc_WatchHandler wh,
929    dbus_svc_ErrorHandler eh,
930    dbus_svc_ErrorHandler dh,
931    void *wh_arg
932)
933{
934    *dbus = dbcs_new( connection );
935
936    if ( *dbus == 0L )
937    {
938	if(eh)(*(eh))("connection_setup: out of memory");
939	goto fail;
940    }
941    (*dbus)->wh = wh;
942    (*dbus)->wh_arg = wh_arg;
943    (*dbus)->eh = eh;
944    (*dbus)->dh = dh;
945
946    if (!dbus_connection_set_watch_functions
947	 (    (*dbus)->connection,
948	      add_watch,
949	      remove_watch,
950	      toggle_watch,
951	      *dbus,
952	      no_free
953	  )
954       )
955    {
956	if( (*dbus)->eh != 0L ) (*((*dbus)->eh))("connection_setup: dbus_connection_set_watch_functions failed");
957	goto fail;
958    }
959
960    if (!dbus_connection_set_timeout_functions
961	 (    connection,
962	      add_timeout,
963	      remove_timeout,
964	      toggle_timeout,
965	      *dbus,
966	      no_free
967	 )
968       )
969    {
970	if( (*dbus)->eh != 0L ) (*((*dbus)->eh))("connection_setup: dbus_connection_set_timeout_functions failed");
971	goto fail;
972    }
973
974    dbus_connection_set_dispatch_status_function
975    (   connection,
976	dispatch_status,
977	*dbus,
978	no_free
979    );
980
981    if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
982	dbus_connection_ref(connection);
983
984    return ISC_R_SUCCESS;
985
986 fail:
987    if( *dbus != 0L )
988	free(*dbus);
989
990    dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
991    dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL);
992    dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL);
993
994    return ISC_R_FAILURE;
995}
996
997isc_result_t
998dbus_svc_init
999(
1000    dbus_svc_DBUS_TYPE    bus,
1001    char                  *name,
1002    DBUS_SVC		  *dbus,
1003    dbus_svc_WatchHandler wh ,
1004    dbus_svc_ErrorHandler eh ,
1005    dbus_svc_ErrorHandler dh ,
1006    void *wh_arg
1007)
1008{
1009    DBusConnection       *connection;
1010    DBusError            error;
1011    char *session_bus_address=0L;
1012
1013    memset(&error,'\0',sizeof(DBusError));
1014
1015    dbus_error_init(&error);
1016
1017    switch( bus )
1018    {
1019	/* DBUS_PRIVATE_* bus types are the only type which allow reconnection if the dbus-daemon is restarted
1020         */
1021    case DBUS_PRIVATE_SYSTEM:
1022
1023	if ( (connection = dbus_connection_open_private("unix:path=/var/run/dbus/system_bus_socket", &error)) == 0L )
1024	{
1025	    if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message);
1026	    return ISC_R_FAILURE;
1027	}
1028
1029	if ( ! dbus_bus_register(connection,&error) )
1030	{
1031	    if(eh)(*eh)("dbus_bus_register failed: %s %s", error.name, error.message);
1032	    dbus_connection_close(connection);
1033	    free(connection);
1034	    return ISC_R_FAILURE;
1035	}
1036	break;
1037
1038    case DBUS_PRIVATE_SESSION:
1039
1040	session_bus_address = getenv("DBUS_SESSION_BUS_ADDRESS");
1041	if ( session_bus_address == 0L )
1042	{
1043	    if(eh)(*eh)("dbus_svc_init failed: DBUS_SESSION_BUS_ADDRESS environment variable not set");
1044	    return ISC_R_FAILURE;
1045	}
1046
1047	if ( (connection = dbus_connection_open_private(session_bus_address, &error)) == 0L )
1048	{
1049	    if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message);
1050	    return ISC_R_FAILURE;
1051	}
1052
1053	if ( ! dbus_bus_register(connection,&error) )
1054	{
1055	    if(eh)(*eh)("dbus_bus_register failed: %s %s", error.name, error.message);
1056	    dbus_connection_close(connection);
1057	    free(connection);
1058	    return ISC_R_FAILURE;
1059	}
1060	break;
1061
1062    case DBUS_SYSTEM:
1063    case DBUS_SESSION:
1064
1065	if ( (connection = dbus_bus_get (bus, &error)) == 0L )
1066	{
1067	    if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message);
1068	    return ISC_R_FAILURE;
1069	}
1070	break;
1071
1072    default:
1073	if(eh)(*eh)("dbus_svc_init failed: unknown bus type %d", bus);
1074	return ISC_R_FAILURE;
1075    }
1076
1077    dbus_connection_set_exit_on_disconnect(connection, FALSE);
1078
1079    if ( (connection_setup(connection, dbus, wh, eh, dh, wh_arg)) != ISC_R_SUCCESS)
1080    {
1081	if(eh)(*eh)("dbus_svc_init failed: connection_setup failed");
1082	return ISC_R_FAILURE;
1083    }
1084
1085    if( name == 0L )
1086	return ISC_R_SUCCESS;
1087
1088    (*dbus)->unique_name = dbus_bus_get_unique_name(connection);
1089
1090    switch
1091	(   dbus_bus_request_name
1092	    (   connection, name,
1093#ifdef DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT
1094		DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT ,
1095#else
1096		0 ,
1097#endif
1098		&error
1099	    )
1100	)
1101    {
1102    case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
1103	break;
1104    case DBUS_REQUEST_NAME_REPLY_EXISTS:
1105    case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
1106    case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
1107	if(eh)(*eh)("dbus_svc_init: dbus_bus_request_name failed:  Name already registered");
1108	goto give_up;
1109    default:
1110	if(eh)(*eh)("dbus_svc_init: dbus_bus_request_name failed: %s %s", error.name, error.message);
1111	goto give_up;
1112    }
1113    return ISC_R_SUCCESS;
1114
1115 give_up:
1116    dbus_connection_close( connection );
1117    dbus_connection_unref( connection );
1118    if( *dbus )
1119    {
1120	dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
1121	dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL);
1122	dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL);
1123	free(*dbus);
1124    }
1125    return ISC_R_FAILURE;
1126}
1127
1128const char *dbus_svc_unique_name(DBusConnectionState *cs)
1129{
1130    return cs->unique_name;
1131}
1132
1133void
1134dbus_svc_shutdown ( DBusConnectionState *cs )
1135{
1136    if (!dbus_connection_set_watch_functions
1137	 (   cs->connection,
1138	     NULL, NULL, NULL, NULL, NULL
1139	 )
1140       ) if( cs->eh != 0L ) (*(cs->eh))("connection_shutdown: dbus_connection_set_watch_functions: No Memory."
1141                     "Setting watch functions to NULL failed."
1142	            );
1143
1144    if (!dbus_connection_set_timeout_functions
1145	 (   cs->connection,
1146	     NULL, NULL, NULL, NULL, NULL
1147	 )
1148       ) if( cs->eh != 0L ) (*(cs->eh))("connection_shutdown: dbus_connection_set_timeout_functions: No Memory."
1149		     "Setting timeout functions to NULL failed."
1150	            );
1151
1152    dbus_connection_set_dispatch_status_function (cs->connection, NULL, NULL, NULL);
1153
1154    tdestroy( cs->timeouts, free);
1155    cs->timeouts=0L;
1156    tdestroy( cs->watches, no_free);
1157    cs->watches=0L;
1158
1159    dbus_connection_close( cs->connection );
1160    dbus_connection_unref( cs->connection );
1161
1162    free( cs );
1163}
1164