Home | History | Annotate | Download | only in src
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2006-2010  Nokia Corporation
      6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) holtmann.org>
      7  *  Copyright (C) 2005-2007  Johan Hedberg <johan.hedberg (at) nokia.com>
      8  *
      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; either version 2 of the License, or
     13  *  (at your option) any later version.
     14  *
     15  *  This program is distributed in the hope that it will be useful,
     16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  *  GNU General Public License for more details.
     19  *
     20  *  You should have received a copy of the GNU General Public License
     21  *  along with this program; if not, write to the Free Software
     22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     23  *
     24  */
     25 
     26 #ifdef HAVE_CONFIG_H
     27 #include <config.h>
     28 #endif
     29 
     30 #include <stdio.h>
     31 #include <errno.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <unistd.h>
     35 #include <sys/ioctl.h>
     36 
     37 #include <bluetooth/bluetooth.h>
     38 #include <bluetooth/hci.h>
     39 #include <bluetooth/l2cap.h>
     40 
     41 #include <glib.h>
     42 #include <dbus/dbus.h>
     43 #include <gdbus.h>
     44 
     45 #include "log.h"
     46 
     47 #include "manager.h"
     48 #include "adapter.h"
     49 #include "dbus-hci.h"
     50 #include "dbus-common.h"
     51 
     52 #define BLUEZ_NAME "org.bluez"
     53 
     54 #define RECONNECT_RETRY_TIMEOUT	5000
     55 
     56 static gboolean system_bus_reconnect(void *data)
     57 {
     58 	DBusConnection *conn = get_dbus_connection();
     59 	struct hci_dev_list_req *dl = NULL;
     60 	struct hci_dev_req *dr;
     61 	int sk, i;
     62 	gboolean ret_val = TRUE;
     63 
     64 	if (conn) {
     65 		if (dbus_connection_get_is_connected(conn))
     66 			return FALSE;
     67 	}
     68 
     69 	if (hcid_dbus_init() < 0)
     70 		return TRUE;
     71 
     72 	/* Create and bind HCI socket */
     73 	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
     74 	if (sk < 0) {
     75 		error("Can't open HCI socket: %s (%d)",
     76 				strerror(errno), errno);
     77 		return TRUE;
     78 	}
     79 
     80 	dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl));
     81 
     82 	dl->dev_num = HCI_MAX_DEV;
     83 	dr = dl->dev_req;
     84 
     85 	if (ioctl(sk, HCIGETDEVLIST, (void *) dl) < 0) {
     86 		info("Can't get device list: %s (%d)",
     87 			strerror(errno), errno);
     88 		goto failed;
     89 	}
     90 
     91 	/* reset the default device */
     92 	manager_set_default_adapter(-1);
     93 
     94 	/* FIXME: it shouldn't be needed to register adapters again */
     95 	for (i = 0; i < dl->dev_num; i++, dr++)
     96 		manager_register_adapter(dr->dev_id, TRUE);
     97 
     98 	ret_val = FALSE;
     99 
    100 failed:
    101 	if (sk >= 0)
    102 		close(sk);
    103 
    104 	g_free(dl);
    105 
    106 	return ret_val;
    107 }
    108 
    109 static void disconnect_callback(DBusConnection *conn, void *user_data)
    110 {
    111 	set_dbus_connection(NULL);
    112 
    113 	g_timeout_add(RECONNECT_RETRY_TIMEOUT,
    114 				system_bus_reconnect, NULL);
    115 }
    116 
    117 void hcid_dbus_unregister(void)
    118 {
    119 	DBusConnection *conn = get_dbus_connection();
    120 	char **children;
    121 	int i;
    122 	uint16_t dev_id;
    123 
    124 	if (!conn || !dbus_connection_get_is_connected(conn))
    125 		return;
    126 
    127 	/* Unregister all paths in Adapter path hierarchy */
    128 	if (!dbus_connection_list_registered(conn, "/", &children))
    129 		return;
    130 
    131 	for (i = 0; children[i]; i++) {
    132 		char path[MAX_PATH_LENGTH];
    133 		struct btd_adapter *adapter;
    134 
    135 		if (children[i][0] != 'h')
    136 			continue;
    137 
    138 		snprintf(path, sizeof(path), "/%s", children[i]);
    139 
    140 		adapter = manager_find_adapter_by_path(path);
    141 		if (!adapter)
    142 			continue;
    143 
    144 		dev_id = adapter_get_dev_id(adapter);
    145 		manager_unregister_adapter(dev_id);
    146 	}
    147 
    148 	dbus_free_string_array(children);
    149 }
    150 
    151 void hcid_dbus_exit(void)
    152 {
    153 	DBusConnection *conn = get_dbus_connection();
    154 
    155 	if (!conn || !dbus_connection_get_is_connected(conn))
    156 		return;
    157 
    158 	manager_cleanup(conn, "/");
    159 
    160 	set_dbus_connection(NULL);
    161 
    162 	dbus_connection_unref(conn);
    163 }
    164 
    165 int hcid_dbus_init(void)
    166 {
    167 	DBusConnection *conn;
    168 	DBusError err;
    169 
    170 	dbus_error_init(&err);
    171 
    172 	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err);
    173 	if (!conn) {
    174 		if (dbus_error_is_set(&err)) {
    175 			dbus_error_free(&err);
    176 			return -EIO;
    177 		}
    178 		return -EALREADY;
    179 	}
    180 
    181 	if (g_dbus_set_disconnect_function(conn, disconnect_callback,
    182 							NULL, NULL) == FALSE) {
    183 		dbus_connection_unref(conn);
    184 		return -EIO;
    185 	}
    186 
    187 	if (!manager_init(conn, "/"))
    188 		return -EIO;
    189 
    190 	set_dbus_connection(conn);
    191 
    192 	return 0;
    193 }
    194 
    195 static void append_variant(DBusMessageIter *iter, int type, void *val)
    196 {
    197 	DBusMessageIter value;
    198 	char sig[2] = { type, '\0' };
    199 
    200 	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
    201 
    202 	dbus_message_iter_append_basic(&value, type, val);
    203 
    204 	dbus_message_iter_close_container(iter, &value);
    205 }
    206 
    207 static void append_array_variant(DBusMessageIter *iter, int type, void *val)
    208 {
    209 	DBusMessageIter variant, array;
    210 	char type_sig[2] = { type, '\0' };
    211 	char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
    212 	const char ***str_array = val;
    213 	int i;
    214 
    215 	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
    216 						array_sig, &variant);
    217 
    218 	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
    219 						type_sig, &array);
    220 
    221 	for (i = 0; (*str_array)[i]; i++)
    222 		dbus_message_iter_append_basic(&array, type,
    223 						&((*str_array)[i]));
    224 
    225 	dbus_message_iter_close_container(&variant, &array);
    226 
    227 	dbus_message_iter_close_container(iter, &variant);
    228 }
    229 
    230 void dict_append_entry(DBusMessageIter *dict,
    231 			const char *key, int type, void *val)
    232 {
    233 	DBusMessageIter entry;
    234 
    235 	if (type == DBUS_TYPE_STRING) {
    236 		const char *str = *((const char **) val);
    237 		if (str == NULL)
    238 			return;
    239 	}
    240 
    241 	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
    242 							NULL, &entry);
    243 
    244 	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    245 
    246 	append_variant(&entry, type, val);
    247 
    248 	dbus_message_iter_close_container(dict, &entry);
    249 }
    250 
    251 void dict_append_array(DBusMessageIter *dict, const char *key, int type,
    252 			void *val, int n_elements)
    253 {
    254 	DBusMessageIter entry;
    255 
    256 	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
    257 						NULL, &entry);
    258 
    259 	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    260 
    261 	append_array_variant(&entry, type, val);
    262 
    263 	dbus_message_iter_close_container(dict, &entry);
    264 }
    265 
    266 dbus_bool_t emit_property_changed(DBusConnection *conn,
    267 					const char *path,
    268 					const char *interface,
    269 					const char *name,
    270 					int type, void *value)
    271 {
    272 	DBusMessage *signal;
    273 	DBusMessageIter iter;
    274 
    275 	signal = dbus_message_new_signal(path, interface, "PropertyChanged");
    276 
    277 	if (!signal) {
    278 		error("Unable to allocate new %s.PropertyChanged signal",
    279 				interface);
    280 		return FALSE;
    281 	}
    282 
    283 	dbus_message_iter_init_append(signal, &iter);
    284 
    285 	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
    286 
    287 	append_variant(&iter, type, value);
    288 
    289 	return g_dbus_send_message(conn, signal);
    290 }
    291 
    292 dbus_bool_t emit_array_property_changed(DBusConnection *conn,
    293 					const char *path,
    294 					const char *interface,
    295 					const char *name,
    296 					int type, void *value)
    297 {
    298 	DBusMessage *signal;
    299 	DBusMessageIter iter;
    300 
    301 	signal = dbus_message_new_signal(path, interface, "PropertyChanged");
    302 
    303 	if (!signal) {
    304 		error("Unable to allocate new %s.PropertyChanged signal",
    305 				interface);
    306 		return FALSE;
    307 	}
    308 
    309 	dbus_message_iter_init_append(signal, &iter);
    310 
    311 	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
    312 
    313 	append_array_variant(&iter, type, value);
    314 
    315 	return g_dbus_send_message(conn, signal);
    316 }
    317