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); }
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; }