Class: DBus::Connection
- Inherits:
-
Object
- Object
- DBus::Connection
- Defined in:
- lib/dbus/bus.rb
Overview
D-Bus main connection class
Main class that maintains a connection to a bus and can handle incoming and outgoing messages.
Direct Known Subclasses
Defined Under Namespace
Classes: NameRequestError
Constant Summary collapse
- NAME_FLAG_ALLOW_REPLACEMENT =
FIXME: describe the following names, flags and constants. See DBus spec for definition
0x1
- NAME_FLAG_REPLACE_EXISTING =
0x2
- NAME_FLAG_DO_NOT_QUEUE =
0x4
- REQUEST_NAME_REPLY_PRIMARY_OWNER =
0x1
- REQUEST_NAME_REPLY_IN_QUEUE =
0x2
- REQUEST_NAME_REPLY_EXISTS =
0x3
- REQUEST_NAME_REPLY_ALREADY_OWNER =
0x4
- DBUSXMLINTRO =
'<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <interface name="org.freedesktop.DBus.Introspectable"> <method name="Introspect"> <arg name="data" direction="out" type="s"/> </method> </interface> <interface name="org.freedesktop.DBus"> <method name="RequestName"> <arg direction="in" type="s"/> <arg direction="in" type="u"/> <arg direction="out" type="u"/> </method> <method name="ReleaseName"> <arg direction="in" type="s"/> <arg direction="out" type="u"/> </method> <method name="StartServiceByName"> <arg direction="in" type="s"/> <arg direction="in" type="u"/> <arg direction="out" type="u"/> </method> <method name="Hello"> <arg direction="out" type="s"/> </method> <method name="NameHasOwner"> <arg direction="in" type="s"/> <arg direction="out" type="b"/> </method> <method name="ListNames"> <arg direction="out" type="as"/> </method> <method name="ListActivatableNames"> <arg direction="out" type="as"/> </method> <method name="AddMatch"> <arg direction="in" type="s"/> </method> <method name="RemoveMatch"> <arg direction="in" type="s"/> </method> <method name="GetNameOwner"> <arg direction="in" type="s"/> <arg direction="out" type="s"/> </method> <method name="ListQueuedOwners"> <arg direction="in" type="s"/> <arg direction="out" type="as"/> </method> <method name="GetConnectionUnixUser"> <arg direction="in" type="s"/> <arg direction="out" type="u"/> </method> <method name="GetConnectionUnixProcessID"> <arg direction="in" type="s"/> <arg direction="out" type="u"/> </method> <method name="GetConnectionSELinuxSecurityContext"> <arg direction="in" type="s"/> <arg direction="out" type="ay"/> </method> <method name="ReloadConfig"> </method> <signal name="NameOwnerChanged"> <arg type="s"/> <arg type="s"/> <arg type="s"/> </signal> <signal name="NameLost"> <arg type="s"/> </signal> <signal name="NameAcquired"> <arg type="s"/> </signal> </interface> </node> '
- MSG_BUF_SIZE =
The buffer size for messages.
4096
Instance Attribute Summary collapse
-
#socket ⇒ Object
readonly
The socket that is used to connect with the bus.
-
#unique_name ⇒ Object
readonly
The unique name (by specification) of the message.
Instance Method Summary collapse
-
#add_match(mr, &slot) ⇒ Object
Asks bus to send us messages matching mr, and execute slot when received.
-
#connect ⇒ Object
Connect to the bus and initialize the connection.
-
#emit(service, obj, intf, sig, *args) ⇒ Object
Emit a signal event for the given service, object obj, interface intf and signal sig with arguments args.
-
#glibize ⇒ Object
Tell a bus to register itself on the glib main loop.
-
#initialize(path) ⇒ Connection
constructor
Create a new connection to the bus for a given connect path.
-
#introspect(dest, path) ⇒ Object
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.
- #introspect_data(dest, path) ⇒ Object
-
#messages ⇒ Object
Retrieve all the messages that are currently in the buffer.
-
#on_return(m, &retc) ⇒ Object
Specify a code block that has to be executed when a reply for message m is received.
-
#poll_messages ⇒ Object
Update the buffer and retrieve all messages using Connection#messages.
-
#pop_message ⇒ Object
Get one message from the bus and remove it from the buffer.
-
#process(m) ⇒ Object
Process a message m based on its type.
-
#proxy ⇒ Object
Set up a ProxyObject for the bus itself, since the bus is introspectable.
-
#request_service(name) ⇒ Object
Attempt to request a service name.
-
#send(buf) ⇒ Object
Send the buffer buf to the bus using Connection#writel.
-
#send_sync(m, &retc) ⇒ Object
Send a message m on to the bus.
-
#service(name) ⇒ Object
(also: #[])
Retrieves the service with the given name.
-
#update_buffer ⇒ Object
Fill (append) the buffer from data that might be available on the socket.
-
#wait_for_message ⇒ Object
Wait for a message to arrive.
Constructor Details
#initialize(path) ⇒ Connection
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”
Current implementation of ruby-dbus supports only a single server address and only “unix:path=…,guid=…” and “unix:abstract=…,guid=…” forms
184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/dbus/bus.rb', line 184 def initialize(path) @path = path @unique_name = nil @buffer = "" @method_call_replies = Hash.new @method_call_msgs = Hash.new @signal_matchrules = Array.new @proxy = nil # FIXME: can be TCP or any stream @socket = Socket.new(Socket::Constants::PF_UNIX, Socket::Constants::SOCK_STREAM, 0) @object_root = Node.new("/") end |
Instance Attribute Details
#socket ⇒ Object (readonly)
The socket that is used to connect with the bus.
172 173 174 |
# File 'lib/dbus/bus.rb', line 172 def socket @socket end |
#unique_name ⇒ Object (readonly)
The unique name (by specification) of the message.
170 171 172 |
# File 'lib/dbus/bus.rb', line 170 def unique_name @unique_name end |
Instance Method Details
#add_match(mr, &slot) ⇒ Object
Asks bus to send us messages matching mr, and execute slot when received
485 486 487 488 489 |
# File 'lib/dbus/bus.rb', line 485 def add_match(mr, &slot) # check this is a signal. @signal_matchrules << [mr, slot] self.proxy.AddMatch(mr.to_s) end |
#connect ⇒ Object
Connect to the bus and initialize the connection.
199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/dbus/bus.rb', line 199 def connect parse_session_string if @transport == "unix" and @type == "abstract" if HOST_END == LIL_END sockaddr = "\1\0\0#{@unix_abstract}" else sockaddr = "\0\1\0#{@unix_abstract}" end elsif @transport == "unix" and @type == "path" sockaddr = Socket.pack_sockaddr_un(@unix) end @socket.connect(sockaddr) init_connection end |
#emit(service, obj, intf, sig, *args) ⇒ Object
Emit a signal event for the given service, object obj, interface intf and signal sig with arguments args.
556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/dbus/bus.rb', line 556 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[1], args[i]) i += 1 end send(m.marshall) end |
#glibize ⇒ Object
Tell a bus to register itself on the glib main loop
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/dbus/bus.rb', line 220 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 .each do |msg| process(msg) end true end end |
#introspect(dest, path) ⇒ Object
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
363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/dbus/bus.rb', line 363 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 |data| yield(DBus::ProxyObjectFactory.new(data, self, dest, path).build) end end end |
#introspect_data(dest, path) ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/dbus/bus.rb', line 326 def introspect_data(dest, path) 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 not block_given? # introspect in synchronous ! send_sync(m) do |rmsg| if rmsg.is_a?(Error) raise rmsg else return rmsg.params[0] end end else send(m.marshall) on_return(m) do |rmsg| if rmsg.is_a?(Error) yield rmsg else yield rmsg.params[0] end end end nil end |
#messages ⇒ Object
Retrieve all the messages that are currently in the buffer.
420 421 422 423 424 425 426 |
# File 'lib/dbus/bus.rb', line 420 def ret = Array.new while msg = ret << msg end ret end |
#on_return(m, &retc) ⇒ Object
Specify a code block that has to be executed when a reply for message m is received.
474 475 476 477 478 479 480 481 |
# File 'lib/dbus/bus.rb', line 474 def on_return(m, &retc) # Have a better exception here if m. != 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 ⇒ Object
Update the buffer and retrieve all messages using Connection#messages. Return the messages.
433 434 435 436 437 438 439 440 |
# File 'lib/dbus/bus.rb', line 433 def ret = nil r, d, d = IO.select([@socket], nil, nil, 0) if r and r.size > 0 update_buffer end end |
#pop_message ⇒ Object
Get one message from the bus and remove it from the buffer. Return the message.
408 409 410 411 412 413 414 415 416 417 |
# File 'lib/dbus/bus.rb', line 408 def 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) ⇒ Object
Process a message m based on its type.
- method call
-
FIXME…
- method call return value
-
FIXME…
- signal
-
FIXME…
- error
-
FIXME…
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/dbus/bus.rb', line 496 def process(m) case m. when Message::ERROR, Message::METHOD_RETURN raise InvalidPacketException if m.reply_serial == nil mcs = @method_call_replies[m.reply_serial] if not mcs puts "no return code for #{mcs.inspect} (#{m.inspect})" if $DEBUG else if m. == 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 "Got method call on /org/freedesktop/DBus" if $DEBUG end # handle introspectable as an exception: if m.interface == "org.freedesktop.DBus.Introspectable" and m.member == "Introspect" reply = Message.new(Message::METHOD_RETURN).reply_to(m) reply.sender = @unique_name node = @service.get_node(m.path) raise NotImplementedError if not node reply.sender = @unique_name reply.add_param(Type::STRING, @service.get_node(m.path).to_xml) send(reply.marshall) else node = @service.get_node(m.path) return if node.nil? obj = node.object return if obj.nil? obj.dispatch(m) if obj end when DBus::Message::SIGNAL @signal_matchrules.each do |elem| mr, slot = elem if mr.match(m) slot.call(m) return end end else puts "Unknown message type: #{m.}" if $DEBUG end end |
#proxy ⇒ Object
Set up a ProxyObject for the bus itself, since the bus is introspectable. Returns the object.
390 391 392 393 394 395 396 397 398 |
# File 'lib/dbus/bus.rb', line 390 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 |
#request_service(name) ⇒ Object
Attempt to request a service name.
381 382 383 384 385 386 |
# File 'lib/dbus/bus.rb', line 381 def request_service(name) r = proxy.RequestName(name, NAME_FLAG_REPLACE_EXISTING) raise NameRequestError if r[0] != REQUEST_NAME_REPLY_PRIMARY_OWNER @service = Service.new(name, self) @service end |
#send(buf) ⇒ Object
Send the buffer buf to the bus using Connection#writel.
215 216 217 |
# File 'lib/dbus/bus.rb', line 215 def send(buf) @socket.write(buf) end |
#send_sync(m, &retc) ⇒ Object
Send a message m on to the bus. This is done synchronously, thus the call will block until a reply message arrives.
457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'lib/dbus/bus.rb', line 457 def send_sync(m, &retc) # :yields: reply/return message send(m.marshall) @method_call_msgs[m.serial] = m @method_call_replies[m.serial] = retc retm = process(retm) until [DBus::Message::ERROR, DBus::Message::METHOD_RETURN].include?(retm.) and retm.reply_serial == m.serial retm = process(retm) end end |
#service(name) ⇒ Object Also known as: []
Retrieves the service with the given name.
547 548 549 550 551 |
# File 'lib/dbus/bus.rb', line 547 def service(name) # The service might not exist at this time so we cannot really check # anything Service.new(name, self) end |
#update_buffer ⇒ Object
Fill (append) the buffer from data that might be available on the socket.
402 403 404 |
# File 'lib/dbus/bus.rb', line 402 def update_buffer @buffer += @socket.read_nonblock(MSG_BUF_SIZE) end |
#wait_for_message ⇒ Object
Wait for a message to arrive. Return it once it is available.
443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/dbus/bus.rb', line 443 def ret = while ret == nil r, d, d = IO.select([@socket]) if r and r[0] == @socket update_buffer ret = end end ret end |