From 5c304fd22d366f846246c71210a1d45d2a731f85 Mon Sep 17 00:00:00 2001 From: Radoslaw Pajak Date: Thu, 21 Nov 2013 13:52:29 +0100 Subject: [PATCH] [daemon-dev] List of queued owners read from kdbus From now, when method org.freedesktop.DBus.ListQueuedOwners is called, daemon asks kdbus for the list, instead of preparing it from it's own data. Needs kdbus with commit 816abfc [feature] added ioctl KDBUS_CMD_NAME_LIST_QUEUED from 21.11.2013 Change-Id: If6a6f4bbe8dc910160a661191ec1b067a796da34 Signed-off-by: Radoslaw Pajak --- bus/driver.c | 41 +++++++++++++++++++---- bus/kdbus-d.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bus/kdbus-d.h | 1 + dbus/kdbus.h | 1 + 4 files changed, 140 insertions(+), 7 deletions(-) diff --git a/bus/driver.c b/bus/driver.c index 57265e5..9633bc5 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -46,6 +46,7 @@ #include #include #include +#include #endif static DBusConnection * @@ -473,7 +474,6 @@ bus_driver_handle_list_services (DBusConnection *connection, else #endif { - if (!bus_registry_list_services (registry, &services, &len)) { dbus_message_unref (reply); @@ -1366,7 +1366,11 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, if (! _dbus_list_append (&base_names, dbus_service_name)) goto oom; } +#ifdef ENABLE_KDBUS_TRANSPORT + else if (!bus_context_is_kdbus(bus_transaction_get_context (transaction)) && (service == NULL)) +#else else if (service == NULL) +#endif { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, @@ -1375,10 +1379,20 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, } else { - if (!bus_service_list_queued_owners (service, - &base_names, - error)) - goto failed; +#ifdef ENABLE_KDBUS_TRANSPORT + if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) + { + if(!kdbus_list_queued (connection, &base_names, text ,error)) + goto failed; + } + else +#endif + { + if (!bus_service_list_queued_owners (service, + &base_names, + error)) + goto failed; + } } _dbus_assert (base_names != NULL); @@ -1419,6 +1433,21 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, dbus_message_unref (reply); + if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) + { + link = _dbus_list_get_first_link (&base_names); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&base_names, link); + + if(link->data != NULL) + free(link->data); + + _dbus_list_free_link (link); + link = next; + } + } + return TRUE; oom: @@ -1428,10 +1457,8 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); - if (base_names) _dbus_list_clear (&base_names); - return FALSE; } diff --git a/bus/kdbus-d.c b/bus/kdbus-d.c index 70a1a86..be9fccc 100644 --- a/bus/kdbus-d.c +++ b/bus/kdbus-d.c @@ -593,6 +593,110 @@ out: } /* + * Asks kdbus for list of connections being in the queue to own + * given well-known name. The list includes the owner of the name on the + * first position. + */ +dbus_bool_t kdbus_list_queued (DBusConnection *connection, DBusList **return_list, + const char *name, DBusError *error) +{ + int fd; + struct kdbus_cmd_names* pCmd; + __u64 cmd_size; + dbus_bool_t ret_val = FALSE; + int name_length; + + _dbus_assert (*return_list == NULL); + + name_length = strlen(name) + 1; + cmd_size = sizeof(struct kdbus_cmd_names) + sizeof(struct kdbus_cmd_name) + name_length; + pCmd = malloc(cmd_size); + if(pCmd == NULL) + goto out; + pCmd->size = cmd_size; + pCmd->names[0].id = 0; + pCmd->names[0].size = sizeof(struct kdbus_cmd_name) + name_length; + memcpy(pCmd->names[0].name, name, name_length); + _dbus_verbose ("Asking for queued owners of %s\n", pCmd->names[0].name); + + _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd); + + again: + cmd_size = 0; + if(ioctl(fd, KDBUS_CMD_NAME_LIST_QUEUED, pCmd)) + { + if(errno == EINTR) + goto again; + if(errno == ENOBUFS) //buffer to small to put all names into it + cmd_size = pCmd->size; //here kernel tells how much memory it needs + else if(errno == ENOENT) + { + dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get owners of name '%s': no such name", name); + free(pCmd); + return FALSE; + } + else + { + _dbus_verbose("kdbus error asking for queued owners list: err %d (%m)\n",errno); + goto out; + } + } + if(cmd_size) //kernel needs more memory + { + pCmd = realloc(pCmd, cmd_size); //prepare memory + if(pCmd == NULL) + return FALSE; + goto again; //and try again + } + else + { + struct kdbus_cmd_name* pCmd_name; + + for (pCmd_name = pCmd->names; (uint8_t *)(pCmd_name) < (uint8_t *)(pCmd) + pCmd->size; pCmd_name = KDBUS_PART_NEXT(pCmd_name)) + { + char *uname = NULL; + + _dbus_verbose ("Got queued owner id: %llu\n", (unsigned long long)pCmd_name->id); + uname = malloc(snprintf(uname, 0, ":1.%llu0", (unsigned long long)pCmd_name->id)); + if(uname == NULL) + goto out; + sprintf(uname, ":1.%llu", (unsigned long long int)pCmd_name->id); + if (!_dbus_list_append (return_list, uname)) + goto out; + } + } + + ret_val = TRUE; + + out: + if(pCmd) + free(pCmd); + if(ret_val == FALSE) + { + DBusList *link; + + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to list queued owners of \"%s\": %s", + name, _dbus_strerror (errno)); + + link = _dbus_list_get_first_link (return_list); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (return_list, link); + + if(link->data != NULL) + free(link->data); + + _dbus_list_free_link (link); + link = next; + } + } + + return ret_val; +} + +/* * Register match rule in kdbus on behalf of sender of the message */ dbus_bool_t kdbus_add_match_rule (DBusConnection* connection, DBusMessage* message, const char* text, DBusError* error) diff --git a/bus/kdbus-d.h b/bus/kdbus-d.h index ce436da..0423221 100644 --- a/bus/kdbus-d.h +++ b/bus/kdbus-d.h @@ -42,6 +42,7 @@ dbus_bool_t kdbus_register_policy (const DBusString *service_name, DBusConnectio dbus_uint32_t kdbus_request_name(DBusConnection* connection, const DBusString *service_name, dbus_uint32_t flags, __u64 sender_id); dbus_uint32_t kdbus_release_name(DBusConnection* connection, const DBusString *service_name, __u64 sender_id); dbus_bool_t kdbus_list_services (DBusConnection* connection, char ***listp, int *array_len); +dbus_bool_t kdbus_list_queued (DBusConnection *connection, DBusList **return_list, const char *name, DBusError *error); dbus_bool_t kdbus_add_match_rule (DBusConnection* connection, DBusMessage* message, const char* text, DBusError* error); dbus_bool_t kdbus_remove_match (DBusConnection* connection, DBusMessage* message, DBusError* error); diff --git a/dbus/kdbus.h b/dbus/kdbus.h index 7eb9527..c6a58ef 100644 --- a/dbus/kdbus.h +++ b/dbus/kdbus.h @@ -432,6 +432,7 @@ enum { KDBUS_CMD_NAME_RELEASE = _IOW(KDBUS_IOC_MAGIC, 0x51, struct kdbus_cmd_name), KDBUS_CMD_NAME_LIST = _IOWR(KDBUS_IOC_MAGIC, 0x52, struct kdbus_cmd_names), KDBUS_CMD_NAME_QUERY = _IOWR(KDBUS_IOC_MAGIC, 0x53, struct kdbus_cmd_name_info), + KDBUS_CMD_NAME_LIST_QUEUED = _IOWR(KDBUS_IOC_MAGIC, 0x54, struct kdbus_cmd_names), KDBUS_CMD_MATCH_ADD = _IOW(KDBUS_IOC_MAGIC, 0x60, struct kdbus_cmd_match), KDBUS_CMD_MATCH_REMOVE = _IOW(KDBUS_IOC_MAGIC, 0x61, struct kdbus_cmd_match), -- 2.7.4