### Home Classes Methods

### In Files

- lib/dbus/bus.rb

### Parent

Object

### Namespace

- CLASS DBus::Connection::NameRequestError

### Methods

- ::new
- #[]
- #add_match
- #connect
- #connect_to_tcp
- #connect_to_unix
- #emit
- #glibize
- #introspect
- #introspect_data
- #messages
- #on_return
- #poll_messages
- #pop_message
- #process
- #proxy
- #remove_match
- #request_service
- #send
- #send_sync
- #send_sync_or_async
- #service
- #update_buffer
- #wait_for_message

### Files

- README

### Class/Module Index

Quicksearch

- DBus
- DBus::ASessionBus
- DBus::ASystemBus
- DBus::AuthenticationFailed
- DBus::Authenticator
- DBus::Client
- DBus::Connection
- DBus::Connection::NameRequestError
- DBus::DBusCookieSHA1
- DBus::Error
- DBus::ErrorMessage
- DBus::External
- DBus::FormalParameter
- DBus::IncompleteBufferException
- DBus::Interface
- DBus::InterfaceElement
- DBus::IntrospectXMLParser
- DBus::InvalidClassDefinition
- DBus::InvalidDestinationName
- DBus::InvalidIntrospectionData
- DBus::InvalidMethodName
- DBus::InvalidPacketException
- DBus::InvalidParameters
- DBus::Main
- DBus::MatchRule
- DBus::MatchRuleException
- DBus::Message
- DBus::Method
- DBus::MethodNotImplemented
- DBus::MethodReturnMessage
- DBus::Node
- DBus::Object
- DBus::Object::UndefinedInterface
- DBus::PacketMarshaller
- DBus::PacketUnmarshaller
- DBus::ProxyObject
- DBus::ProxyObjectFactory
- DBus::ProxyObjectInterface
- DBus::RemoteBus
- DBus::Service
- DBus::SessionBus
- DBus::Signal
- DBus::SystemBus
- DBus::Type
- DBus::Type::Parser
- DBus::Type::SignatureException
- DBus::Type::Type
- DBus::TypeException
- DBus::UnknownSignal
- Integer

No matching classes.

# DBus::Connection

D-Bus main connection class

Main class that maintains a connection to a bus and can handle incoming and outgoing messages.

### Constants

DBUSXMLINTRO
MSG_BUF_SIZE

  The buffer size for messages.

NAME_FLAG_ALLOW_REPLACEMENT

  FIXME: describe the following names, flags and constants. See DBus spec for definition

NAME_FLAG_DO_NOT_QUEUE
NAME_FLAG_REPLACE_EXISTING
REQUEST_NAME_REPLY_ALREADY_OWNER
REQUEST_NAME_REPLY_EXISTS
REQUEST_NAME_REPLY_IN_QUEUE
REQUEST_NAME_REPLY_PRIMARY_OWNER

### Attributes

socket[R]

The socket that is used to connect with the bus.

unique_name[R]

The unique name (by specification) of the message.

### Public Class Methods

new(path) click to toggle source

Create a new connection to the bus for a given connect path. path format is described in the D-Bus specification: dbus.freedesktop.org/doc/dbus-specification.html#addresses and is something like: "transport1:key1=value1,key2=value2;transport2:key1=value1,key2=value2" e.g. "unix:path=/tmp/dbus-test" or "tcp:host=localhost,port=2687"

    # File lib/dbus/bus.rb, line 198
    def initialize(path)
      @path = path
      @unique_name = nil
      @buffer = ""
      @method_call_replies = Hash.new
      @method_call_msgs = Hash.new
      @signal_matchrules = Hash.new
      @proxy = nil
      @object_root = Node.new("/")
      @is_tcp = false
    end

### Public Instance Methods

[](name) click to toggle source
Alias for: service
add_match(mr, &slot) click to toggle source

Asks bus to send us messages matching mr, and execute slot when received

    # File lib/dbus/bus.rb, line 591
    def add_match(mr, &slot)
      # check this is a signal.
      mrs = mr.to_s
      puts "#{@signal_matchrules.size} rules, adding #{mrs.inspect}" if $DEBUG
      # don't ask for the same match if we override it
      unless @signal_matchrules.key?(mrs)
        puts "Asked for a new match" if $DEBUG
        proxy.AddMatch(mrs)
      end
      @signal_matchrules[mrs] = slot
    end

connect() click to toggle source

Connect to the bus and initialize the connection.

    # File lib/dbus/bus.rb, line 211
    def connect
      addresses = @path.split ";"
      # connect to first one that succeeds
      worked = addresses.find do |a|
        transport, keyvaluestring = a.split ":"
        kv_list = keyvaluestring.split ","
        kv_hash = Hash.new
        kv_list.each do |kv|
          key, escaped_value = kv.split "="
          value = escaped_value.gsub(/%(..)/) {|m| [$1].pack "H2" }
          kv_hash[key] = value
        end
        case transport
          when "unix"
          connect_to_unix kv_hash
          when "tcp"
          connect_to_tcp kv_hash
          else
          # ignore, report?
        end
      end
      worked
      # returns the address that worked or nil.
      # how to report failure?
    end

connect_to_tcp(params) click to toggle source

Connect to a bus over tcp and initialize the connection.

    # File lib/dbus/bus.rb, line 238
    def connect_to_tcp(params)
      #check if the path is sufficient
      if params.key?("host") and params.key?("port")
        begin
          #initialize the tcp socket
          @socket = TCPSocket.new(params["host"],params["port"].to_i)
          @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
          init_connection
          @is_tcp = true
        rescue
          puts "Error: Could not establish connection to: #{@path}, will now exit."
          exit(0) #a little harsh
        end
      else
        #Danger, Will Robinson: the specified "path" is not usable
        puts "Error: supplied path: #{@path}, unusable! sorry."
      end
    end

connect_to_unix(params) click to toggle source

Connect to an abstract unix bus and initialize the connection.

    # File lib/dbus/bus.rb, line 258
    def connect_to_unix(params)
      @socket = Socket.new(Socket::Constants::PF_UNIX,Socket::Constants::SOCK_STREAM, 0)
      @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      if ! params['abstract'].nil?
        if HOST_END == LIL_END
          sockaddr = "\11\\00\\00##{params['abstract']}"
        else
          sockaddr = "\00\\11\\00##{params['abstract']}"
        end
      elsif ! params['path'].nil?
        sockaddr = Socket.pack_sockaddr_un(params['path'])
      end
      @socket.connect(sockaddr)
      init_connection
    end

emit(service, obj, intf, sig, *args) click to toggle source

Emit a signal event for the given service, object obj, interface intf and signal sig with arguments args.

    # File lib/dbus/bus.rb, line 674
    def emit(service, obj, intf, sig, *args)
      m = Message.new(DBus::Message::SIGNAL)
      m.path = obj.path
      m.interface = intf.name
      m.member = sig.name
      m.sender = service.name
      i = 0
      sig.params.each do |par|
        m.add_param(par.type, args[i])
        i += 1
      end
      send(m.marshall)
    end

glibize() click to toggle source

Tell a bus to register itself on the glib main loop

    # File lib/dbus/bus.rb, line 280
    def glibize
      require 'glib2'
      # Circumvent a ruby-glib bug
      @channels ||= Array.new

      gio = GLib::IOChannel.new(@socket.fileno)
      @channels << gio
      gio.add_watch(GLib::IOChannel::IN) do |c, ch|
        update_buffer
        messages.each do |msg|
          process(msg)
        end
        true
      end
    end

introspect(dest, path) click to toggle source

Issues a call to the org.freedesktop.DBus.Introspectable.Introspect method dest is the service and path the object path you want to introspect If a code block is given, the introspect call in asynchronous. If not data is returned

FIXME: link to ProxyObject data definition The returned object is a ProxyObject that has methods you can call to issue somme METHOD_CALL messages, and to setup to receive METHOD_RETURN

    # File lib/dbus/bus.rb, line 443
    def introspect(dest, path)
      if not block_given?
        # introspect in synchronous !
        data = introspect_data(dest, path)
        pof = DBus::ProxyObjectFactory.new(data, self, dest, path)
        return pof.build
      else
        introspect_data(dest, path) do |async_data|
          yield(DBus::ProxyObjectFactory.new(async_data, self, dest, path).build)
        end
      end
    end

introspect_data(dest, path, &reply_handler) click to toggle source

    # File lib/dbus/bus.rb, line 416
    def introspect_data(dest, path, &reply_handler)
      m = DBus::Message.new(DBus::Message::METHOD_CALL)
      m.path = path
      m.interface = "org.freedesktop.DBus.Introspectable"
      m.destination = dest
      m.member = "Introspect"
      m.sender = unique_name
      if reply_handler.nil?
        send_sync_or_async(m).first
      else
        send_sync_or_async(m) do |*args|
          # TODO test async introspection, is it used at all?
          args.shift            # forget the message, pass only the text
          reply_handler.call(*args)
          nil
        end
      end
    end

messages() click to toggle source

Retrieve all the messages that are currently in the buffer.

    # File lib/dbus/bus.rb, line 520
    def messages
      ret = Array.new
      while msg = pop_message
        ret << msg
      end
      ret
    end

on_return(m, &retc) click to toggle source

Specify a code block that has to be executed when a reply for message m is received.

    # File lib/dbus/bus.rb, line 580
    def on_return(m, &retc)
      # Have a better exception here
      if m.message_type != Message::METHOD_CALL
        raise "on_return should only get method_calls"
      end
      @method_call_msgs[m.serial] = m
      @method_call_replies[m.serial] = retc
    end

poll_messages() click to toggle source

Update the buffer and retrieve all messages using Connection#messages. Return the messages.

    # File lib/dbus/bus.rb, line 533
    def poll_messages
      ret = nil
      r, d, d = IO.select([@socket], nil, nil, 0)
      if r and r.size > 0
        update_buffer
      end
      messages
    end

pop_message() click to toggle source

Get one message from the bus and remove it from the buffer. Return the message.

    # File lib/dbus/bus.rb, line 507
    def pop_message
      return nil if @buffer.empty?
      ret = nil
      begin
        ret, size = Message.new.unmarshall_buffer(@buffer)
        @buffer.slice!(0, size)
      rescue IncompleteBufferException => e
        # fall through, let ret be null
      end
      ret
    end

process(m) click to toggle source

Process a message m based on its type.

    # File lib/dbus/bus.rb, line 614
    def process(m)
      return if m.nil? #check if somethings wrong
      case m.message_type
      when Message::ERROR, Message::METHOD_RETURN
        raise InvalidPacketException if m.reply_serial == nil
        mcs = @method_call_replies[m.reply_serial]
        if not mcs
          puts "DEBUG: no return code for mcs: #{mcs.inspect} m: #{m.inspect}" if $DEBUG
        else
          if m.message_type == Message::ERROR
            mcs.call(Error.new(m))
          else
            mcs.call(m)
          end
          @method_call_replies.delete(m.reply_serial)
          @method_call_msgs.delete(m.reply_serial)
        end
      when DBus::Message::METHOD_CALL
        if m.path == "/org/freedesktop/DBus"
          puts "DEBUG: Got method call on /org/freedesktop/DBus" if $DEBUG
        end
        node = @service.get_node(m.path)
        if not node
          reply = Message.error(m, "org.freedesktop.DBus.Error.UnknownObject",
                                "Object #{m.path} doesn't exist")
          send(reply.marshall)
        # handle introspectable as an exception:
        elsif m.interface == "org.freedesktop.DBus.Introspectable" and
            m.member == "Introspect"
          reply = Message.new(Message::METHOD_RETURN).reply_to(m)
          reply.sender = @unique_name
          reply.add_param(Type::STRING, node.to_xml)
          send(reply.marshall)
        else
          obj = node.object
          return if obj.nil?    # FIXME, sends no reply
          obj.dispatch(m) if obj
        end
      when DBus::Message::SIGNAL
        # the signal can match multiple different rules
        @signal_matchrules.each do |mrs, slot|
          if DBus::MatchRule.new.from_s(mrs).match(m)
            slot.call(m)
          end
        end
      else
        puts "DEBUG: Unknown message type: #{m.message_type}" if $DEBUG
      end
    end

proxy() click to toggle source

Set up a ProxyObject for the bus itself, since the bus is introspectable. Returns the object.

    # File lib/dbus/bus.rb, line 482
    def proxy
      if @proxy == nil
        path = "/org/freedesktop/DBus"
        dest = "org.freedesktop.DBus"
        pof = DBus::ProxyObjectFactory.new(DBUSXMLINTRO, self, dest, path)
        @proxy = pof.build["org.freedesktop.DBus"]
      end
      @proxy
    end

remove_match(mr) click to toggle source

    # File lib/dbus/bus.rb, line 603
    def remove_match(mr)
      mrs = mr.to_s
      unless @signal_matchrules.delete(mrs).nil?
        # don't remove nonexisting matches.
        # FIXME if we do try, the Error.MatchRuleNotFound is *not* raised
        # and instead is reported as "no return code for nil"
        proxy.RemoveMatch(mrs)
      end
    end

request_service(name) click to toggle source

Attempt to request a service name.

FIXME, NameRequestError cannot really be rescued as it will be raised when dispatching a later call. Rework the API to better match the spec.

    # File lib/dbus/bus.rb, line 464
    def request_service(name)
      # Use RequestName, but asynchronously!
      # A synchronous call would not work with service activation, where
      # method calls to be serviced arrive before the reply for RequestName
      # (Ticket#29).
      proxy.RequestName(name, NAME_FLAG_REPLACE_EXISTING) do |rmsg, r|
        if rmsg.is_a?(Error)  # check and report errors first
          raise rmsg
        elsif r != REQUEST_NAME_REPLY_PRIMARY_OWNER
          raise NameRequestError
        end
      end
      @service = Service.new(name, self)
      @service
    end

send(buf) click to toggle source

Send the buffer buf to the bus using Connection#writel.

    # File lib/dbus/bus.rb, line 275
    def send(buf)
      @socket.write(buf) unless @socket.nil?
    end

send_sync(m) click to toggle source

Send a message m on to the bus. This is done synchronously, thus the call will block until a reply message arrives.

    # File lib/dbus/bus.rb, line 561
    def send_sync(m, &retc) # :yields: reply/return message
      return if m.nil? #check if somethings wrong
      send(m.marshall)
      @method_call_msgs[m.serial] = m
      @method_call_replies[m.serial] = retc

      retm = wait_for_message

      return if retm.nil? #check if somethings wrong

      process(retm)
      while @method_call_replies.has_key? m.serial
        retm = wait_for_message
        process(retm)
      end
    end

send_sync_or_async(message, &reply_handler) click to toggle source

Send a message. If reply_handler is not given, wait for the reply and return the reply, or raise the error. If reply_handler is given, it will be called when the reply eventually arrives, with the reply message as the 1st param and its params following

    # File lib/dbus/bus.rb, line 393
    def send_sync_or_async(message, &reply_handler)
      ret = nil
      if reply_handler.nil?
        send_sync(message) do |rmsg|
          if rmsg.is_a?(Error)
            raise rmsg
          else
            ret = rmsg.params
          end
        end
      else
        on_return(message) do |rmsg|
          if rmsg.is_a?(Error)
            reply_handler.call(rmsg)
          else
            reply_handler.call(rmsg, * rmsg.params)
          end
        end
        send(message.marshall)
      end
      ret
    end

service(name) click to toggle source

Retrieves the Service with the given name.

    # File lib/dbus/bus.rb, line 665
    def service(name)
      # The service might not exist at this time so we cannot really check
      # anything
      Service.new(name, self)
    end

Also aliased as: []
update_buffer() click to toggle source

Fill (append) the buffer from data that might be available on the socket.

    # File lib/dbus/bus.rb, line 494
    def update_buffer
      @buffer += @socket.read_nonblock(MSG_BUF_SIZE)
    rescue EOFError
      raise                     # the caller expects it
    rescue Exception => e
      puts "Oops:", e
      raise if @is_tcp          # why?
      puts "WARNING: read_nonblock failed, falling back to .recv"
      @buffer += @socket.recv(MSG_BUF_SIZE)
    end

wait_for_message() click to toggle source

Wait for a message to arrive. Return it once it is available.

    # File lib/dbus/bus.rb, line 543
    def wait_for_message
      if @socket.nil?
        puts "ERROR: Can't wait for messages, @socket is nil."
        return
      end
      ret = pop_message
      while ret == nil
        r, d, d = IO.select([@socket])
        if r and r[0] == @socket
          update_buffer
          ret = pop_message
        end
      end
      ret
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.