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;
}
Example #2
0
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;
}
Example #3
0
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);
}