Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <dbus/dbus.h>
      7 #include <errno.h>
      8 #include <poll.h>
      9 #include <stdint.h>
     10 #include <stdlib.h>
     11 #include <syslog.h>
     12 #include <sys/select.h>
     13 #include <unistd.h>
     14 
     15 #include "cras_system_state.h"
     16 #include "cras_tm.h"
     17 
     18 static void dbus_watch_callback(void *arg)
     19 {
     20 	DBusWatch *watch = (DBusWatch *)arg;
     21 	int r, flags;
     22 	struct pollfd pollfd;
     23 
     24 	pollfd.fd = dbus_watch_get_unix_fd(watch);
     25 	pollfd.events = POLLIN | POLLOUT;
     26 
     27 	r = poll(&pollfd, 1, 0);
     28 	if (r <= 0)
     29 		return;
     30 
     31 	flags = 0;
     32 	if (pollfd.revents & POLLIN)
     33 		flags |= DBUS_WATCH_READABLE;
     34 	if (pollfd.revents & POLLOUT)
     35 		flags |= DBUS_WATCH_WRITABLE;
     36 
     37 	if (!dbus_watch_handle(watch, flags))
     38 		syslog(LOG_WARNING, "Failed to handle D-Bus watch.");
     39 }
     40 
     41 static dbus_bool_t dbus_watch_add(DBusWatch *watch, void *data)
     42 {
     43 	int r;
     44 	unsigned int flags = dbus_watch_get_flags(watch);
     45 
     46 	/* Only select the read watch.
     47 	 * TODO(hychao): select on write watch when we have a use case.
     48 	 */
     49 	if ((flags & DBUS_WATCH_READABLE) && dbus_watch_get_enabled(watch)) {
     50 		r = cras_system_add_select_fd(dbus_watch_get_unix_fd(watch),
     51 					      dbus_watch_callback,
     52 					      watch);
     53 		if (r != 0)
     54 			return FALSE;
     55 	}
     56 
     57 	return TRUE;
     58 }
     59 
     60 static void dbus_watch_remove(DBusWatch *watch, void *data)
     61 {
     62 	unsigned int flags = dbus_watch_get_flags(watch);
     63 
     64 	/* Only select the read watch. */
     65 	if (flags & DBUS_WATCH_READABLE)
     66 		cras_system_rm_select_fd(dbus_watch_get_unix_fd(watch));
     67 }
     68 
     69 static void dbus_watch_toggled(DBusWatch *watch, void *data)
     70 {
     71 	if (dbus_watch_get_enabled(watch)) {
     72 		dbus_watch_add(watch, NULL);
     73 	} else {
     74 		dbus_watch_remove(watch, NULL);
     75 	}
     76 }
     77 
     78 
     79 static void dbus_timeout_callback(struct cras_timer *t, void *data)
     80 {
     81 	struct cras_tm *tm = cras_system_state_get_tm();
     82 	struct DBusTimeout *timeout = data;
     83 
     84 
     85 	/* Timer is automatically removed after it fires.  Add a new one so this
     86 	 * fires until it is removed by dbus. */
     87 	t = cras_tm_create_timer(tm,
     88 				 dbus_timeout_get_interval(timeout),
     89 				 dbus_timeout_callback, timeout);
     90 	dbus_timeout_set_data(timeout, t, NULL);
     91 
     92 	if (!dbus_timeout_handle(timeout))
     93 		syslog(LOG_WARNING, "Failed to handle D-Bus timeout.");
     94 }
     95 
     96 static dbus_bool_t dbus_timeout_add(DBusTimeout *timeout, void *arg)
     97 {
     98 	struct cras_tm *tm = cras_system_state_get_tm();
     99 	struct cras_timer *t = dbus_timeout_get_data(timeout);
    100 
    101 	if (t) {
    102 		dbus_timeout_set_data(timeout, NULL, NULL);
    103 		cras_tm_cancel_timer(tm, t);
    104 	}
    105 
    106 	if (dbus_timeout_get_enabled(timeout)) {
    107 		t = cras_tm_create_timer(tm,
    108 					 dbus_timeout_get_interval(timeout),
    109 					 dbus_timeout_callback, timeout);
    110 		dbus_timeout_set_data(timeout, t, NULL);
    111 		if (t == NULL)
    112 			return FALSE;
    113 
    114 	}
    115 
    116 	return TRUE;
    117 }
    118 
    119 static void dbus_timeout_remove(DBusTimeout *timeout, void *arg)
    120 {
    121 	struct cras_tm *tm = cras_system_state_get_tm();
    122 	struct cras_timer *t = dbus_timeout_get_data(timeout);
    123 
    124 	if (t) {
    125 		dbus_timeout_set_data(timeout, NULL, NULL);
    126 		cras_tm_cancel_timer(tm, t);
    127 	}
    128 }
    129 
    130 static void dbus_timeout_toggled(DBusTimeout *timeout, void *arg)
    131 {
    132 	if (dbus_timeout_get_enabled(timeout))
    133 		dbus_timeout_add(timeout, NULL);
    134 	else
    135 		dbus_timeout_remove(timeout, NULL);
    136 }
    137 
    138 DBusConnection *cras_dbus_connect_system_bus()
    139 {
    140 	DBusError dbus_error;
    141 	DBusConnection *conn;
    142 	int rc;
    143 
    144 	dbus_error_init(&dbus_error);
    145 
    146 	conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
    147 	if (!conn) {
    148 		syslog(LOG_WARNING, "Failed to connect to D-Bus: %s",
    149 		       dbus_error.message);
    150 		dbus_error_free(&dbus_error);
    151 		return NULL;
    152 	}
    153 
    154 	/* Request a name on the bus. */
    155 	rc = dbus_bus_request_name(conn, "org.chromium.cras", 0, &dbus_error);
    156 	if (dbus_error_is_set(&dbus_error)) {
    157 		syslog(LOG_ERR, "Requesting dbus name %s", dbus_error.message);
    158 		dbus_error_free(&dbus_error);
    159 	}
    160 	if (rc != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    161 		syslog(LOG_ERR, "Not primary owner of dbus name.");
    162 
    163 	if (!dbus_connection_set_watch_functions(conn,
    164 						 dbus_watch_add,
    165 						 dbus_watch_remove,
    166 						 dbus_watch_toggled,
    167 						 NULL,
    168 						 NULL))
    169 		goto error;
    170 	if (!dbus_connection_set_timeout_functions(conn,
    171 						   dbus_timeout_add,
    172 						   dbus_timeout_remove,
    173 						   dbus_timeout_toggled,
    174 						   NULL,
    175 						   NULL))
    176 		goto error;
    177 
    178 	return conn;
    179 
    180 error:
    181 	syslog(LOG_WARNING, "Failed to setup D-Bus connection.");
    182 	dbus_connection_unref(conn);
    183 	return NULL;
    184 }
    185 
    186 void cras_dbus_dispatch(DBusConnection *conn)
    187 {
    188 	while (dbus_connection_dispatch(conn)
    189 		== DBUS_DISPATCH_DATA_REMAINS)
    190 		;
    191 }
    192 
    193 void cras_dbus_disconnect_system_bus(DBusConnection *conn)
    194 {
    195 	dbus_connection_unref(conn);
    196 }
    197