📄 device.c
字号:
struct btd_adapter *adapter = device_get_adapter(device); sdp_list_t *seq; char srcaddr[18], dstaddr[18]; bdaddr_t src; adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ba2str(&device->bdaddr, dstaddr); for (seq = recs; seq; seq = seq->next) { sdp_record_t *rec = (sdp_record_t *) seq->data; sdp_list_t *svcclass = NULL; gchar *profile_uuid; GSList *l; if (!rec) break; if (sdp_get_service_classes(rec, &svcclass) < 0) continue; /* Extract the first element and skip the remainning */ profile_uuid = bt_uuid2string(svcclass->data); if (!profile_uuid) { sdp_list_free(svcclass, free); continue; } if (!strcasecmp(profile_uuid, PNP_UUID)) { uint16_t source, vendor, product, version; sdp_data_t *pdlist; pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE); source = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID); vendor = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID); product = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_VERSION); version = pdlist ? pdlist->val.uint16 : 0x0000; if (source || vendor || product || version) store_device_id(srcaddr, dstaddr, source, vendor, product, version); } /* Check for duplicates */ if (sdp_list_find(req->records, rec, rec_cmp)) { g_free(profile_uuid); sdp_list_free(svcclass, free); continue; } store_record(srcaddr, dstaddr, rec); /* Copy record */ req->records = sdp_list_append(req->records, sdp_copy_record(rec)); l = g_slist_find_custom(device->uuids, profile_uuid, (GCompareFunc) strcmp); if (!l) req->profiles_added = g_slist_append(req->profiles_added, profile_uuid); else { req->profiles_removed = g_slist_remove(req->profiles_removed, l->data); g_free(profile_uuid); } sdp_list_free(svcclass, free); }}static void store_profiles(struct btd_device *device){ struct btd_adapter *adapter = device->adapter; bdaddr_t src; char *str; adapter_get_address(adapter, &src); if (!device->uuids) { write_device_profiles(&src, &device->bdaddr, ""); return; } str = bt_list2string(device->uuids); write_device_profiles(&src, &device->bdaddr, str); g_free(str);}static void browse_req_free(struct browse_req *req){ struct btd_device *device = req->device; device->discov_active = 0; if (device->discov_requestor) { g_dbus_remove_watch(req->conn, device->discov_listener); device->discov_listener = 0; g_free(device->discov_requestor); device->discov_requestor = NULL; } if (req->msg) dbus_message_unref(req->msg); if (req->conn) dbus_connection_unref(req->conn); g_slist_foreach(req->profiles_added, (GFunc) g_free, NULL); g_slist_free(req->profiles_added); g_slist_free(req->profiles_removed); if (req->records) sdp_list_free(req->records, (sdp_free_func_t) sdp_record_free); g_free(req);}static void search_cb(sdp_list_t *recs, int err, gpointer user_data){ struct browse_req *req = user_data; struct btd_device *device = req->device; DBusMessage *reply; if (err < 0) { error("%s: error updating services: %s (%d)", device->path, strerror(-err), -err); goto proceed; } update_services(req, recs); if (!req->profiles_added && !req->profiles_removed) { debug("%s: No service update", device->path); goto proceed; } if (device->tmp_records && req->records) { sdp_list_free(device->tmp_records, (sdp_free_func_t) sdp_record_free); device->tmp_records = req->records; req->records = NULL; } /* Probe matching drivers for services added */ if (req->profiles_added) device_probe_drivers(device, req->profiles_added); /* Remove drivers for services removed */ if (req->profiles_removed) device_remove_drivers(device, req->profiles_removed); /* Propagate services changes */ services_changed(req->device);proceed: /* Store the device's profiles in the filesystem */ store_profiles(device); if (!req->msg) goto cleanup; if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "DiscoverServices")) { discover_device_reply(req, req->records); goto cleanup; } /* Reply create device request */ reply = dbus_message_new_method_return(req->msg); if (!reply) goto cleanup; dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path, DBUS_TYPE_INVALID); g_dbus_send_message(req->conn, reply);cleanup: browse_req_free(req);}static void browse_cb(sdp_list_t *recs, int err, gpointer user_data){ struct browse_req *req = user_data; struct btd_device *device = req->device; struct btd_adapter *adapter = device->adapter; bdaddr_t src; uuid_t uuid; /* If we have a valid response and req->search_uuid == 2, then L2CAP UUID & PNP searching was successful -- we are done */ if (err < 0 || (req->search_uuid == 2 && req->records)) goto done; update_services(req, recs); adapter_get_address(adapter, &src); /* Search for mandatory uuids */ if (uuid_list[req->search_uuid]) { sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]); bt_search_service(&src, &device->bdaddr, &uuid, browse_cb, user_data, NULL); return; }done: search_cb(recs, err, user_data);}static void init_browse(struct browse_req *req, gboolean reverse){ GSList *l; /* If we are doing reverse-SDP don't try to detect removed profiles * since some devices hide their service records while they are * connected */ if (reverse) return; for (l = req->device->uuids; l; l = l->next) req->profiles_removed = g_slist_append(req->profiles_removed, l->data);}int device_browse(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, uuid_t *search, gboolean reverse){ struct btd_adapter *adapter = device->adapter; struct browse_req *req; bdaddr_t src; uuid_t uuid; bt_callback_t cb; int err; if (device->discov_active) return -EBUSY; adapter_get_address(adapter, &src); req = g_new0(struct browse_req, 1); req->conn = conn ? dbus_connection_ref(conn) : get_dbus_connection(); req->device = device; if (search) { memcpy(&uuid, search, sizeof(uuid_t)); cb = search_cb; } else { sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]); init_browse(req, reverse); cb = browse_cb; } device->discov_active = 1; if (msg) { req->msg = dbus_message_ref(msg); device->discov_requestor = g_strdup(dbus_message_get_sender(msg)); /* Track the request owner to cancel it * automatically if the owner exits */ device->discov_listener = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), discover_services_req_exit, device, NULL); } err = bt_search_service(&src, &device->bdaddr, &uuid, cb, req, NULL); if (err < 0) browse_req_free(req); return err;}struct btd_adapter *device_get_adapter(struct btd_device *device){ if (!device) return NULL; return device->adapter;}void device_get_address(struct btd_device *device, bdaddr_t *bdaddr){ bacpy(bdaddr, &device->bdaddr);}const gchar *device_get_path(struct btd_device *device){ if (!device) return NULL; return device->path;}struct agent *device_get_agent(struct btd_device *device){ if (!device) return NULL; return device->agent;}void device_set_agent(struct btd_device *device, struct agent *agent){ if (!device) return; device->agent = agent;}gboolean device_is_busy(struct btd_device *device){ return device->discov_active ? TRUE : FALSE;}gboolean device_is_temporary(struct btd_device *device){ return device->temporary;}void device_set_temporary(struct btd_device *device, gboolean temporary){ if (!device) return; device->temporary = temporary;}void device_set_cap(struct btd_device *device, uint8_t cap){ if (!device) return; device->cap = cap;}void device_set_auth(struct btd_device *device, uint8_t auth){ if (!device) return; device->auth = auth;}uint8_t device_get_auth(struct btd_device *device){ return device->auth;}static gboolean start_discovery(gpointer user_data){ struct btd_device *device = user_data; device_browse(device, NULL, NULL, NULL, TRUE); device->discov_timer = 0; return FALSE;}int device_set_paired(DBusConnection *conn, struct btd_device *device, struct bonding_request_info *bonding){ dbus_bool_t paired = TRUE; device_set_temporary(device, FALSE); emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired", DBUS_TYPE_BOOLEAN, &paired); /* If we were initiators start service discovery immediately. * However if the other end was the initator wait a few seconds * before SDP. This is due to potential IOP issues if the other * end starts doing SDP at the same time as us */ if (bonding) { /* If we are initiators remove any discovery timer and just * start discovering services directly */ if (device->discov_timer) { g_source_remove(device->discov_timer); device->discov_timer = 0; } return device_browse(device, bonding->conn, bonding->msg, NULL, FALSE); } /* If we are not initiators and there is no currently active discovery * or discovery timer, set the discovery timer */ if (!device->discov_active && !device->discov_timer) device->discov_timer = g_timeout_add_seconds(DISCOVERY_TIMER, start_discovery, device); return 0;}void btd_device_add_uuid(struct btd_device *device, const char *uuid){ GSList *uuid_list; char *new_uuid; if (g_slist_find_custom(device->uuids, uuid, (GCompareFunc) strcasecmp)) return; new_uuid = g_strdup(uuid); uuid_list = g_slist_append(NULL, new_uuid); device_probe_drivers(device, uuid_list); g_free(new_uuid); g_slist_free(uuid_list); store_profiles(device); services_changed(device);}const sdp_record_t *btd_device_get_record(struct btd_device *device, const char *uuid){ bdaddr_t src; if (device->tmp_records) return find_record_in_list(device->tmp_records, uuid); adapter_get_address(device->adapter, &src); device->tmp_records = read_records(&src, &device->bdaddr); if (!device->tmp_records) return NULL; return find_record_in_list(device->tmp_records, uuid);}int btd_register_device_driver(struct btd_device_driver *driver){ device_drivers = g_slist_append(device_drivers, driver); return 0;}void btd_unregister_device_driver(struct btd_device_driver *driver){ device_drivers = g_slist_remove(device_drivers, driver);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -