/** * Checks whether a certain name has an owner. * * @param connection the connection * @param name the name * @param error location to store any errors * @returns #TRUE if the name exists, #FALSE if not or on error */ dbus_bool_t dbus_bus_name_has_owner (DBusConnection *connection, const char *name, DBusError *error) { DBusMessage *message, *reply; dbus_bool_t exists; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (name != NULL, FALSE); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE); _dbus_return_val_if_error_is_set (error, FALSE); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner"); if (message == NULL) { _DBUS_SET_OOM (error); return FALSE; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return FALSE; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_BOOLEAN, &exists, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return FALSE; } dbus_message_unref (reply); return exists; }
/** * Reads arguments from a message iterator given a variable argument * list. Only arguments of basic type and arrays of fixed-length * basic type may be read with this function. See * dbus_message_get_args() for more details. * * @param iter the message iterator * @param error error to be filled in on failure * @param first_arg_type the first argument type * @param ... location for first argument value, then list of type-location pairs * @returns #FALSE if the error was set */ static dbus_bool_t dbus_message_iter_get_args (DBusMessageIter *iter, DBusError *error, int first_arg_type, ...) { dbus_bool_t retval; va_list var_args; _dbus_return_val_if_fail (iter != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); va_start (var_args, first_arg_type); retval = _dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args); va_end (var_args); return retval; }
/** * Listens for new connections on the given address. If there are * multiple semicolon-separated address entries in the address, tries * each one and listens on the first one that works. * * Returns #NULL and sets error if listening fails for any reason. * Otherwise returns a new #DBusServer. * dbus_server_set_new_connection_function(), * dbus_server_set_watch_functions(), and * dbus_server_set_timeout_functions() should be called immediately to * render the server fully functional. * * To free the server, applications must call first * dbus_server_disconnect() and then dbus_server_unref(). * * @param address the address of this server. * @param error location to store reason for failure. * @returns a new #DBusServer, or #NULL on failure. * */ DBusServer* dbus_server_listen (const char *address, DBusError *error) { DBusServer *server; DBusAddressEntry **entries; int len, i; DBusError first_connect_error = DBUS_ERROR_INIT; dbus_bool_t handled_once; _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); if (!dbus_parse_address (address, &entries, &len, error)) return NULL; server = NULL; handled_once = FALSE; for (i = 0; i < len; i++) { int j; for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) { DBusServerListenResult result; DBusError tmp_error = DBUS_ERROR_INIT; result = (* listen_funcs[j].func) (entries[i], &server, &tmp_error); if (result == DBUS_SERVER_LISTEN_OK) { _dbus_assert (server != NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED) { _dbus_assert (server == NULL); dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, "Address '%s' already used", dbus_address_entry_get_method (entries[0])); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); dbus_move_error (&tmp_error, error); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* keep trying addresses */ } else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); if (!dbus_error_is_set (&first_connect_error)) dbus_move_error (&tmp_error, &first_connect_error); else dbus_error_free (&tmp_error); handled_once = TRUE; /* keep trying addresses */ } } _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (error); } out: if (!handled_once) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (len > 0) dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Unknown address type '%s'", dbus_address_entry_get_method (entries[0])); else dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Empty address '%s'", address); } dbus_address_entries_free (entries); if (server == NULL) { _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || dbus_error_is_set (error)); if (error && dbus_error_is_set (error)) { /* already set the error */ } else { /* didn't set the error but either error should be * NULL or first_connect_error should be set. */ _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); dbus_move_error (&first_connect_error, error); } _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ _DBUS_ASSERT_ERROR_IS_SET (error); return NULL; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return server; } }
/** * Asks the bus to assign the given name to this connection by invoking * the RequestName method on the bus. This method is fully documented * in the D-BUS specification. For quick reference, the flags and * result codes are discussed here, but the specification is the * canonical version of this information. * * The #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT flag indicates that * if the name is successfully requested, other applications * will not be able to take over the name. i.e. the name's * owner (the application calling this function) must let go of * the name, it will not lose it involuntarily. * * The #DBUS_NAME_FLAG_REPLACE_EXISTING flag indicates that the caller * would like to take over the name from the current owner. * If the current name owner used #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT * then this flag indicates that the caller would like to be placed * in the queue to own the name when the current owner lets go. * * If no flags are given, an application will receive the requested * name only if the name is currently unowned; and it will give * up the name if another application asks to take it over using * #DBUS_NAME_FLAG_REPLACE_EXISTING. * * This function returns a result code. The possible result codes * are as follows. * * #DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER means that the name had no * existing owner, and the caller is now the primary owner; or that * the name had an owner, and the caller specified * #DBUS_NAME_FLAG_REPLACE_EXISTING, and the current owner did not * specify #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT. * * #DBUS_REQUEST_NAME_REPLY_IN_QUEUE happens only if the current owner * specified #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT and the caller specified * #DBUS_NAME_FLAG_REPLACE_EXISTING. In this case the caller ends up in * a queue to own the name after the current owner gives it up. * * #DBUS_REQUEST_NAME_REPLY_EXISTS happens if the name has an owner * #already and DBUS_NAME_FLAG_REPLACE_EXISTING was not specified. * * #DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER happens if an application * requests a name it already owns. * * When a service represents an application, say "text editor," then * it should specify #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT if it wants * the first editor started to be the user's editor vs. the last one * started. Then any editor that can be the user's editor should * specify #DBUS_NAME_FLAG_REPLACE_EXISTING to either take over * (last-started-wins) or be queued up (first-started-wins) according * to whether #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT was given. * * @todo this all seems sort of broken. Shouldn't the flags be a property * of the name, not the app requesting the name? What are the use-cases * other than the "text editor" thing and how are we supporting them? * * @param connection the connection * @param name the name to request * @param flags flags * @param error location to store the error * @returns a result code, -1 if error is set */ int dbus_bus_request_name (DBusConnection *connection, const char *name, unsigned int flags, DBusError *error) { DBusMessage *message, *reply; dbus_uint32_t result; _dbus_return_val_if_fail (connection != NULL, 0); _dbus_return_val_if_fail (name != NULL, 0); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0); _dbus_return_val_if_error_is_set (error, 0); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "RequestName"); if (message == NULL) { _DBUS_SET_OOM (error); return -1; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return -1; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return -1; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return -1; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, &result, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return -1; } dbus_message_unref (reply); return result; }
/** * Asks the bus to return the uid of the named * connection. * * @param connection the connection * @param name a name owned by the connection * @param error location to store the error * @returns a result code, -1 if error is set */ unsigned long dbus_bus_get_unix_user (DBusConnection *connection, const char *name, DBusError *error) { DBusMessage *message, *reply; dbus_uint32_t uid; _dbus_return_val_if_fail (connection != NULL, DBUS_UID_UNSET); _dbus_return_val_if_fail (name != NULL, DBUS_UID_UNSET); _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), DBUS_UID_UNSET); _dbus_return_val_if_error_is_set (error, DBUS_UID_UNSET); message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionUnixUser"); if (message == NULL) { _DBUS_SET_OOM (error); return DBUS_UID_UNSET; } if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); _DBUS_SET_OOM (error); return DBUS_UID_UNSET; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_UID_UNSET; } if (dbus_set_error_from_message (error, reply)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return DBUS_UID_UNSET; } if (!dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_message_unref (reply); return DBUS_UID_UNSET; } dbus_message_unref (reply); return (unsigned long) uid; }
/** * Registers a connection with the bus. This must be the first * thing an application does when connecting to the message bus. * If registration succeeds, the unique name will be set, * and can be obtained using dbus_bus_get_unique_name(). * * @param connection the connection * @param error place to store errors * @returns #TRUE on success */ dbus_bool_t dbus_bus_register (DBusConnection *connection, DBusError *error) { DBusMessage *message, *reply; char *name; BusData *bd; dbus_bool_t retval; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); retval = FALSE; bd = ensure_bus_data (connection); if (bd == NULL) { _DBUS_SET_OOM (error); return FALSE; } if (bd->unique_name != NULL) { _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n"); /* This isn't an error, it's a programming bug. We'll be nice * and not _dbus_assert_not_reached() */ return TRUE; } message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "Hello"); if (!message) { _DBUS_SET_OOM (error); return FALSE; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); if (reply == NULL) goto out; else if (dbus_set_error_from_message (error, reply)) goto out; else if (!dbus_message_get_args (reply, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) goto out; bd->unique_name = _dbus_strdup (name); if (bd->unique_name == NULL) { _DBUS_SET_OOM (error); goto out; } retval = TRUE; out: if (reply) dbus_message_unref (reply); if (!retval) _DBUS_ASSERT_ERROR_IS_SET (error); return retval; }
/** * Connects to a bus daemon and registers the client with it. If a * connection to the bus already exists, then that connection is * returned. Caller owns a reference to the bus. * * @todo alex thinks we should nullify the connection when we get a disconnect-message. * * @param type bus type * @param error address where an error can be returned. * @returns a DBusConnection with new ref */ DBusConnection * dbus_bus_get (DBusBusType type, DBusError *error) { const char *address; DBusConnection *connection; BusData *bd; DBusBusType address_type; _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL); _dbus_return_val_if_error_is_set (error, NULL); _DBUS_LOCK (bus); if (!init_connections_unlocked ()) { _DBUS_UNLOCK (bus); _DBUS_SET_OOM (error); return NULL; } /* We want to use the activation address even if the * activating bus is the session or system bus, * per the spec. */ address_type = type; /* Use the real type of the activation bus for getting its * connection, but only if the real type's address is available. (If * the activating bus isn't a well-known bus then * activation_bus_type == DBUS_BUS_STARTER) */ if (type == DBUS_BUS_STARTER && bus_connection_addresses[activation_bus_type] != NULL) type = activation_bus_type; if (bus_connections[type] != NULL) { connection = bus_connections[type]; dbus_connection_ref (connection); _DBUS_UNLOCK (bus); return connection; } address = bus_connection_addresses[address_type]; if (address == NULL) { dbus_set_error (error, DBUS_ERROR_FAILED, "Unable to determine the address of the message bus"); _DBUS_UNLOCK (bus); return NULL; } connection = dbus_connection_open (address, error); if (!connection) { _DBUS_ASSERT_ERROR_IS_SET (error); _DBUS_UNLOCK (bus); return NULL; } /* By default we're bound to the lifecycle of * the message bus. */ dbus_connection_set_exit_on_disconnect (connection, TRUE); if (!dbus_bus_register (connection, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_connection_close (connection); dbus_connection_unref (connection); _DBUS_UNLOCK (bus); return NULL; } bus_connections[type] = connection; bd = ensure_bus_data (connection); _dbus_assert (bd != NULL); bd->is_well_known = TRUE; _DBUS_UNLOCK (bus); return connection; }