From bd6d8d261df61ed8b396434e5a80285d43184d6c Mon Sep 17 00:00:00 2001 From: Radoslaw Pajak Date: Wed, 2 Oct 2013 14:38:17 +0200 Subject: [PATCH] [daemon-dev][daemon-fix] starting services by direct message (autostart) and some fixes - added auto starting services (by directly addressed message) - daemon starts the service and then pass a pending message to it this needs appropiriate kdbus changes - KDBUS_NAME_STARTER must be handled by kdbus (since 02.10.2013) - fixes for name aquiring and releasing Change-Id: Ied7746233132a9ab3bd3377fb563c85558486650 Signed-off-by: Radoslaw Pajak --- autogen.sh | 2 +- bus/activation.c | 9 ++++- bus/driver.c | 9 +++-- bus/kdbus-d.c | 30 ++++++++-------- bus/kdbus-d.h | 2 +- bus/services.c | 85 ++++++++++++++++++++++++++++++++++++++------- dbus/dbus-connection.c | 41 +++++++++++++++++----- dbus/dbus-connection.h | 2 ++ dbus/dbus-transport-kdbus.c | 35 ++++++++++--------- dbus/kdbus-common.c | 2 ++ dbus/kdbus.h | 2 ++ 11 files changed, 158 insertions(+), 61 deletions(-) diff --git a/autogen.sh b/autogen.sh index a1e97f4..2338244 100755 --- a/autogen.sh +++ b/autogen.sh @@ -102,7 +102,7 @@ fi #--enable-developer --enable-verbose-mode if $run_configure; then - $srcdir/configure --enable-verbose-mode --config-cache "$@" || exit $? + $srcdir/configure --enable-developer --config-cache "$@" || exit $? echo echo "Now type 'make' to compile $PROJECT." else diff --git a/bus/activation.c b/bus/activation.c index 124f91b..cd77faa 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -1187,7 +1187,14 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation { DBusConnection *addressed_recipient; - addressed_recipient = bus_service_get_primary_owners_connection (service); + /* kdbus change - we can not send anything using phantom connections + * (DBusConnection structures for services other than daemon) + * so we have to use daemon connection + */ + if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) + addressed_recipient = entry->connection; + else + addressed_recipient = bus_service_get_primary_owners_connection (service); /* Resume dispatching where we left off in bus_dispatch() */ if (!bus_dispatch_matches (transaction, diff --git a/bus/driver.c b/bus/driver.c index 7861a52..a664517 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -731,12 +731,11 @@ bus_driver_handle_release_service (DBusConnection *connection, _dbus_string_init_const (&service_name, name); - if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) //todo kdbus incl + if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) { - registry = (BusRegistry*) message; - /* looks like hack? Yes. - * But how to pass message to bus_registry_release_service in other way? - * In kdbus mode we don't need registry, though. + registry = (BusRegistry*) dbus_message_get_sender(message); + /* todo looks like hack? Yes. + * But how to pass sender of message to bus_registry_release_service in other way? */ } diff --git a/bus/kdbus-d.c b/bus/kdbus-d.c index e3202e5..fea4db4 100644 --- a/bus/kdbus-d.c +++ b/bus/kdbus-d.c @@ -26,9 +26,6 @@ #include #include -//todo there should be no include below - needed functions should be moved to kdbus-common -#include - __u64 sender_name_to_id(const char* name, DBusError* error) { __u64 sender_id = 0; @@ -114,7 +111,7 @@ DBusConnection* daemon_as_client(DBusBusType type, char* address, DBusError *err if(kdbus_request_name(connection, &daemon_name, 0, 0) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) goto failed; - if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "type='signal', member='NameLost'")) //todo handle tis in dispatch + if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "type='signal', member='NameLost'")) //todo handle this in dispatch { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:1, %s", _dbus_strerror_from_errno ()); return FALSE; @@ -285,11 +282,10 @@ dbus_bool_t kdbus_get_connection_unix_selinux_security_context(DBusConnection* c return ret; } -DBusConnection* create_phantom_connection(DBusConnection* connection, const char* unique_name) +DBusConnection* create_phantom_connection(DBusConnection* connection, const char* unique_name, DBusError* error) { DBusConnection *phantom_connection; DBusString name; - DBusError error; _dbus_string_init_const(&name, unique_name); @@ -298,20 +294,21 @@ DBusConnection* create_phantom_connection(DBusConnection* connection, const char return FALSE; if(!bus_connections_setup_connection(bus_connection_get_connections(connection), phantom_connection)) { - /*todo FIXME something should be done to clean up the phantom connection - * but we can't use standard disconnect, unref or last_unref because the transport is taken from connection - * so we probably should write own function on the basis of _dbus_connection_last_unref - */ + dbus_connection_unref_phantom(phantom_connection); phantom_connection = NULL; + dbus_set_error (error, DBUS_ERROR_FAILED , "Name \"%s\" could not be acquired", unique_name); + goto out; } - if(!bus_connection_complete(phantom_connection, &name, &error)) + if(!bus_connection_complete(phantom_connection, &name, error)) { - /* todo FIXME exactly the same issue as above */ + dbus_connection_unref_phantom(phantom_connection); phantom_connection = NULL; + goto out; } _dbus_verbose ("Created phantom connection for %s\n", bus_connection_get_name(phantom_connection)); +out: return phantom_connection; } @@ -327,11 +324,14 @@ dbus_bool_t register_kdbus_starters(DBusConnection* connection) _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd); - /* for(i=0; iowners); + + while (link != NULL) + { + BusOwner *bus_owner; + + bus_owner = (BusOwner *) link->data; + if(!strcmp(bus_connection_get_name(bus_owner->conn), unique_name)) + return bus_owner->conn; + + link = _dbus_list_get_next_link (&service->owners, link); + } + + return NULL; +} + static void bus_owner_set_flags (BusOwner *owner, dbus_uint32_t flags) @@ -678,13 +700,13 @@ bus_registry_acquire_kdbus_service (BusRegistry *registry, dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection is not allowed to own the service \"%s\" due to security policies in the configuration file", _dbus_string_get_const_data (service_name)); - goto out; + goto failed; } } sender_id = sender_name_to_id(dbus_message_get_sender(message), error); if(dbus_error_is_set(error)) - return FALSE; + goto failed; *result = kdbus_request_name(connection, service_name, flags, sender_id); if(*result == -EPERM) @@ -692,28 +714,35 @@ bus_registry_acquire_kdbus_service (BusRegistry *registry, dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection is not allowed to own the service \"%s\" due to security policies in the configuration file", _dbus_string_get_const_data (service_name)); - goto out; + goto failed; } else if(*result < 0) { dbus_set_error (error, DBUS_ERROR_FAILED , "Name \"%s\" could not be acquired", name); - goto out; + goto failed; } if((*result == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) || (*result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)) { DBusConnection* phantom; - phantom = create_phantom_connection(connection, dbus_message_get_sender(message)); + phantom = create_phantom_connection(connection, dbus_message_get_sender(message), error); if(phantom == NULL) - goto out; + goto failed2; if (!bus_service_add_owner (service, phantom, flags, transaction, error)) - goto out; /* todo FIXME what to do with phantom connection? look into create_phantom_connection for a clue*/ + { + dbus_connection_unref_phantom(phantom); + goto failed2; + } if(*result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + /* Here we are removing DBus daemon as an owner of the service, + * which is set by bus_registry_ensure. + * If bus_service_remove_owner fail, we ignore it, because it has + * almost none impact on the usage + */ if(_bus_service_find_owner_link (service, connection)) - if (!bus_service_remove_owner (service, connection, transaction, error)) - goto out; /* todo FIXME what to do with phantom connection? look into create_phantom_connection for a clue*/ + bus_service_remove_owner (service, connection, transaction, NULL); } } @@ -722,9 +751,16 @@ bus_registry_acquire_kdbus_service (BusRegistry *registry, service, transaction, error); - out: - return retval; + return retval; + +failed2: + kdbus_release_name(connection, service_name, sender_id); +failed: + if(_bus_service_find_owner_link (service, connection)) + bus_service_remove_owner (service, connection, transaction, NULL); + + return FALSE; } dbus_bool_t @@ -778,15 +814,38 @@ bus_registry_release_service (BusRegistry *registry, goto out; } - if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) //todo kdbus incl + if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) { __u64 sender_id; - sender_id = sender_name_to_id(dbus_message_get_sender((DBusMessage*)registry), error); + sender_id = sender_name_to_id((const char*)registry, error); if(dbus_error_is_set(error)) return FALSE; *result = kdbus_release_name(connection, service_name, sender_id); + + if(*result == DBUS_RELEASE_NAME_REPLY_RELEASED) + { + const char* name; + + name = (const char*)registry; //get name passed in registry pointer + registry = bus_connection_get_registry (connection); //than take original registry address + + service = bus_registry_lookup (registry, service_name); + if(service) + { + DBusConnection* phantom; + + phantom = _bus_service_find_owner_connection(service, name); + if(phantom) + { + bus_service_remove_owner (service, phantom, transaction, NULL); + dbus_connection_unref_phantom(phantom); + } + else + _dbus_verbose ("Didn't find phantom connection for released name!\n"); + } + } } else { diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 21d0db9..4923812 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2702,12 +2702,8 @@ free_outgoing_message (void *element, dbus_message_unref (message); } -/* This is run without the mutex held, but after the last reference - * to the connection has been dropped we should have no thread-related - * problems - */ static void -_dbus_connection_last_unref (DBusConnection *connection) +_dbus_connection_last_unref_internal (DBusConnection *connection, dbus_bool_t unref_transport) { DBusList *link; @@ -2762,17 +2758,18 @@ _dbus_connection_last_unref (DBusConnection *connection) _dbus_list_foreach (&connection->outgoing_messages, free_outgoing_message, - connection); + connection); _dbus_list_clear (&connection->outgoing_messages); _dbus_list_foreach (&connection->incoming_messages, - (DBusForeachFunction) dbus_message_unref, - NULL); + (DBusForeachFunction) dbus_message_unref, + NULL); _dbus_list_clear (&connection->incoming_messages); _dbus_counter_unref (connection->outgoing_counter); - _dbus_transport_unref (connection->transport); + if(unref_transport) + _dbus_transport_unref (connection->transport); if (connection->disconnect_message_link) { @@ -2794,6 +2791,16 @@ _dbus_connection_last_unref (DBusConnection *connection) dbus_free (connection); } +/* This is run without the mutex held, but after the last reference + * to the connection has been dropped we should have no thread-related + * problems + */ +static void +_dbus_connection_last_unref (DBusConnection *connection) +{ + _dbus_connection_last_unref_internal(connection, TRUE); +} + /** * Decrements the reference count of a DBusConnection, and finalizes * it if the count reaches zero. @@ -2842,6 +2849,22 @@ dbus_connection_unref (DBusConnection *connection) } } +void +dbus_connection_unref_phantom (DBusConnection *connection) +{ + dbus_int32_t old_refcount; + + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (connection->generation == _dbus_current_generation); + + old_refcount = _dbus_atomic_dec (&connection->refcount); + + _dbus_connection_trace_ref (connection, old_refcount, old_refcount - 1, "unref"); + + if (old_refcount == 1) + _dbus_connection_last_unref_internal(connection, FALSE); +} + /* * Note that the transport can disconnect itself (other end drops us) * and in that case this function never runs. So this function must diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index d223954..a3afb93 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -185,6 +185,8 @@ DBusConnection* dbus_connection_ref (DBusConnection DBUS_EXPORT void dbus_connection_unref (DBusConnection *connection); DBUS_EXPORT +void dbus_connection_unref_phantom (DBusConnection *connection); +DBUS_EXPORT void dbus_connection_close (DBusConnection *connection); DBUS_EXPORT dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection); diff --git a/dbus/dbus-transport-kdbus.c b/dbus/dbus-transport-kdbus.c index a7b4477..6a33241 100644 --- a/dbus/dbus-transport-kdbus.c +++ b/dbus/dbus-transport-kdbus.c @@ -33,8 +33,6 @@ #include #include -//todo documentation need to be corrected - #define KDBUS_PART_FOREACH(part, head, first) \ for (part = (head)->first; \ (uint8_t *)(part) < (uint8_t *)(head) + (head)->size; \ @@ -172,7 +170,7 @@ static int reply_1_data(DBusMessage *message, int data_type, void* pData, DBusCo return -1; } -/*todo uncomment if needed +/* static int reply_ack(DBusMessage *message, DBusConnection* connection) { DBusMessage *reply; @@ -410,18 +408,21 @@ static int kdbus_write_msg(DBusTransportSocket *transport, DBusMessage *message, { if(errno == EINTR) goto again; - if((errno == ESRCH) || (errno == ENXIO) || (errno = EADDRNOTAVAIL)) //when recipient is not available on the bus + else if(errno == ENXIO) //no such id on the bus + { + if(!reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Name \"%s\" does not exist", dbus_message_get_destination(message), message, transport->base.connection)) + goto out; + } + else if((errno == ESRCH) || (errno = EADDRNOTAVAIL)) //when well known name is not available on the bus { if(autostart) { - //todo start service here, otherwise if(!reply_with_error(DBUS_ERROR_SERVICE_UNKNOWN, "The name %s was not provided by any .service files", dbus_message_get_destination(message), message, transport->base.connection)) goto out; } else - if(!reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Name \"%s\" does not exist", dbus_message_get_destination(message), message, transport->base.connection)) - goto out; - + if(!reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Name \"%s\" does not exist", dbus_message_get_destination(message), message, transport->base.connection)) + goto out; } _dbus_verbose("kdbus error sending message: err %d (%m)\n", errno); ret_size = -1; @@ -834,7 +835,7 @@ static int emulateOrgFreedesktopDBus(DBusTransport *transport, DBusMessage *mess ((DBusTransportSocket*)transport)->sender = sender; if(!reply_1_data(message, DBUS_TYPE_STRING, &name, transport->connection)) - return 0; //todo why we cannot free name after sending reply? + return 0; //todo why we cannot free name after sending reply, shouldn't we? else free(sender); @@ -1066,7 +1067,7 @@ out: return ret_value; } #endif -/* else if(!strcmp(dbus_message_get_member(message), "GetAdtAuditSessionData")) //todo to be implemented +/* else if(!strcmp(dbus_message_get_member(message), "GetAdtAuditSessionData")) //todo to be implemented if needed and possible { char* name = NULL; @@ -1102,7 +1103,6 @@ out: #endif else return 1; //send to daemon -// return reply_with_error(DBUS_ERROR_UNKNOWN_METHOD, NULL, (char*)dbus_message_get_member(message), message, transport->connection); #ifdef DBUS_SERVICES_IN_LIB if(info.sec_label) @@ -2106,9 +2106,12 @@ do_writing (DBusTransport *transport) message = _dbus_connection_get_message_to_send (transport->connection); _dbus_assert (message != NULL); - dbus_message_unlock(message); - dbus_message_set_sender(message, socket_transport->sender); - dbus_message_lock (message); + if(dbus_message_get_sender(message) == NULL) //needed for daemon + { + dbus_message_unlock(message); + dbus_message_set_sender(message, socket_transport->sender); + dbus_message_lock (message); + } _dbus_message_get_network_data (message, &header, &body); total_bytes_to_write = _dbus_string_get_length(header) + _dbus_string_get_length(body); pDestination = dbus_message_get_destination(message); @@ -2473,7 +2476,7 @@ kdbus_connection_set (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; - dbus_connection_set_is_authenticated(transport->connection); //todo remove when authentication will work + dbus_connection_set_is_authenticated(transport->connection); //now we don't have authentication in kdbus _dbus_watch_set_handler (socket_transport->write_watch, _dbus_connection_handle_watch, @@ -2501,7 +2504,7 @@ kdbus_connection_set (DBusTransport *transport) return TRUE; } -/** +/** original dbus copy-pasted * @todo We need to have a way to wake up the select sleep if * a new iteration request comes in with a flag (read/write) that * we're not currently serving. Otherwise a call that just reads diff --git a/dbus/kdbus-common.c b/dbus/kdbus-common.c index 0c96749..fe04a2e 100644 --- a/dbus/kdbus-common.c +++ b/dbus/kdbus-common.c @@ -224,6 +224,8 @@ int request_kdbus_name(int fd, const char *name, const __u64 flags, __u64 id) flags_kdbus |= KDBUS_NAME_QUEUE; if(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) flags_kdbus |= KDBUS_NAME_REPLACE_EXISTING; + if(flags & KDBUS_NAME_STARTER) + flags_kdbus |= KDBUS_NAME_STARTER; cmd_name->flags = flags_kdbus; cmd_name->id = id; diff --git a/dbus/kdbus.h b/dbus/kdbus.h index 368cec3..4e4c2cb 100644 --- a/dbus/kdbus.h +++ b/dbus/kdbus.h @@ -343,6 +343,8 @@ enum { KDBUS_NAME_QUEUE = 1 << 1, KDBUS_NAME_ALLOW_REPLACEMENT = 1 << 2, + KDBUS_NAME_STARTER = 1 << 7, + /* kernel → userspace */ KDBUS_NAME_IN_QUEUE = 1 << 16, }; -- 2.7.4