static bool CALESetUpBlueZObjects(CALEContext * context) { bool success = false; // Get the list of BlueZ D-Bus objects. GList * const objects = g_dbus_object_manager_get_objects(context->object_manager); if (objects == NULL) { OIC_LOG(ERROR, TAG, "Unable to get objects from ObjectManager."); return success; } ca_mutex_lock(context->lock); context->objects = objects; ca_mutex_unlock(context->lock); /* Create a proxies to the org.bluez.Adapter1 D-Bus objects that will later be used to obtain local bluetooth adapter properties, as well as by the BLE central code to discover peripherals. */ GList * adapters = NULL; success = CAGetBlueZManagedObjectProxies(&adapters, BLUEZ_ADAPTER_INTERFACE, context, NULL); // An empty adapters list is NULL. if (success && adapters != NULL) { ca_mutex_lock(context->lock); context->adapters = adapters; ca_mutex_unlock(context->lock); } /* Create a proxies to the org.bluez.Device1 D-Bus objects that will later be used to establish connections. */ GList * devices = NULL; success = CAGetBlueZManagedObjectProxies(&devices, BLUEZ_DEVICE_INTERFACE, context, CALEDeviceFilter); // An empty device list is NULL. if (success && devices != NULL) { ca_mutex_lock(context->lock); context->devices = devices; ca_mutex_unlock(context->lock); } return success; }
static GList * CAPeripheralInitializeGattServices(CALEContext * context) { GList * result = NULL; /* Create a proxies to the org.bluez.GattManager1 D-Bus objects that will later be used to register the OIC GATT service. */ GList * gatt_managers = NULL; if (!CAGetBlueZManagedObjectProxies(&gatt_managers, BLUEZ_GATT_MANAGER_INTERFACE, context, NULL)) return result; GList * gatt_services = NULL; for (GList * l = gatt_managers; l != NULL; ) { CAGattService * const service = OICCalloc(1, sizeof(*service)); if (service == NULL) { g_list_free_full(gatt_services, CAPeripheralDestroyGattServices); g_list_free_full(gatt_managers, g_object_unref); return result; } /* Use the HCI device name (e.g. hci0) in GattManager1 object path (e.g. /org/bluez/hci0) as a means to differentiate the GATT service hierarchy for each GattManager1 object. */ GDBusProxy * const manager = G_DBUS_PROXY(l->data); char const * const path = g_dbus_proxy_get_object_path(manager); /* The return value will actually be a pointer to a substring starting with the '/' before the HCI name. We add 1 later on to skip that character. */ char const * const hci_name = strrchr(path, '/'); if (hci_name == NULL || !CAGattServiceInitialize(service, hci_name + 1, context)) { g_list_free_full(gatt_services, CAPeripheralDestroyGattServices); g_list_free_full(gatt_managers, g_object_unref); return result; } service->gatt_manager = manager; /* The GattManager1 proxy is now owned by the CAGattService object. */ GList * const tmp = l; l = l->next; gatt_managers = g_list_delete_link(gatt_managers, tmp); // Prepend for efficiency. gatt_services = g_list_prepend(gatt_services, service); } result = gatt_services; return result; }
static void CAPeripheralStartEventLoop(void * data) { CALEContext * const context = data; assert(context != NULL); // Create the event loop. GMainContext * const loop_context = g_main_context_new(); GMainLoop * const event_loop = g_main_loop_new(loop_context, FALSE); g_main_context_push_thread_default(loop_context); // Acquire the bus name after exporting our D-Bus objects. guint const owner_id = g_bus_own_name_on_connection(context->connection, CA_DBUS_GATT_SERVICE_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, CAPeripheralOnNameAcquired, CAPeripheralOnNameLost, NULL, // user_data, NULL); /** * Create proxies to the @c org.bluez.LEAdvertisingManager1 D-Bus * objects that will later be used to register the OIC LE * advertisement data. * * @todo Failure to retrieve the LE advertising managers is * currently ignored. We should propagate the failure to * the thread that spawned this one. * * @note Retrieval of the @c org.bluez.LEAdvertisingManager1 * proxies must be done in a thread separate from the one * that makes calls through those proxies since the * underlying GDBusObjectManagerClient sets up signal * subscriptions that are used when dispatching D-Bus method * handling calls (e.g. property retrieval, etc). * Otherwise, a distributed deadlock situation could occur * if a synchronous D-Bus proxy call is made that causes the * recipient (like BlueZ) to call back in to the thread that * handles signals. For example, registration of our LE * advertisment with BlueZ causes BlueZ itself to make a * call to our own @c org.bluez.LEAdvertisement1 object. * However, the thread that initiated the advertisement * registration is blocked waiting for BlueZ to respond, but * BlueZ is blocked waiting for that same thread to respond * to its own advertisement property retrieval call. */ GList * advertising_managers = NULL; if (!CAGetBlueZManagedObjectProxies( &advertising_managers, BLUEZ_ADVERTISING_MANAGER_INTERFACE, context, NULL)) { OIC_LOG(ERROR, TAG, "Failed to retrieve BlueZ LE advertising " "manager interface."); } ca_mutex_lock(g_context.lock); assert(g_context.event_loop == NULL); g_context.event_loop = event_loop; g_context.base = context; g_context.owner_id = owner_id; /** * Initialize all GATT services. * * @todo Failure to initialize the OIC GATT services is currently * ignored. We should propagate the failure to the thread * that spawned this one. * * @note See the @c org.bluez.LEAdvertisingManager1 note above to * understand why the GATT services must be initialized in * a thread seperate from the one that initiates GATT * service registration. */ g_context.gatt_services = CAPeripheralInitializeGattServices(context); CALEAdvertisementInitialize(&g_context.advertisement, context->connection, advertising_managers); ca_mutex_unlock(g_context.lock); ca_cond_signal(g_context.condition); g_main_loop_run(event_loop); // Blocks until loop is quit. /* Clean up in the same thread to avoid having to explicitly bump the ref count to retain ownership. */ g_main_context_unref(loop_context); g_main_loop_unref(event_loop); }