yong-ruby-dbus 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,280 @@
1
+ # dbus.rb - Module containing the low-level D-Bus implementation
2
+ #
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License, version 2.1 as published by the Free Software Foundation.
9
+ # See the file "COPYING" for the exact licensing terms.
10
+
11
+ # = D-Bus main module
12
+ #
13
+ # Module containing all the D-Bus modules and classes.
14
+ module DBus
15
+ # = InvalidDestinationName class
16
+ # Thrown when you try do send a message to /org/freedesktop/DBus/Local, that
17
+ # is reserved.
18
+ class InvalidDestinationName < Exception
19
+ end
20
+
21
+ # = D-Bus message class
22
+ #
23
+ # Class that holds any type of message that travels over the bus.
24
+ class Message
25
+ # The serial number of the message.
26
+ @@serial = 1
27
+ # Mutex that protects updates on the serial number.
28
+ @@serial_mutex = Mutex.new
29
+ # Type of a message (by specification).
30
+ MESSAGE_SIGNATURE = "yyyyuua(yv)"
31
+
32
+ # FIXME: following message type constants should be under Message::Type IMO
33
+ # well, yeah sure
34
+ #
35
+ # Invalid message type.
36
+ INVALID = 0
37
+ # Method call message type.
38
+ METHOD_CALL = 1
39
+ # Method call return value message type.
40
+ METHOD_RETURN = 2
41
+ # Error message type.
42
+ ERROR = 3
43
+ # Signal message type.
44
+ SIGNAL = 4
45
+
46
+ # Message flag signyfing that no reply is expected.
47
+ NO_REPLY_EXPECTED = 0x1
48
+ # Message flag signifying that no automatic start is required/must be
49
+ # performed.
50
+ NO_AUTO_START = 0x2
51
+
52
+ # The type of the message.
53
+ attr_reader :message_type
54
+ # The path of the object instance the message must be sent to/is sent from.
55
+ attr_accessor :path
56
+ # The interface of the object that must be used/was used.
57
+ attr_accessor :interface
58
+ # The interface member (method/signal name) of the object that must be
59
+ # used/was used.
60
+ attr_accessor :member
61
+ # The name of the error (in case of an error message type).
62
+ attr_accessor :error_name
63
+ # The destination connection of the object that must be used/was used.
64
+ attr_accessor :destination
65
+ # The sender of the message.
66
+ attr_accessor :sender
67
+ # The signature of the message contents.
68
+ attr_accessor :signature
69
+ # The serial number of the message this message is a reply for.
70
+ attr_accessor :reply_serial
71
+ # The protocol.
72
+ attr_reader :protocol
73
+ # The serial of the message.
74
+ attr_reader :serial
75
+ # The parameters of the message.
76
+ attr_reader :params
77
+
78
+ # Create a message with message type _mtype_ with default values and a
79
+ # unique serial number.
80
+ def initialize(mtype = INVALID)
81
+ @message_type = mtype
82
+
83
+ @flags = 0
84
+ @protocol = 1
85
+ @body_length = 0
86
+ @signature = String.new
87
+ @@serial_mutex.synchronize do
88
+ @serial = @@serial
89
+ @@serial += 1
90
+ end
91
+ @params = Array.new
92
+ @destination = nil
93
+ @error_name = nil
94
+ @member = nil
95
+ @path = nil
96
+ @reply_serial = nil
97
+
98
+ if mtype == METHOD_RETURN
99
+ @flags = NO_REPLY_EXPECTED
100
+ end
101
+ end
102
+
103
+ # Mark this message as a reply to a another message _m_, taking
104
+ # the serial number of _m_ as reply serial and the sender of _m_ as
105
+ # destination.
106
+ def reply_to(m)
107
+ @message_type = METHOD_RETURN
108
+ @reply_serial = m.serial
109
+ @destination = m.sender
110
+ self
111
+ end
112
+
113
+ # Add a parameter _val_ of type _type_ to the message.
114
+ def add_param(type, val)
115
+ type = type.chr if type.kind_of?(Fixnum)
116
+ @signature += type.to_s
117
+ @params << [type, val]
118
+ end
119
+
120
+ # FIXME: what are these? a message element constant enumeration?
121
+ # See method below, in a message, you have and array of optional parameters
122
+ # that come with an index, to determine their meaning. The values are in
123
+ # spec, more a definition than an enumeration.
124
+
125
+ PATH = 1
126
+ INTERFACE = 2
127
+ MEMBER = 3
128
+ ERROR_NAME = 4
129
+ REPLY_SERIAL = 5
130
+ DESTINATION = 6
131
+ SENDER = 7
132
+ SIGNATURE = 8
133
+
134
+ # Marshall the message with its current set parameters and return
135
+ # it in a packet form.
136
+ def marshall
137
+ if @path == "/org/freedesktop/DBus/Local"
138
+ raise InvalidDestinationName
139
+ end
140
+
141
+ params = PacketMarshaller.new
142
+ @params.each do |param|
143
+ params.append(param[0], param[1])
144
+ end
145
+ @body_length = params.packet.length
146
+
147
+ marshaller = PacketMarshaller.new
148
+ marshaller.append(Type::BYTE, HOST_END)
149
+ marshaller.append(Type::BYTE, @message_type)
150
+ marshaller.append(Type::BYTE, @flags)
151
+ marshaller.append(Type::BYTE, @protocol)
152
+ marshaller.append(Type::UINT32, @body_length)
153
+ marshaller.append(Type::UINT32, @serial)
154
+ marshaller.array(Type::Parser.new("y").parse[0]) do
155
+ if @path
156
+ marshaller.struct do
157
+ marshaller.append(Type::BYTE, PATH)
158
+ marshaller.append(Type::BYTE, 1)
159
+ marshaller.append_simple_string("o")
160
+ marshaller.append(Type::OBJECT_PATH, @path)
161
+ end
162
+ end
163
+ if @interface
164
+ marshaller.struct do
165
+ marshaller.append(Type::BYTE, INTERFACE)
166
+ marshaller.append(Type::BYTE, 1)
167
+ marshaller.append_simple_string("s")
168
+ marshaller.append(Type::STRING, @interface)
169
+ end
170
+ end
171
+ if @member
172
+ marshaller.struct do
173
+ marshaller.append(Type::BYTE, MEMBER)
174
+ marshaller.append(Type::BYTE, 1)
175
+ marshaller.append_simple_string("s")
176
+ marshaller.append(Type::STRING, @member)
177
+ end
178
+ end
179
+ if @error_name
180
+ marshaller.struct do
181
+ marshaller.append(Type::BYTE, ERROR_NAME)
182
+ marshaller.append(Type::BYTE, 1)
183
+ marshaller.append_simple_string("s")
184
+ marshaller.append(Type::STRING, @error_name)
185
+ end
186
+ end
187
+ if @reply_serial
188
+ marshaller.struct do
189
+ marshaller.append(Type::BYTE, REPLY_SERIAL)
190
+ marshaller.append(Type::BYTE, 1)
191
+ marshaller.append_simple_string("u")
192
+ marshaller.append(Type::UINT32, @reply_serial)
193
+ end
194
+ end
195
+ if @destination
196
+ marshaller.struct do
197
+ marshaller.append(Type::BYTE, DESTINATION)
198
+ marshaller.append(Type::BYTE, 1)
199
+ marshaller.append_simple_string("s")
200
+ marshaller.append(Type::STRING, @destination)
201
+ end
202
+ end
203
+ if @signature != ""
204
+ marshaller.struct do
205
+ marshaller.append(Type::BYTE, SIGNATURE)
206
+ marshaller.append(Type::BYTE, 1)
207
+ marshaller.append_simple_string("g")
208
+ marshaller.append(Type::SIGNATURE, @signature)
209
+ end
210
+ end
211
+ end
212
+ marshaller.align(8)
213
+ @params.each do |param|
214
+ marshaller.append(param[0], param[1])
215
+ end
216
+ marshaller.packet
217
+ end
218
+
219
+ # Unmarshall a packet contained in the buffer _buf_ and set the
220
+ # parameters of the message object according the data found in the
221
+ # buffer.
222
+ # Return the detected message and the index pointer of the buffer where
223
+ # the message data ended.
224
+ def unmarshall_buffer(buf)
225
+ buf = buf.dup
226
+ if buf[0] == ?l
227
+ endianness = LIL_END
228
+ else
229
+ endianness = BIG_END
230
+ end
231
+ pu = PacketUnmarshaller.new(buf, endianness)
232
+ mdata = pu.unmarshall(MESSAGE_SIGNATURE)
233
+ dummy, @message_type, @flags, @protocol, @body_length, @serial,
234
+ headers = mdata
235
+
236
+ headers.each do |struct|
237
+ case struct[0]
238
+ when PATH
239
+ @path = struct[1]
240
+ when INTERFACE
241
+ @interface = struct[1]
242
+ when MEMBER
243
+ @member = struct[1]
244
+ when ERROR_NAME
245
+ @error_name = struct[1]
246
+ when REPLY_SERIAL
247
+ @reply_serial = struct[1]
248
+ when DESTINATION
249
+ @destination = struct[1]
250
+ when SENDER
251
+ @sender = struct[1]
252
+ when SIGNATURE
253
+ @signature = struct[1]
254
+ end
255
+ end
256
+ pu.align(8)
257
+ if @body_length > 0 and @signature
258
+ @params = pu.unmarshall(@signature, @body_length)
259
+ end
260
+ [self, pu.idx]
261
+ end # def unmarshall_buf
262
+
263
+ # Unmarshall the data of a message found in the buffer _buf_ using
264
+ # Message#unmarshall_buf.
265
+ # Return the message.
266
+ def unmarshall(buf)
267
+ ret, size = unmarshall_buffer(buf)
268
+ ret
269
+ end
270
+ end # class Message
271
+
272
+ # A helper exception on errors
273
+ class Error < Exception
274
+ attr_reader :dbus_message
275
+ def initialize(msg)
276
+ super(msg.error_name + ": " + msg.params.join(", "))
277
+ @dbus_message = msg
278
+ end
279
+ end
280
+ end # module DBus
data/lib/dbus/type.rb ADDED
@@ -0,0 +1,206 @@
1
+ # dbus/type.rb - module containing low-level D-Bus data type information
2
+ #
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License, version 2.1 as published by the Free Software Foundation.
9
+ # See the file "COPYING" for the exact licensing terms.
10
+
11
+ module DBus
12
+
13
+ # = D-Bus type module
14
+ #
15
+ # This module containts the constants of the types specified in the D-Bus
16
+ # protocol.
17
+ module Type
18
+ # The types.
19
+ INVALID = 0
20
+ BYTE = ?y
21
+ BOOLEAN = ?b
22
+ INT16 = ?n
23
+ UINT16 = ?q
24
+ INT32 = ?i
25
+ UINT32 = ?u
26
+ INT64 = ?x
27
+ UINT64 = ?t
28
+ DOUBLE = ?d
29
+ STRUCT = ?r
30
+ ARRAY = ?a
31
+ VARIANT = ?v
32
+ OBJECT_PATH = ?o
33
+ STRING = ?s
34
+ SIGNATURE = ?g
35
+ DICT_ENTRY = ?e
36
+
37
+ # Mapping from type number to name.
38
+ TypeName = {
39
+ INVALID => "INVALID",
40
+ BYTE => "BYTE",
41
+ BOOLEAN => "BOOLEAN",
42
+ INT16 => "INT16",
43
+ UINT16 => "UINT16",
44
+ INT32 => "INT32",
45
+ UINT32 => "UINT32",
46
+ INT64 => "INT64",
47
+ UINT64 => "UINT64",
48
+ DOUBLE => "DOUBLE",
49
+ STRUCT => "STRUCT",
50
+ ARRAY => "ARRAY",
51
+ VARIANT => "VARIANT",
52
+ OBJECT_PATH => "OBJECT_PATH",
53
+ STRING => "STRING",
54
+ SIGNATURE => "SIGNATURE",
55
+ DICT_ENTRY => "DICT_ENTRY"
56
+ }
57
+
58
+ # Exception raised when an unknown/incorrect type is encountered.
59
+ class SignatureException < Exception
60
+ end
61
+
62
+ # = D-Bus type conversion class
63
+ #
64
+ # Helper class for representing a D-Bus type.
65
+ class Type
66
+ # Returns the signature type number.
67
+ attr_reader :sigtype
68
+ # Return contained member types.
69
+ attr_reader :members
70
+
71
+ # Create a new type instance for type number _sigtype_.
72
+ def initialize(sigtype)
73
+ if not TypeName.keys.member?(sigtype)
74
+ raise SignatureException, "Unknown key in signature: #{sigtype.chr}"
75
+ end
76
+ @sigtype = sigtype
77
+ @members = Array.new
78
+ end
79
+
80
+ # Return the required alignment for the type.
81
+ def alignment
82
+ {
83
+ BYTE => 1,
84
+ BOOLEAN => 4,
85
+ INT16 => 2,
86
+ UINT16 => 2,
87
+ INT32 => 4,
88
+ UINT32 => 4,
89
+ INT64 => 8,
90
+ UINT64 => 8,
91
+ STRUCT => 8,
92
+ DICT_ENTRY => 8,
93
+ DOUBLE => 8,
94
+ ARRAY => 4,
95
+ OBJECT_PATH => 4,
96
+ STRING => 4,
97
+ SIGNATURE => 1,
98
+ }[@sigtype]
99
+ end
100
+
101
+ # Return a string representation of the type according to the
102
+ # D-Bus specification.
103
+ def to_s
104
+ case @sigtype
105
+ when STRUCT
106
+ "(" + @members.collect { |t| t.to_s }.join + ")"
107
+ when ARRAY
108
+ "a" + @members.collect { |t| t.to_s }
109
+ when DICT_ENTRY
110
+ "{" + @members.collect { |t| t.to_s }.join + "}"
111
+ else
112
+ if not TypeName.keys.member?(@sigtype)
113
+ raise NotImplementedError
114
+ end
115
+ @sigtype.chr
116
+ end
117
+ end
118
+
119
+ # Add a new member type _a_.
120
+ def <<(a)
121
+ if not [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
122
+ raise SignatureException
123
+ end
124
+ raise SignatureException if @sigtype == ARRAY and @members.size > 0
125
+ if @sigtype == DICT_ENTRY
126
+ if @members.size == 2
127
+ raise SignatureException, "Dict entries have exactly two members"
128
+ end
129
+ if @members.size == 0
130
+ if [STRUCT, ARRAY, DICT_ENTRY].member?(a.sigtype)
131
+ raise SignatureException, "Dict entry keys must be basic types"
132
+ end
133
+ end
134
+ end
135
+ @members << a
136
+ end
137
+
138
+ # Return the first contained member type.
139
+ def child
140
+ @members[0]
141
+ end
142
+
143
+ def inspect
144
+ s = TypeName[@sigtype]
145
+ if [STRUCT, ARRAY].member?(@sigtype)
146
+ s += ": " + @members.inspect
147
+ end
148
+ s
149
+ end
150
+ end # class Type
151
+
152
+ # = D-Bus type parser class
153
+ #
154
+ # Helper class to parse a type signature in the protocol.
155
+ class Parser
156
+ # Create a new parser for the given _signature_.
157
+ def initialize(signature)
158
+ @signature = signature
159
+ @idx = 0
160
+ end
161
+
162
+ # Returns the next character from the signature.
163
+ def nextchar
164
+ c = @signature[@idx]
165
+ @idx += 1
166
+ c
167
+ end
168
+
169
+ # Parse one character _c_ of the signature.
170
+ def parse_one(c)
171
+ res = nil
172
+ case c
173
+ when ?a
174
+ res = Type.new(ARRAY)
175
+ child = parse_one(nextchar)
176
+ res << child
177
+ when ?(
178
+ res = Type.new(STRUCT)
179
+ while (c = nextchar) != nil and c != ?)
180
+ res << parse_one(c)
181
+ end
182
+ raise SignatureException, "Parse error in #{@signature}" if c == nil
183
+ when ?{
184
+ res = Type.new(DICT_ENTRY)
185
+ while (c = nextchar) != nil and c != ?}
186
+ res << parse_one(c)
187
+ end
188
+ raise SignatureException, "Parse error in #{@signature}" if c == nil
189
+ else
190
+ res = Type.new(c)
191
+ end
192
+ res
193
+ end
194
+
195
+ # Parse the entire signature, return a DBus::Type object.
196
+ def parse
197
+ @idx = 0
198
+ ret = Array.new
199
+ while (c = nextchar)
200
+ ret << parse_one(c)
201
+ end
202
+ ret
203
+ end
204
+ end # class Parser
205
+ end # module Type
206
+ end # module DBus