diff --git a/packages/cpp/dbus-proxy/dbus-proxy/callback-handling.cpp b/packages/cpp/dbus-proxy/dbus-proxy/callback-handling.cpp index 8ead0f4..de393b9 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/callback-handling.cpp +++ b/packages/cpp/dbus-proxy/dbus-proxy/callback-handling.cpp @@ -127,11 +127,21 @@ AgentData* find_registered_path(const gchar* unique_path) { return result; } +static const GDBusMethodTable* find_method_by_name_ptrs(const GDBusMethodTable* methods, + const gchar* name) { + for (guint i = 0; methods[i].name != nullptr; ++i) { + if (g_strcmp0(methods[i].name, name) == 0) { + return &methods[i]; + } + } + return nullptr; +} + const gchar* get_agent_name(const gchar* object_path, const gchar* interface_name, const gchar* method_name) { AgentData* result = find_registered_path(object_path); if (result && g_strcmp0(result->rule->client_interface, interface_name) == 0 && - !g_strv_contains(result->rule->client_methods, method_name)) { + !find_method_by_name_ptrs(result->rule->client_methods, method_name)) { Log::error() << "No agent found for object path " << object_path << " call " << interface_name << "." << method_name; return nullptr; @@ -152,8 +162,59 @@ void unregister_all_agent_registrations() { g_rw_lock_writer_unlock(&proxy_state->rw_lock); } +static GDBusArgInfo** build_arg_info_list(const gchar* sig, const gchar* prefix) { + if (!sig || sig[0] == '\0' || !prefix) { + return nullptr; + } + + GPtrArray* arr = g_ptr_array_new(); + const gchar* p = sig; + guint idx = 0; + + while (*p) { + const gchar* end = nullptr; + if (!g_variant_type_string_scan(p, nullptr, &end)) { + // invalid signature: free partial + for (guint i = 0; i < arr->len; ++i) { + auto* a = static_cast(g_ptr_array_index(arr, i)); + g_free(a->name); + g_free(a->signature); + g_free(a); + } + g_ptr_array_free(arr, TRUE); + return nullptr; + } + + GDBusArgInfo* arg = g_new0(GDBusArgInfo, 1); + arg->ref_count = 1; + arg->name = g_strdup_printf("%s%u", prefix, idx++); // in0, in1, out0... + arg->signature = g_strndup(p, end - p); + g_ptr_array_add(arr, arg); + + p = end; + } + + g_ptr_array_add(arr, nullptr); // NULL-terminate + return reinterpret_cast(g_ptr_array_free(arr, FALSE)); +} + +static void free_arg_info_list(GDBusArgInfo** args) { + if (!args) + return; + for (guint i = 0; args[i] != nullptr; ++i) { + g_free(args[i]->name); + g_free(args[i]->signature); + g_free(args[i]); + } + g_free(args); +} + void free_interface_info(GDBusInterfaceInfo* iface) { + if (!iface) + return; for (int i = 0; iface->methods && iface->methods[i]; i++) { + free_arg_info_list(iface->methods[i]->in_args); + free_arg_info_list(iface->methods[i]->out_args); g_free(iface->methods[i]->name); g_free(iface->methods[i]); } @@ -162,18 +223,46 @@ void free_interface_info(GDBusInterfaceInfo* iface) { g_free(iface); } -GDBusInterfaceInfo* build_interface_info(const gchar* iface_name, const gchar** methods) { +// Input: parameters is "(o)" or "(os)" +// Output: new variant with first field replaced by unique_agent_path. +// Caller owns returned GVariant* (g_variant_unref when done). +static GVariant* replace_first_with_unique_agent_path(GVariant* parameters, + const gchar* unique_agent_path) { + if (!parameters || !unique_agent_path) { + return nullptr; + } + + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(o)"))) { + return g_variant_new("(o)", unique_agent_path); + } + + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(os)"))) { + const gchar* old_path = nullptr; // ignored + const gchar* s = nullptr; + g_variant_get(parameters, "(&o&s)", &old_path, &s); + return g_variant_new("(os)", unique_agent_path, s); + } + + return nullptr; // unsupported type +} + +GDBusInterfaceInfo* build_interface_info(const AgentRule* rule) { GDBusInterfaceInfo* iface = g_new0(GDBusInterfaceInfo, 1); iface->ref_count = 1; - iface->name = g_strdup(iface_name); + iface->name = g_strdup(rule->client_interface); - int n = g_strv_length(static_cast(const_cast(methods))); - iface->methods = g_new0(GDBusMethodInfo*, n + 1); + int method_count = 0; + for (int i = 0; rule->client_methods[i].name != nullptr; i++) { + method_count++; + } + iface->methods = g_new0(GDBusMethodInfo*, method_count + 1); - for (int i = 0; i < n; i++) { + for (int i = 0; i < method_count; i++) { GDBusMethodInfo* m = g_new0(GDBusMethodInfo, 1); m->ref_count = 1; - m->name = g_strdup(methods[i]); + m->name = g_strdup(rule->client_methods[i].name); + m->in_args = build_arg_info_list(rule->client_methods[i].in_signature, "in"); + m->out_args = build_arg_info_list(rule->client_methods[i].out_signature, "out"); iface->methods[i] = m; } @@ -182,7 +271,8 @@ GDBusInterfaceInfo* build_interface_info(const gchar* iface_name, const gchar** gboolean handle_agent_register_call(const gchar* sender, const gchar* object_path G_GNUC_UNUSED, const gchar* interface_name, const gchar* method_name, - GVariant* parameters) { + GVariant* parameters, GDBusMethodInvocation* invocation, + guint message_count) { const AgentRule* rule = get_callback_rule(proxy_state->config.source_bus_name, interface_name, method_name); @@ -195,54 +285,49 @@ gboolean handle_agent_register_call(const gchar* sender, const gchar* object_pat Log::info() << "Handling register call for " << sender << " " << interface_name << "." << method_name; - // When the object path is customisable, the first parameter is expected - // to be a D-Bus object path (`&o` in the GVariant signature). This branch - // should be exercised with: - // - correctly formatted object paths to confirm successful registration, - // - missing or NULL parameters to verify that we log an error and return - // FALSE without dereferencing invalid data, - // - unusual but valid sender names to ensure that combining `agent_path` - // and `sender` and then normalising with `g_strdelimit` still produces - // a valid and unique D-Bus object path. - - // Build unique agent path - gchar* unique_agent_path = NULL; + // Generate unique object path for this registration, combining sender name + // and agent path from parameters if needed, to allow multiple registrations + // from the same sender + gchar* unique_agent_path = nullptr; + gchar* agent_path = nullptr; + + GVariant* param = g_variant_get_child_value(parameters, 0); + if (g_variant_is_of_type(param, G_VARIANT_TYPE_OBJECT_PATH)) { + agent_path = g_variant_dup_string(param, nullptr); // owned copy + } + g_variant_unref(param); - if (rule->object_path_customisable) { - // jarekk: test it - // Extract agent path from parameters - const gchar* agent_path = NULL; - g_variant_get(parameters, "(&o)", - &agent_path); // Assuming first param is object - - if (!agent_path) { - Log::error() << "Failed to extract agent path from parameters"; - return FALSE; - } + if (!agent_path) { + Log::error() + << "Expected first parameter to be an object path string, but got different type"; + return FALSE; + } + if (rule->object_path_customisable) { + Log::info() << "Extracted agent path from parameters: " << agent_path; unique_agent_path = g_strdup_printf("%s/%s", agent_path, sender); g_strdelimit(unique_agent_path, ".:", '_'); } else { - unique_agent_path = g_strdup(rule->client_object_path); + unique_agent_path = g_strdup(agent_path); } - // Check if already registered + // Register a new object if already not registered AgentData* path_registered = find_registered_path(unique_agent_path); guint reg_id = 0; GDBusInterfaceInfo* iface = nullptr; - if (path_registered) { - if (g_strcmp0(path_registered->owner, sender) == 0) { - Log::error() << "Sender " << sender << " is already registered at path " - << unique_agent_path; - g_free(unique_agent_path); - return TRUE; - } - Log::info() << "Sender " << sender << " attempts to register agent at path " - << unique_agent_path << " (" << interface_name << "." << method_name << ")"; + if ((path_registered) && (g_strcmp0(path_registered->owner, sender) == 0)) { + Log::error() << "Sender " << sender << " is already registered at path " + << unique_agent_path; + g_dbus_method_invocation_return_error( + invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Agent is already registered for this sender and path"); + g_free(unique_agent_path); + g_free(agent_path); + return TRUE; } else { // Register new object - GError* error = NULL; - iface = build_interface_info(interface_name, rule->client_methods); + GError* error = nullptr; + iface = build_interface_info(rule); static const GDBusInterfaceVTable vtable = {.method_call = handle_method_call_generic, .get_property = NULL, @@ -251,8 +336,8 @@ gboolean handle_agent_register_call(const gchar* sender, const gchar* object_pat reg_id = g_dbus_connection_register_object(proxy_state->source_bus, unique_agent_path, iface, &vtable, - g_strdup(unique_agent_path), // user_data - g_free, // free user_data + g_strdup(agent_path), // user_data + g_free, // free user_data &error); if (reg_id == 0) { @@ -261,10 +346,14 @@ gboolean handle_agent_register_call(const gchar* sender, const gchar* object_pat g_clear_error(&error); free_interface_info(iface); g_free(unique_agent_path); + g_free(agent_path); return FALSE; } } + // Store registration in registry with sender and unique path, so we can + // properly handle multiple registrations from the same sender and cleanup on + // unregistration or NameOwnerChanged if (register_agent_callback(sender, rule->client_object_path, unique_agent_path, interface_name, method_name, reg_id, iface)) { Log::info() << "Callback registered: sender " << sender << " path " @@ -272,31 +361,63 @@ gboolean handle_agent_register_call(const gchar* sender, const gchar* object_pat << interface_name << "." << method_name << ") reg_id " << reg_id; } else { Log::error() << "Failed to store callback registration"; - g_dbus_connection_unregister_object(proxy_state->source_bus, reg_id); + if (reg_id != 0) { + g_dbus_connection_unregister_object(proxy_state->source_bus, reg_id); + } + free_interface_info(iface); g_free(unique_agent_path); + g_free(agent_path); return FALSE; } - g_free(unique_agent_path); if (reg_id == 0) { // Inform caller to skip registration call on the server // side, because this was just a registry update for an // already registered path + g_dbus_method_invocation_return_value(invocation, nullptr); + g_free(unique_agent_path); + return TRUE; + + } else { + GVariant* params = replace_first_with_unique_agent_path(parameters, unique_agent_path); + g_free(unique_agent_path); + if (!params) { + Log::error() << "Failed to build parameters for method call"; + g_dbus_method_invocation_return_value(invocation, nullptr); + return TRUE; + } + + MethodCallContext* context = g_new0(MethodCallContext, 1); + context->invocation = invocation; + context->forward_bus_name = g_strdup(proxy_state->config.source_bus_name); + context->call_number = message_count; // Set call number for logging + + g_object_ref(invocation); + + // Forward the Register call to the server with the unique path as a + // parameter, so the server can identify the caller if needed. The reply + // will be handled in the generic method call handler, which will route it + // back to the correct invocation. + g_dbus_connection_call(proxy_state->source_bus, proxy_state->config.source_bus_name, + object_path, interface_name, method_name, params, nullptr, + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, method_call_reply_callback, + context); return TRUE; } + return FALSE; } -gboolean handle_agent_unregister_call(const gchar* sender, const gchar* object_path G_GNUC_UNUSED, - const gchar* interface_name G_GNUC_UNUSED, - const gchar* method_name G_GNUC_UNUSED, - GVariant* parameters G_GNUC_UNUSED) { - Log::info() << "Handling callback unregistration for " << sender << " at " << object_path - << " method " << method_name; +void handle_agent_unregister_call(const gchar* sender, const gchar* object_path, + const gchar* interface_name, const gchar* method_name, + GVariant* parameters, GDBusMethodInvocation* invocation, + guint message_count) { + Log::info() << "Handling callback unregistration [" << message_count << "] for " << sender + << " at " << object_path << " method " << method_name; /* Find registration ID for this sender by sender */ g_rw_lock_writer_lock(&proxy_state->rw_lock); // Iterate over the agents registry to find all registrations for this sender // and remove them - gboolean secondary_agent = FALSE; + gboolean found = FALSE; for (guint i = 0; i < proxy_state->agents_registry->len; i++) { AgentData* data = static_cast(g_ptr_array_index(proxy_state->agents_registry, i)); @@ -304,19 +425,53 @@ gboolean handle_agent_unregister_call(const gchar* sender, const gchar* object_p g_strcmp0(data->rule->manager_path, object_path) == 0 && g_strcmp0(data->rule->manager_interface, interface_name) == 0 && g_strcmp0(data->rule->unregister_method, method_name) == 0) { - Log::info() << "Found Unregister data for sender " << sender << " unique path " - << object_path << " path " << method_name; + found = TRUE; + Log::info() << "Found Unregister data [" << message_count << "] for sender " << sender + << " unique path " << object_path << " path " << method_name; if (data->agent_object_reg_id == 0) { - Log::info() << "This was a secondary registration for sender " << sender + Log::info() << "This was a secondary registration [" << message_count + << "] for sender " << sender << ", skipping unregistration on the server"; - secondary_agent = TRUE; + g_dbus_method_invocation_return_value(invocation, nullptr); + } else { + // We need to call Unregister method on the server for this callback to + // allow proper cleanup on the server side. + // Rewrite parameters with the unique agent path if needed, so server + // can identify the caller. This is needed in case of multiple + // registrations from the same sender, to allow proper unregistration of + // the correct callback on the server side. + GVariant* params = nullptr; + params = replace_first_with_unique_agent_path(parameters, data->unique_object_path); + + if (!params) { + Log::error() << "Failed to build parameters for Unregister method call"; + g_dbus_method_invocation_return_value(invocation, nullptr); + g_rw_lock_writer_unlock(&proxy_state->rw_lock); + return; + } + + MethodCallContext* context = g_new0(MethodCallContext, 1); + context->invocation = invocation; + context->forward_bus_name = g_strdup(proxy_state->config.source_bus_name); + context->call_number = message_count; // Set call number for logging + g_object_ref(invocation); + + g_dbus_connection_call(proxy_state->source_bus, proxy_state->config.source_bus_name, + object_path, interface_name, method_name, params, nullptr, + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, + method_call_reply_callback, context); } g_ptr_array_remove(proxy_state->agents_registry, data); break; } } + if (!found) { + Log::error() << "No registration found for sender " << sender << " path " << object_path + << " method " << method_name; + g_dbus_method_invocation_return_value(invocation, nullptr); + } g_rw_lock_writer_unlock(&proxy_state->rw_lock); - return secondary_agent; + return; } static void on_name_owner_changed(GDBusConnection* connection G_GNUC_UNUSED, @@ -346,10 +501,10 @@ static void on_name_owner_changed(GDBusConnection* connection G_GNUC_UNUSED, // Find and release all callbacks associated with the old owner g_rw_lock_writer_lock(&proxy_state->rw_lock); - // We are deeling usually with very few callbacks per sender, so iterating + // We are dealing usually with very few callbacks per sender, so iterating // over the array should be fine // We are dealing usually with very few callbacks per sender, so iterating - for (guint i = proxy_state->agents_registry->len; i-- > 0;) { + for (guint i = 0; i < proxy_state->agents_registry->len; i++) { AgentData* data = static_cast(g_ptr_array_index(proxy_state->agents_registry, i)); if (g_strcmp0(data->owner, old_owner) == 0) { @@ -361,12 +516,16 @@ static void on_name_owner_changed(GDBusConnection* connection G_GNUC_UNUSED, // for the same object path, so we should not notify server with // Unregister it yet if (data->agent_object_reg_id) { - GError* error = NULL; + GError* error = nullptr; + GVariant* custom_parameters = nullptr; + if (data->rule->use_object_path_on_unregister) { + custom_parameters = g_variant_new("(o)", data->unique_object_path); + } g_dbus_connection_call_sync(proxy_state->source_bus, proxy_state->config.source_bus_name, data->rule->manager_path, data->rule->manager_interface, - data->rule->unregister_method, nullptr, nullptr, - G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); + data->rule->unregister_method, custom_parameters, + nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error); if (error) { Log::error() << "Failed to call Unregister method for sender " << data->owner << ": " << error->message; @@ -379,7 +538,8 @@ static void on_name_owner_changed(GDBusConnection* connection G_GNUC_UNUSED, Log::verbose() << "Skipping Unregister call for sender " << data->owner << " because this was a secondary registration"; } - g_ptr_array_remove_index(proxy_state->agents_registry, i); + g_ptr_array_remove(proxy_state->agents_registry, data); + i--; // Adjust index after removal } } g_rw_lock_writer_unlock(&proxy_state->rw_lock); diff --git a/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.cpp b/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.cpp index fa880ce..81b8543 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.cpp +++ b/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.cpp @@ -5,8 +5,21 @@ #include "dbus_proxy.h" -const gchar* nm_agent_methods[] = {"GetSecrets", "CancelGetSecrets", "SaveSecrets", "DeleteSecrets", - nullptr}; +const GDBusMethodTable nm_agent_methods[] = {{"GetSecrets", "a{sa{sv}}osasu", "a{sa{sv}}"}, + {"CancelGetSecrets", "os", ""}, + {"SaveSecrets", "a{sa{sv}}o", ""}, + {"DeleteSecrets", "a{sa{sv}}o", ""}, + {nullptr, nullptr, nullptr}}; + +const GDBusMethodTable bluez_agent_methods[] = { + {"RequestPinCode", "o", "s"}, {"DisplayPinCode", "os", ""}, + {"RequestPasskey", "o", "u"}, {"DisplayPasskey", "ouq", ""}, + {"RequestConfirmation", "ou", ""}, {"RequestAuthorization", "o", ""}, + {"AuthorizeService", "os", ""}, {"Cancel", "", ""}, + {nullptr, nullptr, nullptr}}; + +const GDBusMethodTable obex_agent_methods[] = { + {"CreateSession", "s", "sa{sv}"}, {"RemoveSession", "o", ""}, {nullptr, nullptr, nullptr}}; const AgentRule callbacks_rules[] = { {.bus_name = DBUS_NETWORK_MANAGER_NAME, @@ -14,6 +27,7 @@ const AgentRule callbacks_rules[] = { .manager_interface = "org.freedesktop.NetworkManager.AgentManager", .register_method = "Register", .unregister_method = "Unregister", + .use_object_path_on_unregister = FALSE, .object_path_customisable = FALSE, .client_object_path = DBUS_NM_AGENT_PATH, .client_interface = DBUS_INTERFACE_SECRET_AGENT, @@ -24,12 +38,38 @@ const AgentRule callbacks_rules[] = { .manager_interface = "org.freedesktop.NetworkManager.AgentManager", .register_method = "RegisterWithCapabilities", .unregister_method = "Unregister", + .use_object_path_on_unregister = FALSE, .object_path_customisable = FALSE, .client_object_path = DBUS_NM_AGENT_PATH, .client_interface = DBUS_INTERFACE_SECRET_AGENT, .client_methods = nm_agent_methods}, - {nullptr, nullptr, nullptr, nullptr, nullptr, FALSE, nullptr, nullptr, nullptr}}; + + {.bus_name = DBUS_BLUEZ_NAME, + .manager_path = "/org/bluez", + .manager_interface = "org.bluez.AgentManager1", + .register_method = "RegisterAgent", + .unregister_method = "UnregisterAgent", + .use_object_path_on_unregister = TRUE, + .object_path_customisable = FALSE, + + .client_object_path = DBUS_BLUEZ_AGENT_PATH, + .client_interface = DBUS_BLUEZ_AGENT_INTERFACE, + .client_methods = bluez_agent_methods}, + + {.bus_name = DBUS_OBEX_NAME, + .manager_path = "/org/bluez/obex", + .manager_interface = "org.bluez.obex.AgentManager1", + .register_method = "RegisterAgent", + .unregister_method = "UnregisterAgent", + .use_object_path_on_unregister = FALSE, + .object_path_customisable = FALSE, + + .client_object_path = DBUS_OBEX_AGENT_PATH, + .client_interface = DBUS_OBEX_AGENT_INTERFACE, + .client_methods = obex_agent_methods}, + + {nullptr, nullptr, nullptr, nullptr, nullptr, FALSE, FALSE, nullptr, nullptr, nullptr}}; const AgentRule* get_callback_rule(const gchar* bus_name, const gchar* interface_name, const gchar* method_name) { diff --git a/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.h b/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.h index 257313b..d5dbb2c 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.h +++ b/packages/cpp/dbus-proxy/dbus-proxy/callback-rules.h @@ -9,19 +9,27 @@ #ifndef CALLBACK_RULES_H #define CALLBACK_RULES_H +typedef struct { + const gchar* name; // method name + const gchar* in_signature; // e.g. "os", "a{sv}", "" (or nullptr) + const gchar* out_signature; // e.g. "", "b", "o" +} GDBusMethodTable; + struct AgentRule { - const gchar* bus_name; // "org.bluez" - const gchar* manager_path; // "/org/freedesktop/NetworkManager/AgentManager" - const gchar* manager_interface; // "org.bluez.AgentManager1" - const gchar* register_method; // "RegisterAgent" - const gchar* unregister_method; // "UnregisterAgent" + const gchar* bus_name; // "org.bluez" + const gchar* manager_path; // "/org/freedesktop/NetworkManager/AgentManager" + const gchar* manager_interface; // "org.bluez.AgentManager1" + const gchar* register_method; // "RegisterAgent" + const gchar* unregister_method; // "UnregisterAgent" + const gboolean use_object_path_on_unregister; // whether to use the object path or unique path + // for unregistration // set to true when client sends its agent object path // which can be customized const gboolean object_path_customisable; - const gchar* client_object_path; // "/org/bluez/agent" - const gchar* client_interface; // "org.bluez.Agent1" - const gchar** client_methods; // NULL-terminated array of method names + const gchar* client_object_path; // "/org/bluez/agent" + const gchar* client_interface; // "org.bluez.Agent1" + const GDBusMethodTable* client_methods; // NULL-terminated array of method tables }; extern const AgentRule callbacks_rules[]; diff --git a/packages/cpp/dbus-proxy/dbus-proxy/dbus_proxy.h b/packages/cpp/dbus-proxy/dbus-proxy/dbus_proxy.h index a12cd5c..69e898d 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/dbus_proxy.h +++ b/packages/cpp/dbus-proxy/dbus-proxy/dbus_proxy.h @@ -41,11 +41,11 @@ typedef struct { guint catch_interfaces_removed_subscription_id; GHashTable* proxied_objects; GHashTable* node_info_cache; - GPtrArray* agents_registry; /* jarekk: temporary, to be replaced */ - GHashTable* senders_registry; + GPtrArray* agents_registry; GRWLock rw_lock; guint sigint_source_id; guint sigterm_source_id; + guint message_count; GMainLoop* main_loop; } ProxyState; @@ -68,6 +68,7 @@ struct AgentData { struct MethodCallContext { GDBusMethodInvocation* invocation; gchar* forward_bus_name; + guint call_number; // For logging purposes }; extern ProxyState* proxy_state; @@ -124,7 +125,7 @@ void handle_method_call_generic(GDBusConnection* connection, const gchar* sender GBusType parse_bus_type(const gchar* bus_str); void validateProxyConfigOrExit(ProxyConfig* config); void method_call_reply_callback(GObject* source, GAsyncResult* res, gpointer user_data); -GDBusInterfaceInfo* build_interface_info(const gchar* iface_name, const gchar** methods); +GDBusInterfaceInfo* build_interface_info(const AgentRule* rule); void free_interface_info(GDBusInterfaceInfo* iface); const gchar* get_agent_name(const gchar* object_path, const gchar* interface_name, const gchar* method_name); @@ -135,14 +136,15 @@ gboolean register_agent_callback(const gchar* sender, const gchar* object_path, GDBusInterfaceInfo* ifac); gboolean handle_agent_register_call(const gchar* sender, const gchar* object_path, const gchar* interface_name, const gchar* method_name, - GVariant* parameters); -gboolean handle_agent_unregister_call(const gchar* sender, const gchar* object_path, - const gchar* interface_name, const gchar* method_name, - GVariant* parameters); + GVariant* parameters, GDBusMethodInvocation* invocation, + guint message_count); +void handle_agent_unregister_call(const gchar* sender, const gchar* object_path, + const gchar* interface_name, const gchar* method_name, + GVariant* parameters, GDBusMethodInvocation* invocation, + guint message_count); void unregister_all_agent_registrations(); void free_agent_callback_data(gpointer ptr); GDBusConnection* get_sender_dbus_connection(const gchar* sender_name); -// jarekk gchar *get_sender_name_from_connection(GDBusConnection *connection); GHashTable* get_sender_callbacks(const gchar* sender_name); #endif // GHAF_DBUS_PROXY_H diff --git a/packages/cpp/dbus-proxy/dbus-proxy/gdbusprivate.h b/packages/cpp/dbus-proxy/dbus-proxy/gdbusprivate.h index 3f7ac5f..42036a3 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/gdbusprivate.h +++ b/packages/cpp/dbus-proxy/dbus-proxy/gdbusprivate.h @@ -19,10 +19,13 @@ constexpr const gchar* DBUS_NETWORK_MANAGER_NAME = "org.freedesktop.NetworkManag constexpr const gchar* DBUS_INTERFACE_SECRET_AGENT = "org.freedesktop.NetworkManager.SecretAgent"; constexpr const gchar* DBUS_NM_AGENT_PATH = "/org/freedesktop/NetworkManager/SecretAgent"; -constexpr const gchar* DBUS_BT_AGENT_PATH = "/org/bluez/agent"; -constexpr const gchar* DBUS_INTERFACE_BT_AGENT = "org.bluez.Agent1"; +constexpr const gchar* DBUS_BLUEZ_NAME = "org.bluez"; +constexpr const gchar* DBUS_BLUEZ_AGENT_PATH = "/org/bluez/agent"; +constexpr const gchar* DBUS_BLUEZ_AGENT_INTERFACE = "org.bluez.Agent1"; -constexpr const gchar* DBUS_OBJECT_PATH_NETWORK_MANAGER = "/org/freedesktop/NetworkManager"; +constexpr const gchar* DBUS_OBEX_NAME = "org.bluez.obex"; +constexpr const gchar* DBUS_OBEX_AGENT_PATH = "/org/bluez/obex"; +constexpr const gchar* DBUS_OBEX_AGENT_INTERFACE = "org.bluez.obex.Agent"; // SNI (StatusNotifierItem) protocol constants constexpr const gchar* SNI_WATCHER_INTERFACE = "org.kde.StatusNotifierWatcher"; diff --git a/packages/cpp/dbus-proxy/dbus-proxy/handlers.cpp b/packages/cpp/dbus-proxy/dbus-proxy/handlers.cpp index 0fdeaf1..1addeae 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/handlers.cpp +++ b/packages/cpp/dbus-proxy/dbus-proxy/handlers.cpp @@ -17,6 +17,7 @@ static void proxy_return_error(GDBusMethodInvocation* invocation, GError* error) if (remote) { g_dbus_method_invocation_return_dbus_error(invocation, remote, error->message); + g_free((gpointer)remote); } else { g_dbus_method_invocation_return_gerror(invocation, error); } @@ -29,17 +30,19 @@ void method_call_reply_callback(GObject* source, GAsyncResult* res, gpointer use GVariant* result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); if (result) { - Log::verbose() << "Method call successful, returning result"; + Log::verbose() << "Method call [" << context->call_number + << "] successful, returning result"; g_dbus_method_invocation_return_value(context->invocation, result); g_variant_unref(result); } else { - Log::error() << "Method call failed: " << (error ? error->message : "Unknown error"); + Log::error() << "Method call [" << context->call_number + << "] failed: " << (error ? error->message : "Unknown error"); proxy_return_error(context->invocation, error); g_clear_error(&error); } g_object_unref(context->invocation); - g_free(context->forward_bus_name); + g_free((gpointer)context->forward_bus_name); g_free(context); } @@ -49,11 +52,13 @@ void handle_method_call_generic(GDBusConnection* connection, const gchar* sender const gchar* method_name, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer user_data) { - const gchar* target_object_path = static_cast(user_data); + const gchar* target_object_path = + user_data ? static_cast(user_data) : object_path; + guint message_count = ++proxy_state->message_count; // Increment message count for logging - Log::verbose() << "Method call: " << interface_name << "." << method_name << " on " - << object_path << " from " << sender << " (forwarding to " << target_object_path - << ")"; + Log::verbose() << "Method call [" << message_count << "]: " << interface_name << "." + << method_name << " on " << object_path << " from " << sender + << " (forwarding to " << target_object_path << ")"; GDBusConnection* forward_bus = nullptr; gchar* forward_bus_name = nullptr; @@ -64,27 +69,19 @@ void handle_method_call_generic(GDBusConnection* connection, const gchar* sender // Handle Register/Unregister methods if (g_str_has_prefix(method_name, "Register")) { - // Add client's agent callback to our registry - // Skip forwarding the call if the agent is already registered + // Handle agent registration method, extract agent path from parameters, + // register callback and store in registry and handle call to + // the server if registration is successful if (handle_agent_register_call(sender, object_path, interface_name, method_name, - parameters)) { - // Generate DBus reply indicating success, predending we handled the - // registration - g_dbus_method_invocation_return_value(invocation, nullptr); + parameters, invocation, message_count)) { + return; }; } else if (g_str_has_prefix(method_name, "Unregister")) { - // Check if method name starts with Unregister - Log::error() << "Method " << method_name << " detected as unregistration method"; // Remove client's agent callback from our registry - // Skip forwarding the call if the agent is already unregistered - if (handle_agent_unregister_call(sender, object_path, interface_name, method_name, - parameters)) { - // Generate DBus reply indicating success, predending we handled the - // unregistration - g_dbus_method_invocation_return_value(invocation, nullptr); - return; - } + handle_agent_unregister_call(sender, object_path, interface_name, method_name, + parameters, invocation, message_count); + return; } } else { // call comes from source bus, forward back to client @@ -109,6 +106,7 @@ void handle_method_call_generic(GDBusConnection* connection, const gchar* sender MethodCallContext* context = g_new0(MethodCallContext, 1); context->invocation = invocation; context->forward_bus_name = forward_bus_name; + context->call_number = message_count; // Set call number for logging g_object_ref(invocation); diff --git a/packages/cpp/dbus-proxy/dbus-proxy/proxy_core.cpp b/packages/cpp/dbus-proxy/dbus-proxy/proxy_core.cpp index fc14d09..f41a110 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/proxy_core.cpp +++ b/packages/cpp/dbus-proxy/dbus-proxy/proxy_core.cpp @@ -41,6 +41,9 @@ gboolean init_proxy_state(const ProxyConfig* config) { proxy_state->sigterm_source_id = g_unix_signal_add(SIGTERM, signal_handler, GINT_TO_POINTER(SIGTERM)); + // Initialize message count for logging purposes + proxy_state->message_count = 0; + return TRUE; } @@ -377,9 +380,7 @@ gboolean proxy_single_object(const gchar* object_path, GDBusNodeInfo* node_info, GError* error = nullptr; guint registration_id = g_dbus_connection_register_object( - proxy_state->target_bus, object_path, iface, &vtable, - g_strdup(object_path), // Pass object path as user_data for forwarding - g_free, &error); + proxy_state->target_bus, object_path, iface, &vtable, nullptr, g_free, &error); if (registration_id == 0) { Log::error() << "Failed to register interface " << iface->name << " on " << object_path @@ -464,9 +465,8 @@ gboolean register_single_interface(const gchar* object_path, const gchar* interf .set_property = nullptr, .padding = {nullptr}}; - guint registration_id = - g_dbus_connection_register_object(proxy_state->target_bus, object_path, iface_info, &vtable, - g_strdup(object_path), g_free, &error); + guint registration_id = g_dbus_connection_register_object( + proxy_state->target_bus, object_path, iface_info, &vtable, nullptr, g_free, &error); if (registration_id == 0) { Log::error() << "Failed to register interface " << interface_name << " on " << object_path @@ -660,10 +660,6 @@ void cleanup_proxy_state() { } unregister_all_agent_registrations(); - if (proxy_state->senders_registry) { - g_hash_table_destroy(proxy_state->senders_registry); - proxy_state->senders_registry = nullptr; - } if (proxy_state->introspection_data) { g_dbus_node_info_unref(proxy_state->introspection_data); diff --git a/packages/cpp/dbus-proxy/dbus-proxy/sni/proxy.cpp b/packages/cpp/dbus-proxy/dbus-proxy/sni/proxy.cpp index 6e7550c..467cecf 100644 --- a/packages/cpp/dbus-proxy/dbus-proxy/sni/proxy.cpp +++ b/packages/cpp/dbus-proxy/dbus-proxy/sni/proxy.cpp @@ -1665,15 +1665,15 @@ void SniProxy::on_item_name_acquired(G_GNUC_UNUSED GDBusConnection* conn, const [](GObject* source, GAsyncResult* res, gpointer user_data) { auto ctx = std::unique_ptr( static_cast(user_data)); - GError* error = nullptr; + GError* err = nullptr; GVariant* result = - g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); + g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err); if (result) { Log::info() << "[REPLY] RegisterStatusNotifierItem to target watcher OK"; g_variant_unref(result); } else { Log::error() << "[REPLY] RegisterStatusNotifierItem to target watcher failed"; - g_clear_error(&error); + g_clear_error(&err); } // ctx unique_ptr destructor frees forward_bus_name },