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