⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbus-sdp.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 2 页
字号:
	}done:	send_message_and_unref(ctxt->conn, reply);failed:	transaction_context_free(ctxt, TRUE);}static void remote_svc_handles_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;	uint8_t *pdata;	int csrc, tsrc;	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_errno(ctxt->conn, ctxt->rq, EINVAL);			goto failed;		}		error("search failed: %s (%d)", strerror(sdp_err), sdp_err);		error_failed_errno(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_RSP) {		error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);		error_failed_errno(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_UINT32_AS_STRING, &array_iter);	pdata = rsp;	tsrc = ntohs(bt_get_unaligned((uint16_t *) pdata));	if (tsrc <= 0)		goto done;	pdata += sizeof(uint16_t);	csrc = ntohs(bt_get_unaligned((uint16_t *) pdata));	if (csrc <= 0)		goto done;	pdata += sizeof(uint16_t);	do {		uint32_t handle = ntohl(bt_get_unaligned((uint32_t*)pdata));		pdata += sizeof(uint32_t);		dbus_message_iter_append_basic(&array_iter,						DBUS_TYPE_UINT32, &handle);	} while (--tsrc);done:	dbus_message_iter_close_container(&iter, &array_iter);	send_message_and_unref(ctxt->conn, reply);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)		return NULL;	if (d->dtd != SDP_SEQ8 && d->dtd != SDP_SEQ16 && d->dtd != SDP_SEQ32)		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 int service_search_attr(struct transaction_context *ctxt, uint16_t uuid){	sdp_list_t *attrids, *search;	uint32_t range = 0x0000ffff;	int ret = 0;	sdp_uuid16_create(&ctxt->uuid, uuid);	search = sdp_list_append(0, &ctxt->uuid);	attrids = sdp_list_append(NULL, &range);	/*	 * 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_RANGE, attrids) < 0)		ret = -sdp_get_error(ctxt->session);	sdp_list_free(search, NULL);	sdp_list_free(attrids, NULL);	return ret;}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;	const char *src, *dst, *puuid;	const char *devid_uuid = "00001200-0000-1000-8000-00805f9b34fb";	char **identifiers;	DBusMessage *reply;	GSList *l = NULL;	int scanned, extracted = 0, len = 0, recsize = 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_errno(ctxt->conn, ctxt->rq, EINVAL);			goto failed;		}		error("search failed: %s (%d)", strerror(sdp_err), sdp_err);		error_failed_errno(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_errno(ctxt->conn, ctxt->rq, EPROTO);		goto failed;	}	src = get_address_from_message(ctxt->conn, ctxt->rq);	dbus_message_get_args(ctxt->rq, NULL,			DBUS_TYPE_STRING, &dst,			DBUS_TYPE_INVALID);	scanned = sdp_extract_seqtype(rsp, &dtd, &len);	rsp += scanned;	for (; extracted < len; rsp += recsize, extracted += recsize) {		sdp_record_t *rec;		sdp_data_t *d;		recsize = 0;		rec = sdp_extract_pdu(rsp, &recsize);		if (!rec)			break;		sdp_store_record(src, dst, rec->handle, rsp, recsize);		d = sdp_data_get(rec, SDP_ATTR_SVCLASS_ID_LIST);		if (!d) {			sdp_record_free(rec);			continue;		}		puuid = extract_service_class(d);		sdp_record_free(rec);		if (!puuid)			continue;		/* Ignore repeated identifiers */		l = g_slist_find_custom(ctxt->identifiers,				puuid, (GCompareFunc) strcmp);		if (l)			continue;		ctxt->identifiers = g_slist_append(ctxt->identifiers,							g_strdup(puuid));	}	/* If public browse response is empty: search for L2CAP */	if (!ctxt->identifiers && ctxt->uuid.value.uuid16 == PUBLIC_BROWSE_GROUP)		if (service_search_attr(ctxt, L2CAP_UUID) == 0)			return; /* Wait the response */	/* Request DeviceID if it was not returned previously */	l = g_slist_find_custom(ctxt->identifiers,			devid_uuid, (GCompareFunc) strcmp);	if (!l && ctxt->uuid.value.uuid16 != PNP_INFO_SVCLASS_ID)		if (service_search_attr(ctxt, PNP_INFO_SVCLASS_ID) == 0)			return; /* Wait the response */	reply = dbus_message_new_method_return(ctxt->rq);	identifiers = g_new(char *, g_slist_length(ctxt->identifiers));	for (l = ctxt->identifiers, len = 0; l; l = l->next, len++)		identifiers[len] = l->data;	dbus_message_append_args(reply,			DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,			&identifiers, len,			DBUS_TYPE_INVALID);	send_message_and_unref(ctxt->conn, reply);	if (len)		dbus_connection_emit_signal(ctxt->conn,				dbus_message_get_path(ctxt->rq),				ADAPTER_INTERFACE,				"RemoteIdentifiersUpdated",				DBUS_TYPE_STRING, &dst,				DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,				&identifiers, len,				DBUS_TYPE_INVALID);	if (identifiers)		g_free(identifiers);failed:	transaction_context_free(ctxt, TRUE);}static gboolean sdp_client_connect_cb(GIOChannel *chan,					GIOCondition cond, void *udata){	struct pending_connect *c = udata;	struct transaction_context *ctxt = NULL;	int sdp_err, err = 0, sk;	socklen_t len;	sk = g_io_channel_unix_get_fd(chan);	len = sizeof(err);	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {		error("getsockopt(): %s (%d)", strerror(errno), errno);		err = errno;		goto failed;	}	if (err != 0) {		error("connect(): %s (%d)", strerror(err), err);		goto failed;	}	ctxt = g_new0(struct transaction_context, 1);	ctxt->conn = dbus_connection_ref(c->conn);	ctxt->rq = dbus_message_ref(c->rq);	ctxt->session = c->session;	/* set the complete transaction callback and send the search request */	sdp_err = c->conn_cb(ctxt);	if (sdp_err < 0) {		err = -sdp_err;		error("search failed: %s (%d)", strerror(err), err);		goto failed;	}	/* set the callback responsible for update the transaction data */	ctxt->io_id = g_io_add_watch(chan,				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,				search_process_cb, ctxt);	ctxt->io = g_io_channel_ref(chan);	goto done;failed:	error_connection_attempt_failed(c->conn, c->rq, err);	if (ctxt)		transaction_context_free(ctxt, FALSE);	else		sdp_close(c->session);done:	pending_connects = g_slist_remove(pending_connects, c);	pending_connect_free(c);	return FALSE;}static struct pending_connect *connect_request(DBusConnection *conn,					DBusMessage *msg,					uint16_t dev_id,					const char *dst,					connect_cb_t *cb, int *err){	struct pending_connect *c;	bdaddr_t srcba, dstba;	GIOChannel *chan;	c = pending_connect_new(conn, msg, dst, cb);	if (!c) {		if (err)			*err = ENOMEM;		return NULL;	}	hci_devba(dev_id, &srcba);	str2ba(dst, &dstba);	c->session = get_sdp_session(&srcba, &dstba);	if (!c->session) {		if (err)			*err = errno;		error("sdp_connect() failed: %s (%d)", strerror(errno), errno);		pending_connect_free(c);		return NULL;	}	chan = g_io_channel_unix_new(sdp_get_socket(c->session));	g_io_add_watch(chan, G_IO_OUT, sdp_client_connect_cb, c);	g_io_channel_unref(chan);	pending_connects = g_slist_append(pending_connects, c);	return c;}static int remote_svc_rec_conn_cb(struct transaction_context *ctxt){	sdp_list_t *attrids;	uint32_t range = 0x0000ffff;	const char *dst;	uint32_t handle;	if (sdp_set_notify(ctxt->session, remote_svc_rec_completed_cb, ctxt) < 0)		return -EINVAL;	dbus_message_get_args(ctxt->rq, NULL,			DBUS_TYPE_STRING, &dst,			DBUS_TYPE_UINT32, &handle,			DBUS_TYPE_INVALID);	attrids = sdp_list_append(NULL, &range);	/*	 * Create/send the search request and set the	 * callback to indicate the request completion	 */	if (sdp_service_attr_async(ctxt->session, handle,				SDP_ATTR_REQ_RANGE, attrids) < 0) {		sdp_list_free(attrids, NULL);		return -sdp_get_error(ctxt->session);	}	sdp_list_free(attrids, NULL);	return 0;}static int remote_svc_rec_conn_xml_cb(struct transaction_context *ctxt){	sdp_list_t *attrids;	uint32_t range = 0x0000ffff;	const char *dst;	uint32_t handle;	if (sdp_set_notify(ctxt->session, remote_svc_rec_completed_xml_cb, ctxt) < 0)		return -EINVAL;	dbus_message_get_args(ctxt->rq, NULL,			DBUS_TYPE_STRING, &dst,			DBUS_TYPE_UINT32, &handle,			DBUS_TYPE_INVALID);	attrids = sdp_list_append(NULL, &range);	/* 	 * Create/send the search request and set the	 * callback to indicate the request completion	 */	if (sdp_service_attr_async(ctxt->session, handle,				SDP_ATTR_REQ_RANGE, attrids) < 0) {		sdp_list_free(attrids, NULL);		return -sdp_get_error(ctxt->session);	}	sdp_list_free(attrids, NULL);	return 0;}DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg,				void *data, sdp_format_t format){	struct adapter *adapter = data;	const char *dst;	uint32_t handle;	int err;	connect_cb_t *cb;	if (!adapter->up)		return error_not_ready(conn, msg);	if (!dbus_message_get_args(msg, NULL,			DBUS_TYPE_STRING, &dst,			DBUS_TYPE_UINT32, &handle,			DBUS_TYPE_INVALID))		return error_invalid_arguments(conn, msg, NULL);	if (find_pending_connect(dst))		return error_service_search_in_progress(conn, msg);	cb = remote_svc_rec_conn_cb;	if (format == SDP_FORMAT_XML)		cb = remote_svc_rec_conn_xml_cb;	if (!connect_request(conn, msg, adapter->dev_id,				dst, cb, &err)) {		error("Search request failed: %s (%d)", strerror(err), err);		return error_failed_errno(conn, msg, err);	}	return DBUS_HANDLER_RESULT_HANDLED;}static int remote_svc_handles_conn_cb(struct transaction_context *ctxt){	sdp_list_t *search = NULL;	const char *dst, *svc;	if (sdp_set_notify(ctxt->session, remote_svc_handles_completed_cb, ctxt) < 0)		return -EINVAL;	dbus_message_get_args(ctxt->rq, NULL,			DBUS_TYPE_STRING, &dst,			DBUS_TYPE_STRING, &svc,			DBUS_TYPE_INVALID);	if (strlen(svc) > 0)		str2uuid(&ctxt->uuid, svc);	else		sdp_uuid16_create(&ctxt->uuid, PUBLIC_BROWSE_GROUP);	search = sdp_list_append(0, &ctxt->uuid);	/* Create/send the search request and set the callback to indicate the request completion */	if (sdp_service_search_async(ctxt->session, search, 64) < 0) {		error("send request failed: %s (%d)", strerror(errno), errno);		sdp_list_free(search, NULL);		return -sdp_get_error(ctxt->session);	}	sdp_list_free(search, NULL);	return 0;}static int remote_svc_identifiers_conn_cb(struct transaction_context *ctxt){	if (sdp_set_notify(ctxt->session,			remote_svc_identifiers_completed_cb, ctxt) < 0)		return -EINVAL;	return service_search_attr(ctxt, PUBLIC_BROWSE_GROUP);}DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data){	struct adapter *adapter = data;	const char *dst, *svc;	int err;	uuid_t uuid;	if (!adapter->up)		return error_not_ready(conn, msg);	if (!dbus_message_get_args(msg, NULL,			DBUS_TYPE_STRING, &dst,			DBUS_TYPE_STRING, &svc,			DBUS_TYPE_INVALID))		return error_invalid_arguments(conn, msg, NULL);	if (strlen(svc) > 0) {		/* Check if it is a service name string */		if (str2uuid(&uuid, svc) < 0) {			error("Invalid service class name");			return error_invalid_arguments(conn, msg, NULL);		}	}	if (find_pending_connect(dst))		return error_service_search_in_progress(conn, msg);	if (!connect_request(conn, msg, adapter->dev_id,				dst, remote_svc_handles_conn_cb, &err)) {		error("Search request failed: %s (%d)", strerror(err), err);		return error_failed_errno(conn, msg, err);	}	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, NULL);	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_errno(conn, msg, err);	}	return DBUS_HANDLER_RESULT_HANDLED;}DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn,						DBusMessage *msg, void *data){	struct cached_session *s;	const char *address;	struct adapter *adapter = data;	DBusMessage *reply;	bdaddr_t sba, dba;	if (!dbus_message_get_args(msg, NULL,			DBUS_TYPE_STRING, &address,			DBUS_TYPE_INVALID))		return error_invalid_arguments(conn, msg, NULL);	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	str2ba(adapter->address, &sba);	str2ba(address, &dba);	while ((s = get_cached_session(&sba, &dba))) {		sdp_close(s->session);		g_source_remove(s->timeout_id);		g_source_remove(s->io_id);		g_free(s);	}	return send_message_and_unref(conn, reply);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -