static void bt_gatt_server_free(struct bt_gatt_server *server) { if (server->debug_destroy) server->debug_destroy(server->debug_data); bt_att_unregister(server->att, server->mtu_id); bt_att_unregister(server->att, server->read_by_grp_type_id); bt_att_unregister(server->att, server->read_by_type_id); bt_att_unregister(server->att, server->find_info_id); bt_att_unregister(server->att, server->find_by_type_value_id); bt_att_unregister(server->att, server->write_id); bt_att_unregister(server->att, server->write_cmd_id); bt_att_unregister(server->att, server->read_id); bt_att_unregister(server->att, server->read_blob_id); bt_att_unregister(server->att, server->read_multiple_id); bt_att_unregister(server->att, server->prep_write_id); bt_att_unregister(server->att, server->exec_write_id); if (server->pending_read_op) server->pending_read_op->server = NULL; if (server->pending_write_op) server->pending_write_op->server = NULL; queue_destroy(server->prep_queue, prep_write_data_destroy); gatt_db_unref(server->db); bt_att_unref(server->att); free(server); }
static void gas_free(struct gas *gas) { gatt_db_unref(gas->db); bt_gatt_client_unref(gas->client); btd_device_unref(gas->device); g_free(gas); }
static void gas_reset(struct gas *gas) { gas->attr = NULL; gatt_db_unref(gas->db); gas->db = NULL; bt_gatt_client_unref(gas->client); gas->client = NULL; }
void gatt_server_stop(void) { if (att_fd < 0) return; mainloop_remove_fd(att_fd); queue_destroy(conn_list, gatt_conn_destroy); gatt_db_unref(gatt_cache); gatt_cache = NULL; gatt_db_unref(gatt_db); gatt_db = NULL; close(att_fd); att_fd = -1; }
void gatt_server_start(void) { struct sockaddr_l2 addr; if (att_fd >= 0) return; att_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_CLOEXEC, BTPROTO_L2CAP); if (att_fd < 0) { fprintf(stderr, "Failed to create ATT server socket: %m\n"); return; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; addr.l2_cid = htobs(ATT_CID); memcpy(&addr.l2_bdaddr, static_addr, 6); addr.l2_bdaddr_type = BDADDR_LE_RANDOM; if (bind(att_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { fprintf(stderr, "Failed to bind ATT server socket: %m\n"); close(att_fd); att_fd = -1; return; } if (listen(att_fd, 1) < 0) { fprintf(stderr, "Failed to listen on ATT server socket: %m\n"); close(att_fd); att_fd = -1; return; } gatt_db = gatt_db_new(); if (!gatt_db) { close(att_fd); att_fd = -1; return; } populate_gap_service(gatt_db); populate_devinfo_service(gatt_db); gatt_cache = gatt_db_new(); conn_list = queue_new(); if (!conn_list) { gatt_db_unref(gatt_db); gatt_db = NULL; close(att_fd); att_fd = -1; return; } mainloop_add_fd(att_fd, EPOLLIN, att_conn_callback, NULL, NULL); }
void btd_gatt_client_destroy(struct btd_gatt_client *client) { if (!client) return; queue_destroy(client->services, unregister_service); bt_gatt_client_unref(client->gatt); gatt_db_unref(client->db); free(client); }
static void notify_service_changed(struct gatt_db *db, struct gatt_db_service *service, bool added) { struct notify_data data; if (queue_isempty(db->notify_list)) return; data.attr = service->attributes[0]; data.added = added; gatt_db_ref(db); queue_foreach(db->notify_list, handle_notify, &data); gatt_db_unref(db); }
static int gap_driver_accept(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); struct gatt_db *db = btd_device_get_gatt_db(device); struct bt_gatt_client *client = btd_device_get_gatt_client(device); struct gas *gas; GSList *l; char addr[18]; bt_uuid_t gap_uuid; ba2str(device_get_address(device), addr); DBG("GAP profile accept (%s)", addr); l = g_slist_find_custom(devices, device, cmp_device); if (!l) { error("GAP service not handled by profile"); return -1; } gas = l->data; /* Clean-up any old client/db and acquire the new ones */ gas->attr = NULL; gatt_db_unregister(gas->db, gas->db_id); gatt_db_unref(gas->db); bt_gatt_client_unref(gas->client); gas->db = gatt_db_ref(db); gas->client = bt_gatt_client_ref(client); gas->db_id = gatt_db_register(db, service_added, service_removed, gas, NULL); /* Handle the GAP services */ bt_uuid16_create(&gap_uuid, GAP_UUID16); gatt_db_foreach_service(db, &gap_uuid, foreach_gap_service, gas); return 0; }
static void server_destroy(struct server *server) { timeout_remove(server->hr_timeout_id); bt_gatt_server_unref(server->gatt); gatt_db_unref(server->db); }
static struct server *server_create(int fd, uint16_t mtu, bool hr_visible) { struct server *server; size_t name_len = strlen(test_device_name); server = new0(struct server, 1); if (!server) { fprintf(stderr, "Failed to allocate memory for server\n"); return NULL; } server->att = bt_att_new(fd, false); if (!server->att) { fprintf(stderr, "Failed to initialze ATT transport layer\n"); goto fail; } if (!bt_att_set_close_on_unref(server->att, true)) { fprintf(stderr, "Failed to set up ATT transport layer\n"); goto fail; } if (!bt_att_register_disconnect(server->att, att_disconnect_cb, NULL, NULL)) { fprintf(stderr, "Failed to set ATT disconnect handler\n"); goto fail; } server->name_len = name_len + 1; server->device_name = malloc(name_len + 1); if (!server->device_name) { fprintf(stderr, "Failed to allocate memory for device name\n"); goto fail; } memcpy(server->device_name, test_device_name, name_len); server->device_name[name_len] = '\0'; server->fd = fd; server->db = gatt_db_new(); if (!server->db) { fprintf(stderr, "Failed to create GATT database\n"); goto fail; } server->gatt = bt_gatt_server_new(server->db, server->att, mtu); if (!server->gatt) { fprintf(stderr, "Failed to create GATT server\n"); goto fail; } server->hr_visible = hr_visible; if (verbose) { bt_att_set_debug(server->att, att_debug_cb, "att: ", NULL); bt_gatt_server_set_debug(server->gatt, gatt_debug_cb, "server: ", NULL); } /* Random seed for generating fake Heart Rate measurements */ srand(time(NULL)); /* bt_gatt_server already holds a reference */ populate_db(server); return server; fail: gatt_db_unref(server->db); free(server->device_name); bt_att_unref(server->att); free(server); return NULL; }
static struct client *client_create(int fd, uint16_t mtu) { struct client *cli; cli = new0(struct client, 1); if (!cli) { fprintf(stderr, "Failed to allocate memory for client\n"); return NULL; } cli->att = bt_att_new(fd, false); if (!cli->att) { fprintf(stderr, "Failed to initialze ATT transport layer\n"); bt_att_unref(cli->att); free(cli); return NULL; } if (!bt_att_set_close_on_unref(cli->att, true)) { fprintf(stderr, "Failed to set up ATT transport layer\n"); bt_att_unref(cli->att); free(cli); return NULL; } if (!bt_att_register_disconnect(cli->att, att_disconnect_cb, NULL, NULL)) { fprintf(stderr, "Failed to set ATT disconnect handler\n"); bt_att_unref(cli->att); free(cli); return NULL; } cli->fd = fd; cli->db = gatt_db_new(); if (!cli->db) { fprintf(stderr, "Failed to create GATT database\n"); bt_att_unref(cli->att); free(cli); return NULL; } cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu); if (!cli->gatt) { fprintf(stderr, "Failed to create GATT client\n"); gatt_db_unref(cli->db); bt_att_unref(cli->att); free(cli); return NULL; } gatt_db_register(cli->db, service_added_cb, service_removed_cb, NULL, NULL); if (verbose) { bt_att_set_debug(cli->att, att_debug_cb, "att: ", NULL); bt_gatt_client_set_debug(cli->gatt, gatt_debug_cb, "gatt: ", NULL); } bt_gatt_client_ready_register(cli->gatt, ready_cb, cli, NULL); bt_gatt_client_set_service_changed(cli->gatt, service_changed_cb, cli, NULL); /* bt_gatt_client already holds a reference */ gatt_db_unref(cli->db); return cli; }