summaryrefslogtreecommitdiffstats
path: root/hcid
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2007-06-15 11:06:34 +0000
committerMarcel Holtmann <marcel@holtmann.org>2007-06-15 11:06:34 +0000
commit950da2453656f7e4da59d30a3c7cbb6e65a00027 (patch)
tree711ec84106af94b7c3103763723fa806b918e218 /hcid
parent57290a1e2c13f79d353a21f7c67388ee8c142897 (diff)
Add first version of GetRemoteServiceIdentifiers
Diffstat (limited to 'hcid')
-rw-r--r--hcid/dbus-adapter.c9
-rw-r--r--hcid/dbus-sdp.c180
-rw-r--r--hcid/dbus-sdp.h2
3 files changed, 189 insertions, 2 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c
index 0f6d680a..b32569f6 100644
--- a/hcid/dbus-adapter.c
+++ b/hcid/dbus-adapter.c
@@ -1265,6 +1265,13 @@ static DBusHandlerResult adapter_get_remote_svc_handles(DBusConnection *conn,
return get_remote_svc_handles(conn, msg, data);
}
+static DBusHandlerResult adapter_get_remote_svc_identifiers(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ return get_remote_svc_identifiers(conn, msg, data);
+}
+
static DBusHandlerResult adapter_finish_sdp_transact(DBusConnection *conn,
DBusMessage *msg,
void *data)
@@ -3138,6 +3145,8 @@ static DBusMethodVTable adapter_methods[] = {
"su", "s" },
{ "GetRemoteServiceHandles", adapter_get_remote_svc_handles,
"ss", "au" },
+ { "GetRemoteServiceIdentifiers", adapter_get_remote_svc_identifiers,
+ "s", "as" },
{ "FinishRemoteServiceTransaction", adapter_finish_sdp_transact,
"s", "" },
diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c
index d6dd16ef..8fb8dbf6 100644
--- a/hcid/dbus-sdp.c
+++ b/hcid/dbus-sdp.c
@@ -676,7 +676,7 @@ static void remote_svc_handles_completed_cb(uint8_t type, uint16_t err,
reply = dbus_message_new_method_return(ctxt->rq);
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_UINT32_AS_STRING, &array_iter);
+ DBUS_TYPE_UINT32_AS_STRING, &array_iter);
pdata = rsp;
@@ -697,7 +697,7 @@ static void remote_svc_handles_completed_cb(uint8_t type, uint16_t err,
pdata += sizeof(uint32_t);
dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_UINT32, &handle);
+ DBUS_TYPE_UINT32, &handle);
} while (--tsrc);
@@ -709,6 +709,123 @@ failed:
transaction_context_free(ctxt, TRUE);
}
+static const char *extract_service_class(sdp_data_t *d)
+{
+ sdp_data_t *seq;
+ uuid_t *uuid;
+ static char uuid_str[37];
+
+ /* Expected sequence of UUID16 */
+ if (d->attrId != SDP_ATTR_SVCLASS_ID_LIST || d->dtd != SDP_SEQ8)
+ return NULL;
+
+ if (!d->val.dataseq)
+ return NULL;
+
+ seq = d->val.dataseq;
+ if (!SDP_IS_UUID(seq->dtd))
+ return NULL;
+
+ uuid = &seq->val.uuid;
+ if (uuid->type != SDP_UUID16)
+ return NULL;
+
+ sprintf(uuid_str, "0000%04X-0000-1000-8000-00805F9B34FB",
+ uuid->value.uuid16);
+
+ return uuid_str;
+}
+
+static void remote_svc_identifiers_completed_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ int scanned, n, attrlen, extracted = 0, len = 0;
+ uint8_t dtd = 0;
+
+ if (!ctxt)
+ return;
+
+ if (err == 0xffff) {
+ /* Check for protocol error or I/O error */
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ error_failed(ctxt->conn, ctxt->rq, EINVAL);
+ goto failed;
+ }
+
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ error_failed(ctxt->conn, ctxt->rq, sdp_err);
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP) {
+ error_sdp_failed(ctxt->conn, ctxt->rq, err);
+ goto failed;
+ }
+
+ /* Check response PDU ID */
+ if (type != SDP_SVC_SEARCH_ATTR_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ error_failed(ctxt->conn, ctxt->rq, EPROTO);
+ goto failed;
+ }
+
+ reply = dbus_message_new_method_return(ctxt->rq);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ /* Expected sequence of service class id list */
+ scanned = sdp_extract_seqtype(rsp, &dtd, &len);
+ if (!scanned || !len)
+ goto done;
+
+ rsp += scanned;
+ while (extracted < len) {
+ const char *puuid;
+ sdp_data_t *d;
+ int seqlen;
+ uint16_t attr;
+
+ seqlen = 0;
+ scanned = sdp_extract_seqtype(rsp, &dtd, &seqlen);
+ if (!scanned || !seqlen)
+ goto done;
+
+ extracted += (seqlen + scanned);
+
+ n = sizeof(uint8_t);
+ attrlen = 0;
+
+ rsp += scanned;
+ attr = ntohs(bt_get_unaligned((uint16_t *) (rsp + n)));
+ n += sizeof(uint16_t);
+ d = sdp_extract_attr(rsp + n, &attrlen, NULL);
+ if (!d)
+ break;
+
+ d->attrId = attr;
+ puuid = extract_service_class(d);
+ if (puuid)
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &puuid);
+ sdp_data_free(d);
+
+ n += attrlen;
+ rsp += n;
+ }
+done:
+ dbus_message_iter_close_container(&iter, &array_iter);
+ send_message_and_unref(ctxt->conn, reply);
+
+failed:
+ transaction_context_free(ctxt, TRUE);
+}
+
static gboolean sdp_client_connect_cb(GIOChannel *chan,
GIOCondition cond, void *udata)
{
@@ -941,6 +1058,39 @@ static int remote_svc_handles_conn_cb(struct transaction_context *ctxt)
return 0;
}
+static int remote_svc_identifiers_conn_cb(struct transaction_context *ctxt)
+{
+ sdp_list_t *attrids, *search;
+ uuid_t uuid;
+ uint16_t attr;
+
+ if (sdp_set_notify(ctxt->session,
+ remote_svc_identifiers_completed_cb, ctxt) < 0)
+ return -EINVAL;
+
+ sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
+ search = sdp_list_append(0, &uuid);
+
+ attr = SDP_ATTR_SVCLASS_ID_LIST;
+ attrids = sdp_list_append(NULL, &attr);
+
+ /*
+ * Create/send the search request and set the
+ * callback to indicate the request completion
+ */
+ if (sdp_service_search_attr_async(ctxt->session, search,
+ SDP_ATTR_REQ_INDIVIDUAL, attrids) < 0) {
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrids, NULL);
+ return -sdp_get_error(ctxt->session);
+ }
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrids, NULL);
+
+ return 0;
+}
+
DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data)
{
struct adapter *adapter = data;
@@ -977,6 +1127,32 @@ DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg,
return DBUS_HANDLER_RESULT_HANDLED;
}
+DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *dst;
+ int err;
+
+ if (!adapter->up)
+ return error_not_ready(conn, msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ if (find_pending_connect(dst))
+ return error_service_search_in_progress(conn, msg);
+
+ if (!connect_request(conn, msg, adapter->dev_id,
+ dst, remote_svc_identifiers_conn_cb, &err)) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ return error_failed(conn, msg, err);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn,
DBusMessage *msg, void *data)
{
diff --git a/hcid/dbus-sdp.h b/hcid/dbus-sdp.h
index d34f2fa1..c1a7382d 100644
--- a/hcid/dbus-sdp.h
+++ b/hcid/dbus-sdp.h
@@ -35,6 +35,8 @@ typedef enum {
DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data);
+DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data);
+
DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data, sdp_format_t format);
DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn, DBusMessage *msg, void *data);