📄 dbus-sdp.c
字号:
if (err) { if (ctxt->call) { get_record_data_call_cb(ctxt->call, NULL, err); get_record_data_free(ctxt->call); } else error_failed(ctxt->conn, ctxt->rq, err); transaction_context_free(ctxt, FALSE); } return TRUE;}static void remote_svc_rec_completed_cb(uint8_t type, uint16_t err, uint8_t *rsp, size_t size, void *udata){ struct transaction_context *ctxt = udata; sdp_record_t *rec = NULL; DBusMessage *reply; DBusMessageIter iter, array_iter; const char *src, *dst; int scanned; 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_ATTR_RSP) { error("SDP error: %s (%d)", strerror(EPROTO), EPROTO); error_failed(ctxt->conn, ctxt->rq, EPROTO); goto failed; } dbus_message_get_args(ctxt->rq, NULL, DBUS_TYPE_STRING, &dst, DBUS_TYPE_INVALID); src = get_address_from_message(ctxt->conn, ctxt->rq); 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_BYTE_AS_STRING, &array_iter); rec = sdp_extract_pdu(rsp, &scanned); if (rec == NULL) { error("SVC REC is null"); goto done; } sdp_store_record(src, dst, rec->handle, rsp, size); sdp_record_free(rec); dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &rsp, size);done: dbus_message_iter_close_container(&iter, &array_iter); send_message_and_unref(ctxt->conn, reply);failed: transaction_context_free(ctxt, TRUE);}static void remote_svc_rec_completed_xml_cb(uint8_t type, uint16_t err, uint8_t *rsp, size_t size, void *udata){ struct transaction_context *ctxt = udata; sdp_record_t *rec = NULL; DBusMessage *reply; const char *src, *dst; int scanned; sdp_buf_t result; 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_ATTR_RSP) { error("SDP error: %s (%d)", strerror(EPROTO), EPROTO); error_failed(ctxt->conn, ctxt->rq, EPROTO); goto failed; } dbus_message_get_args(ctxt->rq, NULL, DBUS_TYPE_STRING, &dst, DBUS_TYPE_INVALID); src = get_address_from_message(ctxt->conn, ctxt->rq); reply = dbus_message_new_method_return(ctxt->rq); rec = sdp_extract_pdu(rsp, &scanned); if (rec == NULL) { error("SVC REC is null"); goto done; } sdp_store_record(src, dst, rec->handle, rsp, size); memset(&result, 0, sizeof(sdp_buf_t)); convert_sdp_record_to_xml(rec, &result, append_and_grow_string); sdp_record_free(rec); if (result.data) { dbus_message_append_args(reply, DBUS_TYPE_STRING, &result.data, DBUS_TYPE_INVALID); free(result.data); }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(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_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_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 || 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 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(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; } 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; if (c->call) ctxt->call = c->call; /* 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: if (c->call) get_record_data_call_cb(c->call, NULL, err); else error_connection_attempt_failed(c->conn, c->rq, err); if (c->call) get_record_data_free(c->call); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -