C++ GDBus. Bluetooth service registration and getting out of the loop

408 Views Asked by At

I need to register bluetooth service on Linux PC in C++ and so far, I am able to do it with such code: (taken and shorthened from here).

#include <cstdio>
#include <gio/gio.h>
#include <glib.h>

#define SERIAL_PORT_PROFILE_UUID "00001101-0000-1000-8000-00805F9B34FB"
#define CUSTOM_UUID              "22222222-2222-2222-2222-222222222222" //"E62C4DCA-9ABC-11E5-8994-FEFF819CDC9F"

int register_profile(GDBusProxy *proxy){
    GVariant *profile;
    GVariantBuilder profile_builder;
    GError *error = NULL;

    printf("register_profile called!\n");

    g_variant_builder_init(&profile_builder, G_VARIANT_TYPE("(osa{sv})"));

    if (g_variant_is_object_path("/org/bluez/customprofile")) {
        printf("object path is good!\n");
    }

    g_variant_builder_add (&profile_builder, "o",
                           "/org/bluez/customprofile");

    g_variant_builder_add (&profile_builder, "s", SERIAL_PORT_PROFILE_UUID);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("a{sv}"));

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Channel");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_uint16(22));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Service");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_string(CUSTOM_UUID));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Name");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_string("Custom Serial Port"));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Role");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_string("server"));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "RequireAuthentication");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_boolean(FALSE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "RequireAuthorization");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_boolean(FALSE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "AutoConnect");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_boolean(TRUE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_close(&profile_builder);
    profile = g_variant_builder_end(&profile_builder);

    GVariant * ret = g_dbus_proxy_call_sync (proxy,
                                             "RegisterProfile",
                                             profile,
                                             G_DBUS_CALL_FLAGS_NONE,
                                             -1,
                                             NULL,
                                             &error);
    g_assert_no_error(error);
    if(ret != NULL && error==NULL){
        return 0;
    } else {
        return 1;
    }
}

void init_server()
{
    GDBusProxy *proxy;
    GDBusConnection *conn;
    GError *error = nullptr;

    GMainLoop *loop = g_main_loop_new (nullptr, false);

    conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, nullptr, &error);
    g_assert_no_error (error);

    proxy = g_dbus_proxy_new_sync (conn,
                                   G_DBUS_PROXY_FLAGS_NONE,
                                   nullptr,/* GDBusInterfaceInfo */
                                   "org.bluez",/* name */
                                   "/org/bluez",/* object path */
                                   "org.bluez.ProfileManager1",/* interface */
                                   nullptr,/* GCancellable */
                                   &error);
    g_assert_no_error (error);
    error=nullptr;
    if (register_profile (proxy)) {
        printf("profile register failed\n");
        return;
    }
    printf("SPP profile registered");
    g_main_loop_run (loop);

    g_object_unref (proxy);
    g_object_unref (conn);
}


int main(int argc, const char** argv) {
    init_server();
}

Everyting works great, and I can see the service in bluetoothctl or sdptool browse (from other PC).

The problem is: I want to continue the programm execution after the registration, but I do not understand how I can exit the loop after the execution of the g_main_loop_run (loop);. If i simply remove all calls to the main loop (GMainLoop *loop = g_main_loop_new (nullptr, false); and previous) then service ceases to appear in bluetoothctl/sdptool browse. And if I add line g_main_loop_quit(loop); right after the g_main_loop_run (loop);, it also will not be executed, because the loop is still running. So what shall I do?

I've read the GMainLoop and GDBusProxy descriptions (GMainLoop, GDBusProxy), but it did not helped a lot. I've also seen this question, but code listed there is not complete and I am not sure what I should take from there and what I shouldn't.

1

There are 1 best solutions below

0
Gowrishankar Saminathan On

If I understood correctly, You might want to continue doing something after "register_profile()". I would suggest to register callbacks on the proxy interface and complete everything then finally stay in event loop.

If there is a signal from the proxy interface then your program will get it and call the appropriate callback function that you would have registered with proxy signal callbacks.

If this is not your use case then please elaborate more.