1 package dbus
2
3 import (
4 "errors"
5 "fmt"
6 "os"
7 "reflect"
8 "strings"
9 )
10
11 var (
12 ErrMsgInvalidArg = Error{
13 "org.freedesktop.DBus.Error.InvalidArgs",
14 []interface{}{"Invalid type / number of args"},
15 }
16 ErrMsgNoObject = Error{
17 "org.freedesktop.DBus.Error.NoSuchObject",
18 []interface{}{"No such object"},
19 }
20 ErrMsgUnknownMethod = Error{
21 "org.freedesktop.DBus.Error.UnknownMethod",
22 []interface{}{"Unknown / invalid method"},
23 }
24 ErrMsgUnknownInterface = Error{
25 "org.freedesktop.DBus.Error.UnknownInterface",
26 []interface{}{"Object does not implement the interface"},
27 }
28 )
29
30 func MakeNoObjectError(path ObjectPath) Error {
31 return Error{
32 "org.freedesktop.DBus.Error.NoSuchObject",
33 []interface{}{fmt.Sprintf("No such object '%s'", string(path))},
34 }
35 }
36
37 func MakeUnknownMethodError(methodName string) Error {
38 return Error{
39 "org.freedesktop.DBus.Error.UnknownMethod",
40 []interface{}{fmt.Sprintf("Unknown / invalid method '%s'", methodName)},
41 }
42 }
43
44 func MakeUnknownInterfaceError(ifaceName string) Error {
45 return Error{
46 "org.freedesktop.DBus.Error.UnknownInterface",
47 []interface{}{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)},
48 }
49 }
50
51 func MakeFailedError(err error) *Error {
52 return &Error{
53 "org.freedesktop.DBus.Error.Failed",
54 []interface{}{err.Error()},
55 }
56 }
57
58
59
60 type Sender string
61
62 func computeMethodName(name string, mapping map[string]string) string {
63 newname, ok := mapping[name]
64 if ok {
65 name = newname
66 }
67 return name
68 }
69
70 func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
71 if in == nil {
72 return nil
73 }
74 methods := make(map[string]reflect.Value)
75 val := reflect.ValueOf(in)
76 typ := val.Type()
77 for i := 0; i < typ.NumMethod(); i++ {
78 methtype := typ.Method(i)
79 method := val.Method(i)
80 t := method.Type()
81
82
83 if t.NumOut() == 0 ||
84 t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) ||
85 methtype.PkgPath != "" {
86 continue
87 }
88
89 methods[computeMethodName(methtype.Name, mapping)] = method
90 }
91 return methods
92 }
93
94 func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
95 if in == nil {
96 return nil
97 }
98 methods := make(map[string]reflect.Value)
99 val := reflect.ValueOf(in)
100 typ := val.Type()
101 for i := 0; i < typ.NumMethod(); i++ {
102 methtype := typ.Method(i)
103 method := val.Method(i)
104
105 methods[computeMethodName(methtype.Name, mapping)] = method
106 }
107 return methods
108 }
109
110 func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) {
111 pointers := make([]interface{}, m.NumArguments())
112 decode := make([]interface{}, 0, len(body))
113
114 for i := 0; i < m.NumArguments(); i++ {
115 tp := reflect.TypeOf(m.ArgumentValue(i))
116 val := reflect.New(tp)
117 pointers[i] = val.Interface()
118 if tp == reflect.TypeOf((*Sender)(nil)).Elem() {
119 val.Elem().SetString(sender)
120 } else if tp == reflect.TypeOf((*Message)(nil)).Elem() {
121 val.Elem().Set(reflect.ValueOf(*msg))
122 } else {
123 decode = append(decode, pointers[i])
124 }
125 }
126
127 if len(decode) != len(body) {
128 return nil, ErrMsgInvalidArg
129 }
130
131 if err := Store(body, decode...); err != nil {
132 return nil, ErrMsgInvalidArg
133 }
134
135 return pointers, nil
136 }
137
138 func (conn *Conn) decodeArguments(m Method, sender string, msg *Message) ([]interface{}, error) {
139 if decoder, ok := m.(ArgumentDecoder); ok {
140 return decoder.DecodeArguments(conn, sender, msg, msg.Body)
141 }
142 return standardMethodArgumentDecode(m, sender, msg, msg.Body)
143 }
144
145
146
147 func (conn *Conn) handleCall(msg *Message) {
148 name := msg.Headers[FieldMember].value.(string)
149 path := msg.Headers[FieldPath].value.(ObjectPath)
150 ifaceName, _ := msg.Headers[FieldInterface].value.(string)
151 sender, hasSender := msg.Headers[FieldSender].value.(string)
152 serial := msg.serial
153
154 if len(name) == 0 {
155 conn.sendError(ErrMsgUnknownMethod, sender, serial)
156 }
157
158 if ifaceName == "org.freedesktop.DBus.Peer" {
159 switch name {
160 case "Ping":
161 conn.sendReply(sender, serial)
162 case "GetMachineId":
163 conn.sendReply(sender, serial, conn.uuid)
164 default:
165 conn.sendError(MakeUnknownMethodError(name), sender, serial)
166 }
167 return
168 }
169
170 object, ok := conn.handler.LookupObject(path)
171 if !ok {
172 conn.sendError(MakeNoObjectError(path), sender, serial)
173 return
174 }
175
176 iface, exists := object.LookupInterface(ifaceName)
177 if !exists {
178 conn.sendError(MakeUnknownInterfaceError(ifaceName), sender, serial)
179 return
180 }
181
182 m, exists := iface.LookupMethod(name)
183 if !exists {
184 conn.sendError(MakeUnknownMethodError(name), sender, serial)
185 return
186 }
187 args, err := conn.decodeArguments(m, sender, msg)
188 if err != nil {
189 conn.sendError(err, sender, serial)
190 return
191 }
192
193 ret, err := m.Call(args...)
194 if err != nil {
195 conn.sendError(err, sender, serial)
196 return
197 }
198
199 if msg.Flags&FlagNoReplyExpected == 0 {
200 reply := new(Message)
201 reply.Type = TypeMethodReply
202 reply.Headers = make(map[HeaderField]Variant)
203 if hasSender {
204 reply.Headers[FieldDestination] = msg.Headers[FieldSender]
205 }
206 reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
207 reply.Body = make([]interface{}, len(ret))
208 for i := 0; i < len(ret); i++ {
209 reply.Body[i] = ret[i]
210 }
211 reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
212
213 if err := reply.IsValid(); err != nil {
214 fmt.Fprintf(os.Stderr, "dbus: dropping invalid reply to %s.%s on obj %s: %s\n", ifaceName, name, path, err)
215 } else {
216 conn.sendMessageAndIfClosed(reply, nil)
217 }
218 }
219 }
220
221
222
223 func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
224 i := strings.LastIndex(name, ".")
225 if i == -1 {
226 return errors.New("dbus: invalid method name")
227 }
228 iface := name[:i]
229 member := name[i+1:]
230 msg := new(Message)
231 msg.Type = TypeSignal
232 msg.Headers = make(map[HeaderField]Variant)
233 msg.Headers[FieldInterface] = MakeVariant(iface)
234 msg.Headers[FieldMember] = MakeVariant(member)
235 msg.Headers[FieldPath] = MakeVariant(path)
236 msg.Body = values
237 if len(values) > 0 {
238 msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
239 }
240 if err := msg.IsValid(); err != nil {
241 return err
242 }
243
244 var closed bool
245 conn.sendMessageAndIfClosed(msg, func() {
246 closed = true
247 })
248 if closed {
249 return ErrClosed
250 }
251 return nil
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282 func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
283 return conn.ExportWithMap(v, nil, path, iface)
284 }
285
286
287
288
289
290
291
292
293
294 func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error {
295 return conn.export(getAllMethods(v, nil), path, iface, false)
296 }
297
298
299
300
301
302
303 func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
304 return conn.export(getMethods(v, mapping), path, iface, false)
305 }
306
307
308
309
310
311
312
313
314
315
316
317 func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error {
318 return conn.ExportSubtreeWithMap(v, nil, path, iface)
319 }
320
321
322
323
324
325
326 func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
327 return conn.export(getMethods(v, mapping), path, iface, true)
328 }
329
330
331
332
333
334
335
336
337
338
339
340 func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
341 return conn.exportMethodTable(methods, path, iface, false)
342 }
343
344
345 func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
346 return conn.exportMethodTable(methods, path, iface, true)
347 }
348
349 func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
350 var out map[string]reflect.Value
351 if methods != nil {
352 out = make(map[string]reflect.Value)
353 for name, method := range methods {
354 rval := reflect.ValueOf(method)
355 if rval.Kind() != reflect.Func {
356 continue
357 }
358 t := rval.Type()
359
360 if t.NumOut() == 0 ||
361 t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
362 continue
363 }
364 out[name] = rval
365 }
366 }
367 return conn.export(out, path, iface, includeSubtree)
368 }
369
370 func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) error {
371 if h.PathExists(path) {
372 obj := h.objects[path]
373 obj.DeleteInterface(iface)
374 if len(obj.interfaces) == 0 {
375 h.DeleteObject(path)
376 }
377 }
378 return nil
379 }
380
381
382 func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
383 h, ok := conn.handler.(*defaultHandler)
384 if !ok {
385 return fmt.Errorf(
386 `dbus: export only allowed on the default handler. Received: %T"`,
387 conn.handler)
388 }
389
390 if !path.IsValid() {
391 return fmt.Errorf(`dbus: Invalid path name: "%s"`, path)
392 }
393
394
395 if methods == nil {
396 return conn.unexport(h, path, iface)
397 }
398
399
400
401 if !h.PathExists(path) {
402 h.AddObject(path, newExportedObject())
403 }
404
405 exportedMethods := make(map[string]Method)
406 for name, method := range methods {
407 exportedMethods[name] = exportedMethod{method}
408 }
409
410
411 obj := h.objects[path]
412 obj.AddInterface(iface, newExportedIntf(exportedMethods, includeSubtree))
413
414 return nil
415 }
416
417
418 func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) {
419 var r uint32
420 err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r)
421 if err != nil {
422 return 0, err
423 }
424 return ReleaseNameReply(r), nil
425 }
426
427
428 func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) {
429 var r uint32
430 err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r)
431 if err != nil {
432 return 0, err
433 }
434 return RequestNameReply(r), nil
435 }
436
437
438 type ReleaseNameReply uint32
439
440 const (
441 ReleaseNameReplyReleased ReleaseNameReply = 1 + iota
442 ReleaseNameReplyNonExistent
443 ReleaseNameReplyNotOwner
444 )
445
446
447 type RequestNameFlags uint32
448
449 const (
450 NameFlagAllowReplacement RequestNameFlags = 1 << iota
451 NameFlagReplaceExisting
452 NameFlagDoNotQueue
453 )
454
455
456 type RequestNameReply uint32
457
458 const (
459 RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota
460 RequestNameReplyInQueue
461 RequestNameReplyExists
462 RequestNameReplyAlreadyOwner
463 )
464
View as plain text