diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-04-09 00:12:36 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-04-09 00:12:36 +0000 |
commit | e0d05942e436393256b61f111d5924add57840c7 (patch) | |
tree | 3657026fe793e6e051022d90728369578a7bec9b | |
parent | 8fa8629fa44075dfa41b1bff96a7951dd40cfb0a (diff) |
* Add D-Bus methods for getting remote device class information
* Fix a couple of memory leaks where result of textfile_get wasn't free'd
-rw-r--r-- | hcid/dbus-adapter.c | 204 | ||||
-rw-r--r-- | hcid/dbus-api.txt | 27 | ||||
-rw-r--r-- | hcid/dbus.c | 85 | ||||
-rw-r--r-- | hcid/dbus.h | 4 | ||||
-rw-r--r-- | hcid/hcid.h | 2 | ||||
-rw-r--r-- | hcid/storage.c | 49 |
6 files changed, 299 insertions, 72 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index 7a995e83..106c6152 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -55,6 +55,19 @@ static const char *service_cls[] = { "information" }; +static const char *major_cls[] = { + "miscellaneous", + "computer", + "phone", + "access point", + "audio/video", + "peripheral", + "imaging", + "wearable", + "toy", + "uncategorized" +}; + static const char *computer_minor_cls[] = { "uncategorized", "desktop", @@ -1051,6 +1064,132 @@ static DBusHandlerResult handle_dev_get_remote_company_req(DBusConnection *conn, return send_reply_and_unref(conn, reply); } +static int get_remote_class(DBusConnection *conn, DBusMessage *msg, void *data, uint32_t *class) +{ + struct hci_dbus_data *dbus_data = data; + char addr_local[18], *addr_peer; + DBusError err; + bdaddr_t local, peer; + int ecode; + + dbus_error_init(&err); + dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &addr_peer, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + error("Can't extract message arguments:%s", err.message); + dbus_error_free(&err); + error_invalid_arguments(conn, msg); + return -1; + } + + if (check_address(addr_peer) < 0) { + error_invalid_arguments(conn, msg); + return -1; + } + + ecode = get_device_address(dbus_data->dev_id, addr_local, sizeof(addr_local)); + if (ecode < 0) { + error_failed(conn, msg, -ecode); + return -1; + } + + str2ba(addr_peer, &peer); + str2ba(addr_local, &local); + + ecode = read_remote_class(&local, &peer, class); + if (ecode < 0) { + error_failed(conn, msg, -ecode); + return -1; + } + + return 0; +} + +static DBusHandlerResult handle_dev_get_remote_major_class_req(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + const char *major_class; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + major_class = major_class_str(class); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class, + DBUS_TYPE_INVALID); + + return send_reply_and_unref(conn, reply); +} + +static DBusHandlerResult handle_dev_get_remote_minor_class_req(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + const char *major_class; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + major_class = minor_class_str(class); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class, + DBUS_TYPE_INVALID); + + return send_reply_and_unref(conn, reply); +} + +static DBusHandlerResult handle_dev_get_remote_service_cls_req(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, array_iter; + const char **service_classes; + int i; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + service_classes = service_classes_str(class); + if (!service_classes) { + error("Unable to create service classes list"); + return error_failed(conn,msg, ENOMEM); + } + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + for (i = 0; service_classes[i] != NULL; i++) + dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &service_classes[i]); + + dbus_message_iter_close_container(&iter, &array_iter); + + free(service_classes); + + return send_reply_and_unref(conn, reply); +} + static DBusHandlerResult handle_dev_get_remote_name_req(DBusConnection *conn, DBusMessage *msg, void *data) { char filename[PATH_MAX + 1], addr[18]; @@ -2030,6 +2169,68 @@ static DBusHandlerResult handle_dev_cancel_discovery_req(DBusConnection *conn, D return send_reply_and_unref(conn, reply); } +const char *major_class_str(uint32_t class) +{ + uint8_t index = (class >> 8) & 0x1F; + + if (index > 8) + return major_cls[9]; /* uncategorized */ + + return major_cls[index]; +} + +const char *minor_class_str(uint32_t class) +{ + uint8_t major_index = (class >> 8) & 0x1F; + uint8_t minor_index = (class >> 2) & 0x3F; + + switch (major_index) { + case 1: /* computer */ + return computer_minor_cls[minor_index]; + case 2: /* phone */ + return phone_minor_cls[minor_index]; + } + + return ""; +} + +/* Return NULL terminated array of strings */ +const char **service_classes_str(uint32_t class) +{ + uint8_t services = class >> 16; + const char **classes; + int i, class_count = 0; + + classes = malloc(sizeof(const char *)); + if (!classes) + return NULL; + + classes[0] = NULL; + + for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { + const char **tmp; + + if (!(services & (1 << i))) + continue; + + class_count++; + + tmp = realloc(classes, sizeof(const char *) * (class_count + 1)); + if (!tmp) { + free(classes); + return NULL; + } + + classes = tmp; + + classes[class_count - 1] = service_cls[i]; + classes[class_count] = NULL; + } + + return classes; +} + + static struct service_data dev_services[] = { { "GetAddress", handle_dev_get_address_req }, { "GetVersion", handle_dev_get_version_req }, @@ -2056,6 +2257,9 @@ static struct service_data dev_services[] = { { "GetRemoteRevision", handle_dev_get_remote_revision_req }, { "GetRemoteManufacturer", handle_dev_get_remote_manufacturer_req }, { "GetRemoteCompany", handle_dev_get_remote_company_req }, + { "GetRemoteMajorClass", handle_dev_get_remote_major_class_req }, + { "GetRemoteMinorClass", handle_dev_get_remote_minor_class_req }, + { "GetRemoteServiceClasses", handle_dev_get_remote_service_cls_req }, { "GetRemoteName", handle_dev_get_remote_name_req }, { "GetRemoteAlias", handle_dev_get_remote_alias_req }, { "SetRemoteAlias", handle_dev_set_remote_alias_req }, diff --git a/hcid/dbus-api.txt b/hcid/dbus-api.txt index 51081424..a5f30101 100644 --- a/hcid/dbus-api.txt +++ b/hcid/dbus-api.txt @@ -416,6 +416,33 @@ Methods string GetAddress() Possible errors: org.bluez.Error.UnknownAddress org.bluez.Error.NotAvailable + string GetRemoteMajorClass(string address) + + Get the major device class of the specified device. + + Example: "computer" + + Possible errors: org.bluez.Error.UnknownAddress + org.bluez.Error.NotAvailable + + string GetRemoteMinorClass(string address) + + Get the minor device class of the specified device. + + Example: "laptop" + + Possible errors: org.bluez.Error.UnknownAddress + org.bluez.Error.NotAvailable + + array{string] GetRemoteServiceClasses(string address) + + Get the service classes of the specified device. + + Example: ["networking", "object transfer"] + + Possible errors: org.bluez.Error.UnknownAddress + org.bluez.Error.NotAvailable + string GetRemoteName(string address) Get adapter name for a remote device. This request diff --git a/hcid/dbus.c b/hcid/dbus.c index c1abd71b..a74b0309 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -52,50 +52,6 @@ static int default_dev = -1; #define MAX_CONN_NUMBER 10 #define RECONNECT_RETRY_TIMEOUT 5000 -static const char *services_cls[] = { - "positioning", - "networking", - "rendering", - "capturing", - "object transfer", - "audio", - "telephony", - "information" -}; - -static const char *major_cls[] = { - "miscellaneous", - "computer", - "phone", - "access point", - "audio/video", - "peripheral", - "imaging", - "wearable", - "toy", - "uncategorized" -}; - -static const char *computer_minor_cls[] = { - "uncategorized", - "desktop", - "server", - "laptop", - "handheld", - "palm", - "wearable" -}; - -static const char *phone_minor_cls[] = { - "uncategorized", - "cellular", - "cordless", - "smart phone", - "modem", - "isdn" -}; - - void disc_device_info_free(void *data, void *user_data) { struct discovered_dev_info *dev = data; @@ -958,13 +914,11 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i struct slist *l = NULL; struct discovered_dev_info *dev; char *local_addr, *peer_addr, *name = NULL; - const char *major_ptr; - char invalid_minor_class[] = ""; - const char *minor_ptr = invalid_minor_class; + const char *major_ptr, *minor_ptr; + const char **service_classes; const dbus_int16_t tmp_rssi = rssi; bdaddr_t tmp; int id, i; - uint8_t service_index, major_index, minor_index; name_status_t name_status = NAME_PENDING; baswap(&tmp, local); local_addr = batostr(&tmp); @@ -983,6 +937,8 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i goto failed; } + write_remote_class(local, peer, class); + /* send the device found signal */ signal_device = dbus_message_new_signal(path, ADAPTER_INTERFACE, "RemoteDeviceFound"); @@ -991,23 +947,8 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i goto failed; } - /* get the major class */ - major_index = (class >> 8) & 0x1F; - if (major_index > 8) - major_ptr = major_cls[9]; /* set to uncategorized */ - else - major_ptr = major_cls[major_index]; - - /* get the minor class */ - minor_index = (class >> 2) & 0x3F; - switch (major_index) { - case 1: /* computer */ - minor_ptr = computer_minor_cls[minor_index]; - break; - case 2: /* phone */ - minor_ptr = phone_minor_cls[minor_index]; - break; - } + major_ptr = major_class_str(class); + minor_ptr = minor_class_str(class); dbus_message_iter_init_append(signal_device, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &peer_addr); @@ -1015,17 +956,23 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &major_ptr); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor_ptr); + service_classes = service_classes_str(class); + if (!service_classes) { + error("Unable to create service class strings"); + goto failed; + } + /* add the service classes */ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array_iter); - service_index = class >> 16; - for (i = 0; i < (sizeof(services_cls) / sizeof(*services_cls)); i++) - if (service_index & (1 << i)) - dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &services_cls[i]); + for (i = 0; service_classes[i] != NULL; i++) + dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &service_classes[i]); dbus_message_iter_close_container(&iter, &array_iter); + free(service_classes); + if (dbus_connection_send(connection, signal_device, NULL) == FALSE) { error("Can't send D-Bus remote device found signal"); goto failed; diff --git a/hcid/dbus.h b/hcid/dbus.h index f6f0b6d8..663394b6 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -129,6 +129,10 @@ typedef int unregister_function_t(DBusConnection *conn, uint16_t id); DBusHandlerResult msg_func_device(DBusConnection *conn, DBusMessage *msg, void *data); DBusHandlerResult msg_func_manager(DBusConnection *conn, DBusMessage *msg, void *data); +const char *major_class_str(uint32_t class); +const char *minor_class_str(uint32_t class); +const char **service_classes_str(uint32_t class); + DBusHandlerResult bluez_new_failure_msg(DBusConnection *conn, DBusMessage *msg, const uint32_t ecode); DBusMessage *dev_signal_factory(const int devid, const char *prop_name, const int first, ...); diff --git a/hcid/hcid.h b/hcid/hcid.h index 1bd64130..2f5d74c1 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -158,6 +158,8 @@ int write_local_name(bdaddr_t *bdaddr, char *name); int read_local_name(bdaddr_t *bdaddr, char *name); int write_local_class(bdaddr_t *bdaddr, uint8_t *class); int read_local_class(bdaddr_t *bdaddr, uint8_t *class); +int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class); +int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class); int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name); int read_device_name(bdaddr_t *local, bdaddr_t *peer, char *name); int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver); diff --git a/hcid/storage.c b/hcid/storage.c index 17f0744a..e3781278 100644 --- a/hcid/storage.c +++ b/hcid/storage.c @@ -122,6 +122,44 @@ int read_local_class(bdaddr_t *bdaddr, uint8_t *class) return 0; } +int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class) +{ + char filename[PATH_MAX + 1], addr[18], str[9]; + + ba2str(local, addr); + snprintf(filename, PATH_MAX, "%s/%s/classes", STORAGEDIR, addr); + + create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + ba2str(peer, addr); + sprintf(str, "0x%6.6x", class); + + return textfile_put(filename, addr, str); +} + +int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class) +{ + char filename[PATH_MAX + 1], addr[18], *str; + + ba2str(local, addr); + snprintf(filename, PATH_MAX, "%s/%s/classes", STORAGEDIR, addr); + + ba2str(peer, addr); + + str = textfile_get(filename, addr); + if (!str) + return -ENOENT; + + if (sscanf(str, "%x", class) != 1) { + free(str); + return -ENOENT; + } + + free(str); + + return 0; +} + int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name) { char filename[PATH_MAX + 1], addr[18], str[249]; @@ -251,8 +289,11 @@ int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, int type if (length < 0) { char *tmp = textfile_get(filename, addr); - if (tmp && strlen(tmp) > 34) - memcpy(str + 34, tmp + 34, 3); + if (tmp) { + if (strlen(tmp) > 34) + memcpy(str + 34, tmp + 34, 3); + free(tmp); + } } return textfile_put(filename, addr, str); @@ -295,8 +336,10 @@ int read_pin_length(bdaddr_t *local, bdaddr_t *peer) if (!str) return -ENOENT; - if (strlen(str) < 36) + if (strlen(str) < 36) { + free(str); return -ENOENT; + } len = atoi(str + 35); |