Beispiel #1
0
/**
 * 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;
}
Beispiel #3
0
/**
 * 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;
    }
}
Beispiel #4
0
/**
 * 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;
}
Beispiel #5
0
/**
 * 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;
}
Beispiel #6
0
/**
 * 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;
}
Beispiel #7
0
/**
 * 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;
}