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