Merge lp:~dobey/pay-service/initial-iap into lp:pay-service/15.04

Proposed by dobey
Status: Merged
Approved by: Kyle Fazzari
Approved revision: 52
Merged at revision: 52
Proposed branch: lp:~dobey/pay-service/initial-iap
Merge into: lp:pay-service/15.04
Prerequisite: lp:~dobey/pay-service/compile-fixes
Diff against target: 8468 lines (+8051/-5)
72 files modified
.bzrignore (+5/-1)
CMakeLists.txt (+1/-0)
data/CMakeLists.txt (+9/-1)
data/com.canonical.payments.service.in (+3/-0)
data/pay-service.conf.in (+1/-1)
debian/control (+2/-0)
debian/copyright (+30/-2)
debian/pay-service.install (+2/-0)
service-ng/CMakeLists.txt (+26/-0)
service-ng/src/github.com/godbus/dbus/CONTRIBUTING.md (+50/-0)
service-ng/src/github.com/godbus/dbus/LICENSE (+25/-0)
service-ng/src/github.com/godbus/dbus/MAINTAINERS (+2/-0)
service-ng/src/github.com/godbus/dbus/README.markdown (+38/-0)
service-ng/src/github.com/godbus/dbus/_examples/eavesdrop.go (+30/-0)
service-ng/src/github.com/godbus/dbus/_examples/introspect.go (+21/-0)
service-ng/src/github.com/godbus/dbus/_examples/list-names.go (+27/-0)
service-ng/src/github.com/godbus/dbus/_examples/notification.go (+17/-0)
service-ng/src/github.com/godbus/dbus/_examples/prop.go (+68/-0)
service-ng/src/github.com/godbus/dbus/_examples/server.go (+45/-0)
service-ng/src/github.com/godbus/dbus/_examples/signal.go (+24/-0)
service-ng/src/github.com/godbus/dbus/auth.go (+253/-0)
service-ng/src/github.com/godbus/dbus/auth_external.go (+26/-0)
service-ng/src/github.com/godbus/dbus/auth_sha1.go (+102/-0)
service-ng/src/github.com/godbus/dbus/call.go (+36/-0)
service-ng/src/github.com/godbus/dbus/conn.go (+624/-0)
service-ng/src/github.com/godbus/dbus/conn_darwin.go (+21/-0)
service-ng/src/github.com/godbus/dbus/conn_other.go (+27/-0)
service-ng/src/github.com/godbus/dbus/conn_test.go (+199/-0)
service-ng/src/github.com/godbus/dbus/dbus.go (+258/-0)
service-ng/src/github.com/godbus/dbus/decoder.go (+228/-0)
service-ng/src/github.com/godbus/dbus/doc.go (+63/-0)
service-ng/src/github.com/godbus/dbus/encoder.go (+208/-0)
service-ng/src/github.com/godbus/dbus/encoder_test.go (+58/-0)
service-ng/src/github.com/godbus/dbus/examples_test.go (+50/-0)
service-ng/src/github.com/godbus/dbus/export.go (+410/-0)
service-ng/src/github.com/godbus/dbus/export_test.go (+374/-0)
service-ng/src/github.com/godbus/dbus/homedir.go (+28/-0)
service-ng/src/github.com/godbus/dbus/homedir_dynamic.go (+15/-0)
service-ng/src/github.com/godbus/dbus/homedir_static.go (+45/-0)
service-ng/src/github.com/godbus/dbus/introspect/call.go (+27/-0)
service-ng/src/github.com/godbus/dbus/introspect/introspect.go (+86/-0)
service-ng/src/github.com/godbus/dbus/introspect/introspectable.go (+76/-0)
service-ng/src/github.com/godbus/dbus/message.go (+346/-0)
service-ng/src/github.com/godbus/dbus/object.go (+126/-0)
service-ng/src/github.com/godbus/dbus/prop/prop.go (+264/-0)
service-ng/src/github.com/godbus/dbus/proto_test.go (+369/-0)
service-ng/src/github.com/godbus/dbus/sig.go (+257/-0)
service-ng/src/github.com/godbus/dbus/sig_test.go (+70/-0)
service-ng/src/github.com/godbus/dbus/transport_darwin.go (+6/-0)
service-ng/src/github.com/godbus/dbus/transport_generic.go (+35/-0)
service-ng/src/github.com/godbus/dbus/transport_unix.go (+196/-0)
service-ng/src/github.com/godbus/dbus/transport_unix_test.go (+49/-0)
service-ng/src/github.com/godbus/dbus/transport_unixcred_dragonfly.go (+95/-0)
service-ng/src/github.com/godbus/dbus/transport_unixcred_linux.go (+25/-0)
service-ng/src/github.com/godbus/dbus/variant.go (+139/-0)
service-ng/src/github.com/godbus/dbus/variant_lexer.go (+284/-0)
service-ng/src/github.com/godbus/dbus/variant_parser.go (+817/-0)
service-ng/src/github.com/godbus/dbus/variant_test.go (+78/-0)
service-ng/src/pay-service-2/main.go (+60/-0)
service-ng/src/pay-service-2/service/dbus_server.go (+136/-0)
service-ng/src/pay-service-2/service/dbus_server_test.go (+178/-0)
service-ng/src/pay-service-2/service/dbus_wrapper.go (+34/-0)
service-ng/src/pay-service-2/service/fake_dbus_server_test.go (+138/-0)
service-ng/src/pay-service-2/service/fake_timer.go (+51/-0)
service-ng/src/pay-service-2/service/pay_service.go (+141/-0)
service-ng/src/pay-service-2/service/pay_service_test.go (+235/-0)
service-ng/src/pay-service-2/service/service.go (+122/-0)
service-ng/src/pay-service-2/service/service_test.go (+65/-0)
service-ng/src/pay-service-2/service/timer_iface.go (+27/-0)
service-ng/src/update-externals.sh (+42/-0)
service-ng/src/vendor.cfg (+1/-0)
service-ng/test-service.sh (+25/-0)
To merge this branch: bzr merge lp:~dobey/pay-service/initial-iap
Reviewer Review Type Date Requested Status
Kyle Fazzari (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+270087@code.launchpad.net

Commit message

Initial backport of necessary code for IAP.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kyle Fazzari (kyrofa) wrote :

Yep, this looks familiar.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-06-13 17:05:49 +0000
3+++ .bzrignore 2015-09-03 16:43:03 +0000
4@@ -12,7 +12,11 @@
5 verification-curl-tests
6 tests/verification-curl-endpoints/good/simple
7 purchase-ual-tests
8-click-db/test.conf
9 libpay.so.1.0.0
10 libpay-tests
11 verification-curl-endpoints/package-name
12+*.service
13+
14+
15+build/
16+builddir/
17
18=== modified file 'CMakeLists.txt'
19--- CMakeLists.txt 2015-09-03 16:43:02 +0000
20+++ CMakeLists.txt 2015-09-03 16:43:03 +0000
21@@ -81,6 +81,7 @@
22 add_subdirectory(common)
23 add_subdirectory(libpay)
24 add_subdirectory(service)
25+add_subdirectory(service-ng)
26 add_subdirectory(data)
27 if (${enable_tests})
28 add_subdirectory(tests)
29
30=== modified file 'data/CMakeLists.txt'
31--- data/CMakeLists.txt 2014-04-29 03:07:19 +0000
32+++ data/CMakeLists.txt 2015-09-03 16:43:03 +0000
33@@ -2,8 +2,16 @@
34 ##############################
35 # Upstart Job
36 ##############################
37-
38 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pay-service.conf.in ${CMAKE_CURRENT_BINARY_DIR}/pay-service.conf @ONLY)
39 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pay-service.conf
40 DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/upstart/sessions/)
41
42+# New dbus service file
43+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.payments.service.in
44+ ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.payments.service
45+ @ONLY
46+)
47+install(
48+ FILES ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.payments.service
49+ DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/dbus-1/services/
50+)
51
52=== added file 'data/com.canonical.payments.service.in'
53--- data/com.canonical.payments.service.in 1970-01-01 00:00:00 +0000
54+++ data/com.canonical.payments.service.in 2015-09-03 16:43:03 +0000
55@@ -0,0 +1,3 @@
56+[D-BUS Service]
57+Name=com.canonical.payments
58+Exec=@CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/pay-service-2
59
60=== modified file 'data/pay-service.conf.in'
61--- data/pay-service.conf.in 2014-05-30 13:23:15 +0000
62+++ data/pay-service.conf.in 2015-09-03 16:43:03 +0000
63@@ -5,4 +5,4 @@
64
65 respawn
66
67-exec @CMAKE_INSTALL_FULL_LIBEXECDIR@/pay-service/pay-service
68+exec @CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/pay-service
69
70=== modified file 'debian/control'
71--- debian/control 2015-09-03 16:43:02 +0000
72+++ debian/control 2015-09-03 16:43:03 +0000
73@@ -9,6 +9,8 @@
74 dbus-test-runner,
75 debhelper (>= 9),
76 gcovr,
77+ golang-go,
78+ golang-go.tools [amd64 armhf i386] | golang-go (>= 2:1.5~rc1),
79 google-mock,
80 lcov,
81 libaccounts-qt5-dev,
82
83=== modified file 'debian/copyright'
84--- debian/copyright 2014-05-20 15:13:10 +0000
85+++ debian/copyright 2015-09-03 16:43:03 +0000
86@@ -3,13 +3,41 @@
87 Source: http://launchpad.net/pay-service
88
89 Files: *
90-Copyright: 2014 Canonical, Ltd.
91+Copyright: 2014-2015 Canonical, Ltd.
92 License: GPL-3
93
94 Files: libpay/*
95-Copyright: 2014 Canonical, Ltd.
96+Copyright: 2014-2015 Canonical, Ltd.
97 License: LGPL-3
98
99+Files: service-ng/src/github.com/godbus/dbus/*
100+Copyright: 2013 George Reinke <guelfey@gmail.com>, Google Inc.
101+License: BSD-Simplified
102+
103+License: BSD-Simplified
104+ Redistribution and use in source and binary forms, with or without
105+ modification, are permitted provided that the following conditions
106+ are met:
107+ .
108+ 1. Redistributions of source code must retain the above copyright notice,
109+ this list of conditions and the following disclaimer.
110+ .
111+ 2. Redistributions in binary form must reproduce the above copyright
112+ notice, this list of conditions and the following disclaimer in the
113+ documentation and/or other materials provided with the distribution.
114+ .
115+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
116+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
117+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
118+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
119+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
120+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
121+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
122+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
123+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
124+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
125+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
126+
127 License: GPL-3
128 This package is free software; you can redistribute it and/or
129 modify it under the terms of the GNU General Public
130
131=== modified file 'debian/pay-service.install'
132--- debian/pay-service.install 2015-09-03 16:43:02 +0000
133+++ debian/pay-service.install 2015-09-03 16:43:03 +0000
134@@ -1,4 +1,6 @@
135 usr/lib/*/pay-service/pay-service
136+usr/lib/*/pay-service/pay-service-2
137 usr/lib/*/pay-service/setup-staging.sh
138 usr/lib/*/ubuntu-app-launch/pay-ui/*
139+usr/share/dbus-1/services/*.service
140 usr/share/upstart/sessions/*
141
142=== added directory 'service-ng'
143=== added file 'service-ng/CMakeLists.txt'
144--- service-ng/CMakeLists.txt 1970-01-01 00:00:00 +0000
145+++ service-ng/CMakeLists.txt 2015-09-03 16:43:03 +0000
146@@ -0,0 +1,26 @@
147+# Here be Go
148+
149+set(SERVICE_NG_TARGET pay-service-2)
150+
151+add_custom_target(${SERVICE_NG_TARGET} ALL
152+ COMMAND GOPATH=${CMAKE_CURRENT_SOURCE_DIR} go build ${SERVICE_NG_TARGET}
153+)
154+
155+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${SERVICE_NG_TARGET}
156+ DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}
157+)
158+
159+set(TEST_TYPE "normal")
160+string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
161+if("${CMAKE_BUILD_TYPE_LOWER}" STREQUAL "coverage")
162+ set(TEST_TYPE "coverage")
163+endif()
164+
165+add_custom_target(test-service-ng
166+ COMMAND GOPATH=${CMAKE_CURRENT_SOURCE_DIR} dbus-test-runner -m 600 -t ${CMAKE_CURRENT_SOURCE_DIR}/test-service.sh -p ${SERVICE_NG_TARGET}/service -p ${TEST_TYPE}
167+ DEPENDS ${SERVICE_NG_TARGET}
168+)
169+
170+add_test(NAME test-service-ng
171+ COMMAND make test-service-ng
172+)
173
174=== added directory 'service-ng/src'
175=== added directory 'service-ng/src/github.com'
176=== added directory 'service-ng/src/github.com/godbus'
177=== added directory 'service-ng/src/github.com/godbus/dbus'
178=== added file 'service-ng/src/github.com/godbus/dbus/CONTRIBUTING.md'
179--- service-ng/src/github.com/godbus/dbus/CONTRIBUTING.md 1970-01-01 00:00:00 +0000
180+++ service-ng/src/github.com/godbus/dbus/CONTRIBUTING.md 2015-09-03 16:43:03 +0000
181@@ -0,0 +1,50 @@
182+# How to Contribute
183+
184+## Getting Started
185+
186+- Fork the repository on GitHub
187+- Read the [README](README.markdown) for build and test instructions
188+- Play with the project, submit bugs, submit patches!
189+
190+## Contribution Flow
191+
192+This is a rough outline of what a contributor's workflow looks like:
193+
194+- Create a topic branch from where you want to base your work (usually master).
195+- Make commits of logical units.
196+- Make sure your commit messages are in the proper format (see below).
197+- Push your changes to a topic branch in your fork of the repository.
198+- Make sure the tests pass, and add any new tests as appropriate.
199+- Submit a pull request to the original repository.
200+
201+Thanks for your contributions!
202+
203+### Format of the Commit Message
204+
205+We follow a rough convention for commit messages that is designed to answer two
206+questions: what changed and why. The subject line should feature the what and
207+the body of the commit should describe the why.
208+
209+```
210+scripts: add the test-cluster command
211+
212+this uses tmux to setup a test cluster that you can easily kill and
213+start for debugging.
214+
215+Fixes #38
216+```
217+
218+The format can be described more formally as follows:
219+
220+```
221+<subsystem>: <what changed>
222+<BLANK LINE>
223+<why this change was made>
224+<BLANK LINE>
225+<footer>
226+```
227+
228+The first line is the subject and should be no longer than 70 characters, the
229+second line is always blank, and other lines should be wrapped at 80 characters.
230+This allows the message to be easier to read on GitHub as well as in various
231+git tools.
232
233=== added file 'service-ng/src/github.com/godbus/dbus/LICENSE'
234--- service-ng/src/github.com/godbus/dbus/LICENSE 1970-01-01 00:00:00 +0000
235+++ service-ng/src/github.com/godbus/dbus/LICENSE 2015-09-03 16:43:03 +0000
236@@ -0,0 +1,25 @@
237+Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>), Google
238+All rights reserved.
239+
240+Redistribution and use in source and binary forms, with or without
241+modification, are permitted provided that the following conditions
242+are met:
243+
244+1. Redistributions of source code must retain the above copyright notice,
245+this list of conditions and the following disclaimer.
246+
247+2. Redistributions in binary form must reproduce the above copyright
248+notice, this list of conditions and the following disclaimer in the
249+documentation and/or other materials provided with the distribution.
250+
251+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
252+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
253+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
254+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
255+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
256+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
257+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
258+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
259+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
260+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
261+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262
263=== added file 'service-ng/src/github.com/godbus/dbus/MAINTAINERS'
264--- service-ng/src/github.com/godbus/dbus/MAINTAINERS 1970-01-01 00:00:00 +0000
265+++ service-ng/src/github.com/godbus/dbus/MAINTAINERS 2015-09-03 16:43:03 +0000
266@@ -0,0 +1,2 @@
267+Brandon Philips <brandon@ifup.org> (@philips)
268+Brian Waldon <brian@waldon.cc> (@bcwaldon)
269
270=== added file 'service-ng/src/github.com/godbus/dbus/README.markdown'
271--- service-ng/src/github.com/godbus/dbus/README.markdown 1970-01-01 00:00:00 +0000
272+++ service-ng/src/github.com/godbus/dbus/README.markdown 2015-09-03 16:43:03 +0000
273@@ -0,0 +1,38 @@
274+dbus
275+----
276+
277+dbus is a simple library that implements native Go client bindings for the
278+D-Bus message bus system.
279+
280+### Features
281+
282+* Complete native implementation of the D-Bus message protocol
283+* Go-like API (channels for signals / asynchronous method calls, Goroutine-safe connections)
284+* Subpackages that help with the introspection / property interfaces
285+
286+### Installation
287+
288+This packages requires Go 1.1. If you installed it and set up your GOPATH, just run:
289+
290+```
291+go get github.com/godbus/dbus
292+```
293+
294+If you want to use the subpackages, you can install them the same way.
295+
296+### Usage
297+
298+The complete package documentation and some simple examples are available at
299+[godoc.org](http://godoc.org/github.com/godbus/dbus). Also, the
300+[_examples](https://github.com/godbus/dbus/tree/master/_examples) directory
301+gives a short overview over the basic usage.
302+
303+Please note that the API is considered unstable for now and may change without
304+further notice.
305+
306+### License
307+
308+go.dbus is available under the Simplified BSD License; see LICENSE for the full
309+text.
310+
311+Nearly all of the credit for this library goes to github.com/guelfey/go.dbus.
312
313=== added directory 'service-ng/src/github.com/godbus/dbus/_examples'
314=== added file 'service-ng/src/github.com/godbus/dbus/_examples/eavesdrop.go'
315--- service-ng/src/github.com/godbus/dbus/_examples/eavesdrop.go 1970-01-01 00:00:00 +0000
316+++ service-ng/src/github.com/godbus/dbus/_examples/eavesdrop.go 2015-09-03 16:43:03 +0000
317@@ -0,0 +1,30 @@
318+package main
319+
320+import (
321+ "fmt"
322+ "github.com/godbus/dbus"
323+ "os"
324+)
325+
326+func main() {
327+ conn, err := dbus.SessionBus()
328+ if err != nil {
329+ fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
330+ os.Exit(1)
331+ }
332+
333+ for _, v := range []string{"method_call", "method_return", "error", "signal"} {
334+ call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
335+ "eavesdrop='true',type='"+v+"'")
336+ if call.Err != nil {
337+ fmt.Fprintln(os.Stderr, "Failed to add match:", call.Err)
338+ os.Exit(1)
339+ }
340+ }
341+ c := make(chan *dbus.Message, 10)
342+ conn.Eavesdrop(c)
343+ fmt.Println("Listening for everything")
344+ for v := range c {
345+ fmt.Println(v)
346+ }
347+}
348
349=== added file 'service-ng/src/github.com/godbus/dbus/_examples/introspect.go'
350--- service-ng/src/github.com/godbus/dbus/_examples/introspect.go 1970-01-01 00:00:00 +0000
351+++ service-ng/src/github.com/godbus/dbus/_examples/introspect.go 2015-09-03 16:43:03 +0000
352@@ -0,0 +1,21 @@
353+package main
354+
355+import (
356+ "encoding/json"
357+ "github.com/godbus/dbus"
358+ "github.com/godbus/dbus/introspect"
359+ "os"
360+)
361+
362+func main() {
363+ conn, err := dbus.SessionBus()
364+ if err != nil {
365+ panic(err)
366+ }
367+ node, err := introspect.Call(conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus"))
368+ if err != nil {
369+ panic(err)
370+ }
371+ data, _ := json.MarshalIndent(node, "", " ")
372+ os.Stdout.Write(data)
373+}
374
375=== added file 'service-ng/src/github.com/godbus/dbus/_examples/list-names.go'
376--- service-ng/src/github.com/godbus/dbus/_examples/list-names.go 1970-01-01 00:00:00 +0000
377+++ service-ng/src/github.com/godbus/dbus/_examples/list-names.go 2015-09-03 16:43:03 +0000
378@@ -0,0 +1,27 @@
379+package main
380+
381+import (
382+ "fmt"
383+ "github.com/godbus/dbus"
384+ "os"
385+)
386+
387+func main() {
388+ conn, err := dbus.SessionBus()
389+ if err != nil {
390+ fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
391+ os.Exit(1)
392+ }
393+
394+ var s []string
395+ err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&s)
396+ if err != nil {
397+ fmt.Fprintln(os.Stderr, "Failed to get list of owned names:", err)
398+ os.Exit(1)
399+ }
400+
401+ fmt.Println("Currently owned names on the session bus:")
402+ for _, v := range s {
403+ fmt.Println(v)
404+ }
405+}
406
407=== added file 'service-ng/src/github.com/godbus/dbus/_examples/notification.go'
408--- service-ng/src/github.com/godbus/dbus/_examples/notification.go 1970-01-01 00:00:00 +0000
409+++ service-ng/src/github.com/godbus/dbus/_examples/notification.go 2015-09-03 16:43:03 +0000
410@@ -0,0 +1,17 @@
411+package main
412+
413+import "github.com/godbus/dbus"
414+
415+func main() {
416+ conn, err := dbus.SessionBus()
417+ if err != nil {
418+ panic(err)
419+ }
420+ obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
421+ call := obj.Call("org.freedesktop.Notifications.Notify", 0, "", uint32(0),
422+ "", "Test", "This is a test of the DBus bindings for go.", []string{},
423+ map[string]dbus.Variant{}, int32(5000))
424+ if call.Err != nil {
425+ panic(call.Err)
426+ }
427+}
428
429=== added file 'service-ng/src/github.com/godbus/dbus/_examples/prop.go'
430--- service-ng/src/github.com/godbus/dbus/_examples/prop.go 1970-01-01 00:00:00 +0000
431+++ service-ng/src/github.com/godbus/dbus/_examples/prop.go 2015-09-03 16:43:03 +0000
432@@ -0,0 +1,68 @@
433+package main
434+
435+import (
436+ "fmt"
437+ "github.com/godbus/dbus"
438+ "github.com/godbus/dbus/introspect"
439+ "github.com/godbus/dbus/prop"
440+ "os"
441+)
442+
443+type foo string
444+
445+func (f foo) Foo() (string, *dbus.Error) {
446+ fmt.Println(f)
447+ return string(f), nil
448+}
449+
450+func main() {
451+ conn, err := dbus.SessionBus()
452+ if err != nil {
453+ panic(err)
454+ }
455+ reply, err := conn.RequestName("com.github.guelfey.Demo",
456+ dbus.NameFlagDoNotQueue)
457+ if err != nil {
458+ panic(err)
459+ }
460+ if reply != dbus.RequestNameReplyPrimaryOwner {
461+ fmt.Fprintln(os.Stderr, "name already taken")
462+ os.Exit(1)
463+ }
464+ propsSpec := map[string]map[string]*prop.Prop{
465+ "com.github.guelfey.Demo": {
466+ "SomeInt": {
467+ int32(0),
468+ true,
469+ prop.EmitTrue,
470+ func(c *prop.Change) *dbus.Error {
471+ fmt.Println(c.Name, "changed to", c.Value)
472+ return nil
473+ },
474+ },
475+ },
476+ }
477+ f := foo("Bar")
478+ conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
479+ props := prop.New(conn, "/com/github/guelfey/Demo", propsSpec)
480+ n := &introspect.Node{
481+ Name: "/com/github/guelfey/Demo",
482+ Interfaces: []introspect.Interface{
483+ introspect.IntrospectData,
484+ prop.IntrospectData,
485+ {
486+ Name: "com.github.guelfey.Demo",
487+ Methods: introspect.Methods(f),
488+ Properties: props.Introspection("com.github.guelfey.Demo"),
489+ },
490+ },
491+ }
492+ conn.Export(introspect.NewIntrospectable(n), "/com/github/guelfey/Demo",
493+ "org.freedesktop.DBus.Introspectable")
494+ fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
495+
496+ c := make(chan *dbus.Signal)
497+ conn.Signal(c)
498+ for _ = range c {
499+ }
500+}
501
502=== added file 'service-ng/src/github.com/godbus/dbus/_examples/server.go'
503--- service-ng/src/github.com/godbus/dbus/_examples/server.go 1970-01-01 00:00:00 +0000
504+++ service-ng/src/github.com/godbus/dbus/_examples/server.go 2015-09-03 16:43:03 +0000
505@@ -0,0 +1,45 @@
506+package main
507+
508+import (
509+ "fmt"
510+ "github.com/godbus/dbus"
511+ "github.com/godbus/dbus/introspect"
512+ "os"
513+)
514+
515+const intro = `
516+<node>
517+ <interface name="com.github.guelfey.Demo">
518+ <method name="Foo">
519+ <arg direction="out" type="s"/>
520+ </method>
521+ </interface>` + introspect.IntrospectDataString + `</node> `
522+
523+type foo string
524+
525+func (f foo) Foo() (string, *dbus.Error) {
526+ fmt.Println(f)
527+ return string(f), nil
528+}
529+
530+func main() {
531+ conn, err := dbus.SessionBus()
532+ if err != nil {
533+ panic(err)
534+ }
535+ reply, err := conn.RequestName("com.github.guelfey.Demo",
536+ dbus.NameFlagDoNotQueue)
537+ if err != nil {
538+ panic(err)
539+ }
540+ if reply != dbus.RequestNameReplyPrimaryOwner {
541+ fmt.Fprintln(os.Stderr, "name already taken")
542+ os.Exit(1)
543+ }
544+ f := foo("Bar!")
545+ conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
546+ conn.Export(introspect.Introspectable(intro), "/com/github/guelfey/Demo",
547+ "org.freedesktop.DBus.Introspectable")
548+ fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
549+ select {}
550+}
551
552=== added file 'service-ng/src/github.com/godbus/dbus/_examples/signal.go'
553--- service-ng/src/github.com/godbus/dbus/_examples/signal.go 1970-01-01 00:00:00 +0000
554+++ service-ng/src/github.com/godbus/dbus/_examples/signal.go 2015-09-03 16:43:03 +0000
555@@ -0,0 +1,24 @@
556+package main
557+
558+import (
559+ "fmt"
560+ "github.com/godbus/dbus"
561+ "os"
562+)
563+
564+func main() {
565+ conn, err := dbus.SessionBus()
566+ if err != nil {
567+ fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
568+ os.Exit(1)
569+ }
570+
571+ conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
572+ "type='signal',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',sender='org.freedesktop.DBus'")
573+
574+ c := make(chan *dbus.Signal, 10)
575+ conn.Signal(c)
576+ for v := range c {
577+ fmt.Println(v)
578+ }
579+}
580
581=== added file 'service-ng/src/github.com/godbus/dbus/auth.go'
582--- service-ng/src/github.com/godbus/dbus/auth.go 1970-01-01 00:00:00 +0000
583+++ service-ng/src/github.com/godbus/dbus/auth.go 2015-09-03 16:43:03 +0000
584@@ -0,0 +1,253 @@
585+package dbus
586+
587+import (
588+ "bufio"
589+ "bytes"
590+ "errors"
591+ "io"
592+ "os"
593+ "strconv"
594+)
595+
596+// AuthStatus represents the Status of an authentication mechanism.
597+type AuthStatus byte
598+
599+const (
600+ // AuthOk signals that authentication is finished; the next command
601+ // from the server should be an OK.
602+ AuthOk AuthStatus = iota
603+
604+ // AuthContinue signals that additional data is needed; the next command
605+ // from the server should be a DATA.
606+ AuthContinue
607+
608+ // AuthError signals an error; the server sent invalid data or some
609+ // other unexpected thing happened and the current authentication
610+ // process should be aborted.
611+ AuthError
612+)
613+
614+type authState byte
615+
616+const (
617+ waitingForData authState = iota
618+ waitingForOk
619+ waitingForReject
620+)
621+
622+// Auth defines the behaviour of an authentication mechanism.
623+type Auth interface {
624+ // Return the name of the mechnism, the argument to the first AUTH command
625+ // and the next status.
626+ FirstData() (name, resp []byte, status AuthStatus)
627+
628+ // Process the given DATA command, and return the argument to the DATA
629+ // command and the next status. If len(resp) == 0, no DATA command is sent.
630+ HandleData(data []byte) (resp []byte, status AuthStatus)
631+}
632+
633+// Auth authenticates the connection, trying the given list of authentication
634+// mechanisms (in that order). If nil is passed, the EXTERNAL and
635+// DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private
636+// connections, this method must be called before sending any messages to the
637+// bus. Auth must not be called on shared connections.
638+func (conn *Conn) Auth(methods []Auth) error {
639+ if methods == nil {
640+ uid := strconv.Itoa(os.Getuid())
641+ methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
642+ }
643+ in := bufio.NewReader(conn.transport)
644+ err := conn.transport.SendNullByte()
645+ if err != nil {
646+ return err
647+ }
648+ err = authWriteLine(conn.transport, []byte("AUTH"))
649+ if err != nil {
650+ return err
651+ }
652+ s, err := authReadLine(in)
653+ if err != nil {
654+ return err
655+ }
656+ if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) {
657+ return errors.New("dbus: authentication protocol error")
658+ }
659+ s = s[1:]
660+ for _, v := range s {
661+ for _, m := range methods {
662+ if name, data, status := m.FirstData(); bytes.Equal(v, name) {
663+ var ok bool
664+ err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data)
665+ if err != nil {
666+ return err
667+ }
668+ switch status {
669+ case AuthOk:
670+ err, ok = conn.tryAuth(m, waitingForOk, in)
671+ case AuthContinue:
672+ err, ok = conn.tryAuth(m, waitingForData, in)
673+ default:
674+ panic("dbus: invalid authentication status")
675+ }
676+ if err != nil {
677+ return err
678+ }
679+ if ok {
680+ if conn.transport.SupportsUnixFDs() {
681+ err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD"))
682+ if err != nil {
683+ return err
684+ }
685+ line, err := authReadLine(in)
686+ if err != nil {
687+ return err
688+ }
689+ switch {
690+ case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")):
691+ conn.EnableUnixFDs()
692+ conn.unixFD = true
693+ case bytes.Equal(line[0], []byte("ERROR")):
694+ default:
695+ return errors.New("dbus: authentication protocol error")
696+ }
697+ }
698+ err = authWriteLine(conn.transport, []byte("BEGIN"))
699+ if err != nil {
700+ return err
701+ }
702+ go conn.inWorker()
703+ go conn.outWorker()
704+ return nil
705+ }
706+ }
707+ }
708+ }
709+ return errors.New("dbus: authentication failed")
710+}
711+
712+// tryAuth tries to authenticate with m as the mechanism, using state as the
713+// initial authState and in for reading input. It returns (nil, true) on
714+// success, (nil, false) on a REJECTED and (someErr, false) if some other
715+// error occured.
716+func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) {
717+ for {
718+ s, err := authReadLine(in)
719+ if err != nil {
720+ return err, false
721+ }
722+ switch {
723+ case state == waitingForData && string(s[0]) == "DATA":
724+ if len(s) != 2 {
725+ err = authWriteLine(conn.transport, []byte("ERROR"))
726+ if err != nil {
727+ return err, false
728+ }
729+ continue
730+ }
731+ data, status := m.HandleData(s[1])
732+ switch status {
733+ case AuthOk, AuthContinue:
734+ if len(data) != 0 {
735+ err = authWriteLine(conn.transport, []byte("DATA"), data)
736+ if err != nil {
737+ return err, false
738+ }
739+ }
740+ if status == AuthOk {
741+ state = waitingForOk
742+ }
743+ case AuthError:
744+ err = authWriteLine(conn.transport, []byte("ERROR"))
745+ if err != nil {
746+ return err, false
747+ }
748+ }
749+ case state == waitingForData && string(s[0]) == "REJECTED":
750+ return nil, false
751+ case state == waitingForData && string(s[0]) == "ERROR":
752+ err = authWriteLine(conn.transport, []byte("CANCEL"))
753+ if err != nil {
754+ return err, false
755+ }
756+ state = waitingForReject
757+ case state == waitingForData && string(s[0]) == "OK":
758+ if len(s) != 2 {
759+ err = authWriteLine(conn.transport, []byte("CANCEL"))
760+ if err != nil {
761+ return err, false
762+ }
763+ state = waitingForReject
764+ }
765+ conn.uuid = string(s[1])
766+ return nil, true
767+ case state == waitingForData:
768+ err = authWriteLine(conn.transport, []byte("ERROR"))
769+ if err != nil {
770+ return err, false
771+ }
772+ case state == waitingForOk && string(s[0]) == "OK":
773+ if len(s) != 2 {
774+ err = authWriteLine(conn.transport, []byte("CANCEL"))
775+ if err != nil {
776+ return err, false
777+ }
778+ state = waitingForReject
779+ }
780+ conn.uuid = string(s[1])
781+ return nil, true
782+ case state == waitingForOk && string(s[0]) == "REJECTED":
783+ return nil, false
784+ case state == waitingForOk && (string(s[0]) == "DATA" ||
785+ string(s[0]) == "ERROR"):
786+
787+ err = authWriteLine(conn.transport, []byte("CANCEL"))
788+ if err != nil {
789+ return err, false
790+ }
791+ state = waitingForReject
792+ case state == waitingForOk:
793+ err = authWriteLine(conn.transport, []byte("ERROR"))
794+ if err != nil {
795+ return err, false
796+ }
797+ case state == waitingForReject && string(s[0]) == "REJECTED":
798+ return nil, false
799+ case state == waitingForReject:
800+ return errors.New("dbus: authentication protocol error"), false
801+ default:
802+ panic("dbus: invalid auth state")
803+ }
804+ }
805+}
806+
807+// authReadLine reads a line and separates it into its fields.
808+func authReadLine(in *bufio.Reader) ([][]byte, error) {
809+ data, err := in.ReadBytes('\n')
810+ if err != nil {
811+ return nil, err
812+ }
813+ data = bytes.TrimSuffix(data, []byte("\r\n"))
814+ return bytes.Split(data, []byte{' '}), nil
815+}
816+
817+// authWriteLine writes the given line in the authentication protocol format
818+// (elements of data separated by a " " and terminated by "\r\n").
819+func authWriteLine(out io.Writer, data ...[]byte) error {
820+ buf := make([]byte, 0)
821+ for i, v := range data {
822+ buf = append(buf, v...)
823+ if i != len(data)-1 {
824+ buf = append(buf, ' ')
825+ }
826+ }
827+ buf = append(buf, '\r')
828+ buf = append(buf, '\n')
829+ n, err := out.Write(buf)
830+ if err != nil {
831+ return err
832+ }
833+ if n != len(buf) {
834+ return io.ErrUnexpectedEOF
835+ }
836+ return nil
837+}
838
839=== added file 'service-ng/src/github.com/godbus/dbus/auth_external.go'
840--- service-ng/src/github.com/godbus/dbus/auth_external.go 1970-01-01 00:00:00 +0000
841+++ service-ng/src/github.com/godbus/dbus/auth_external.go 2015-09-03 16:43:03 +0000
842@@ -0,0 +1,26 @@
843+package dbus
844+
845+import (
846+ "encoding/hex"
847+)
848+
849+// AuthExternal returns an Auth that authenticates as the given user with the
850+// EXTERNAL mechanism.
851+func AuthExternal(user string) Auth {
852+ return authExternal{user}
853+}
854+
855+// AuthExternal implements the EXTERNAL authentication mechanism.
856+type authExternal struct {
857+ user string
858+}
859+
860+func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) {
861+ b := make([]byte, 2*len(a.user))
862+ hex.Encode(b, []byte(a.user))
863+ return []byte("EXTERNAL"), b, AuthOk
864+}
865+
866+func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) {
867+ return nil, AuthError
868+}
869
870=== added file 'service-ng/src/github.com/godbus/dbus/auth_sha1.go'
871--- service-ng/src/github.com/godbus/dbus/auth_sha1.go 1970-01-01 00:00:00 +0000
872+++ service-ng/src/github.com/godbus/dbus/auth_sha1.go 2015-09-03 16:43:03 +0000
873@@ -0,0 +1,102 @@
874+package dbus
875+
876+import (
877+ "bufio"
878+ "bytes"
879+ "crypto/rand"
880+ "crypto/sha1"
881+ "encoding/hex"
882+ "os"
883+)
884+
885+// AuthCookieSha1 returns an Auth that authenticates as the given user with the
886+// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home
887+// directory of the user.
888+func AuthCookieSha1(user, home string) Auth {
889+ return authCookieSha1{user, home}
890+}
891+
892+type authCookieSha1 struct {
893+ user, home string
894+}
895+
896+func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) {
897+ b := make([]byte, 2*len(a.user))
898+ hex.Encode(b, []byte(a.user))
899+ return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue
900+}
901+
902+func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
903+ challenge := make([]byte, len(data)/2)
904+ _, err := hex.Decode(challenge, data)
905+ if err != nil {
906+ return nil, AuthError
907+ }
908+ b := bytes.Split(challenge, []byte{' '})
909+ if len(b) != 3 {
910+ return nil, AuthError
911+ }
912+ context := b[0]
913+ id := b[1]
914+ svchallenge := b[2]
915+ cookie := a.getCookie(context, id)
916+ if cookie == nil {
917+ return nil, AuthError
918+ }
919+ clchallenge := a.generateChallenge()
920+ if clchallenge == nil {
921+ return nil, AuthError
922+ }
923+ hash := sha1.New()
924+ hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'}))
925+ hexhash := make([]byte, 2*hash.Size())
926+ hex.Encode(hexhash, hash.Sum(nil))
927+ data = append(clchallenge, ' ')
928+ data = append(data, hexhash...)
929+ resp := make([]byte, 2*len(data))
930+ hex.Encode(resp, data)
931+ return resp, AuthOk
932+}
933+
934+// getCookie searches for the cookie identified by id in context and returns
935+// the cookie content or nil. (Since HandleData can't return a specific error,
936+// but only whether an error occured, this function also doesn't bother to
937+// return an error.)
938+func (a authCookieSha1) getCookie(context, id []byte) []byte {
939+ file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
940+ if err != nil {
941+ return nil
942+ }
943+ defer file.Close()
944+ rd := bufio.NewReader(file)
945+ for {
946+ line, err := rd.ReadBytes('\n')
947+ if err != nil {
948+ return nil
949+ }
950+ line = line[:len(line)-1]
951+ b := bytes.Split(line, []byte{' '})
952+ if len(b) != 3 {
953+ return nil
954+ }
955+ if bytes.Equal(b[0], id) {
956+ return b[2]
957+ }
958+ }
959+}
960+
961+// generateChallenge returns a random, hex-encoded challenge, or nil on error
962+// (see above).
963+func (a authCookieSha1) generateChallenge() []byte {
964+ b := make([]byte, 16)
965+ n, err := rand.Read(b)
966+ if err != nil {
967+ return nil
968+ }
969+ if n != 16 {
970+ return nil
971+ }
972+ enc := make([]byte, 32)
973+ hex.Encode(enc, b)
974+ return enc
975+}
976
977=== added file 'service-ng/src/github.com/godbus/dbus/call.go'
978--- service-ng/src/github.com/godbus/dbus/call.go 1970-01-01 00:00:00 +0000
979+++ service-ng/src/github.com/godbus/dbus/call.go 2015-09-03 16:43:03 +0000
980@@ -0,0 +1,36 @@
981+package dbus
982+
983+import (
984+ "errors"
985+)
986+
987+// Call represents a pending or completed method call.
988+type Call struct {
989+ Destination string
990+ Path ObjectPath
991+ Method string
992+ Args []interface{}
993+
994+ // Strobes when the call is complete.
995+ Done chan *Call
996+
997+ // After completion, the error status. If this is non-nil, it may be an
998+ // error message from the peer (with Error as its type) or some other error.
999+ Err error
1000+
1001+ // Holds the response once the call is done.
1002+ Body []interface{}
1003+}
1004+
1005+var errSignature = errors.New("dbus: mismatched signature")
1006+
1007+// Store stores the body of the reply into the provided pointers. It returns
1008+// an error if the signatures of the body and retvalues don't match, or if
1009+// the error status is not nil.
1010+func (c *Call) Store(retvalues ...interface{}) error {
1011+ if c.Err != nil {
1012+ return c.Err
1013+ }
1014+
1015+ return Store(c.Body, retvalues...)
1016+}
1017
1018=== added file 'service-ng/src/github.com/godbus/dbus/conn.go'
1019--- service-ng/src/github.com/godbus/dbus/conn.go 1970-01-01 00:00:00 +0000
1020+++ service-ng/src/github.com/godbus/dbus/conn.go 2015-09-03 16:43:03 +0000
1021@@ -0,0 +1,624 @@
1022+package dbus
1023+
1024+import (
1025+ "errors"
1026+ "io"
1027+ "os"
1028+ "reflect"
1029+ "strings"
1030+ "sync"
1031+)
1032+
1033+const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
1034+
1035+var (
1036+ systemBus *Conn
1037+ systemBusLck sync.Mutex
1038+ sessionBus *Conn
1039+ sessionBusLck sync.Mutex
1040+)
1041+
1042+// ErrClosed is the error returned by calls on a closed connection.
1043+var ErrClosed = errors.New("dbus: connection closed by user")
1044+
1045+// Conn represents a connection to a message bus (usually, the system or
1046+// session bus).
1047+//
1048+// Connections are either shared or private. Shared connections
1049+// are shared between calls to the functions that return them. As a result,
1050+// the methods Close, Auth and Hello must not be called on them.
1051+//
1052+// Multiple goroutines may invoke methods on a connection simultaneously.
1053+type Conn struct {
1054+ transport
1055+
1056+ busObj BusObject
1057+ unixFD bool
1058+ uuid string
1059+
1060+ names []string
1061+ namesLck sync.RWMutex
1062+
1063+ serialLck sync.Mutex
1064+ nextSerial uint32
1065+ serialUsed map[uint32]bool
1066+
1067+ calls map[uint32]*Call
1068+ callsLck sync.RWMutex
1069+
1070+ handlers map[ObjectPath]map[string]exportWithMapping
1071+ handlersLck sync.RWMutex
1072+
1073+ out chan *Message
1074+ closed bool
1075+ outLck sync.RWMutex
1076+
1077+ signals []chan<- *Signal
1078+ signalsLck sync.Mutex
1079+
1080+ eavesdropped chan<- *Message
1081+ eavesdroppedLck sync.Mutex
1082+}
1083+
1084+// SessionBus returns a shared connection to the session bus, connecting to it
1085+// if not already done.
1086+func SessionBus() (conn *Conn, err error) {
1087+ sessionBusLck.Lock()
1088+ defer sessionBusLck.Unlock()
1089+ if sessionBus != nil {
1090+ return sessionBus, nil
1091+ }
1092+ defer func() {
1093+ if conn != nil {
1094+ sessionBus = conn
1095+ }
1096+ }()
1097+ conn, err = SessionBusPrivate()
1098+ if err != nil {
1099+ return
1100+ }
1101+ if err = conn.Auth(nil); err != nil {
1102+ conn.Close()
1103+ conn = nil
1104+ return
1105+ }
1106+ if err = conn.Hello(); err != nil {
1107+ conn.Close()
1108+ conn = nil
1109+ }
1110+ return
1111+}
1112+
1113+// SessionBusPrivate returns a new private connection to the session bus.
1114+func SessionBusPrivate() (*Conn, error) {
1115+ address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
1116+ if address != "" && address != "autolaunch:" {
1117+ return Dial(address)
1118+ }
1119+
1120+ return sessionBusPlatform()
1121+}
1122+
1123+// SystemBus returns a shared connection to the system bus, connecting to it if
1124+// not already done.
1125+func SystemBus() (conn *Conn, err error) {
1126+ systemBusLck.Lock()
1127+ defer systemBusLck.Unlock()
1128+ if systemBus != nil {
1129+ return systemBus, nil
1130+ }
1131+ defer func() {
1132+ if conn != nil {
1133+ systemBus = conn
1134+ }
1135+ }()
1136+ conn, err = SystemBusPrivate()
1137+ if err != nil {
1138+ return
1139+ }
1140+ if err = conn.Auth(nil); err != nil {
1141+ conn.Close()
1142+ conn = nil
1143+ return
1144+ }
1145+ if err = conn.Hello(); err != nil {
1146+ conn.Close()
1147+ conn = nil
1148+ }
1149+ return
1150+}
1151+
1152+// SystemBusPrivate returns a new private connection to the system bus.
1153+func SystemBusPrivate() (*Conn, error) {
1154+ address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
1155+ if address != "" {
1156+ return Dial(address)
1157+ }
1158+ return Dial(defaultSystemBusAddress)
1159+}
1160+
1161+// Dial establishes a new private connection to the message bus specified by address.
1162+func Dial(address string) (*Conn, error) {
1163+ tr, err := getTransport(address)
1164+ if err != nil {
1165+ return nil, err
1166+ }
1167+ return newConn(tr)
1168+}
1169+
1170+// NewConn creates a new private *Conn from an already established connection.
1171+func NewConn(conn io.ReadWriteCloser) (*Conn, error) {
1172+ return newConn(genericTransport{conn})
1173+}
1174+
1175+// newConn creates a new *Conn from a transport.
1176+func newConn(tr transport) (*Conn, error) {
1177+ conn := new(Conn)
1178+ conn.transport = tr
1179+ conn.calls = make(map[uint32]*Call)
1180+ conn.out = make(chan *Message, 10)
1181+ conn.handlers = make(map[ObjectPath]map[string]exportWithMapping)
1182+ conn.nextSerial = 1
1183+ conn.serialUsed = map[uint32]bool{0: true}
1184+ conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
1185+ return conn, nil
1186+}
1187+
1188+// BusObject returns the object owned by the bus daemon which handles
1189+// administrative requests.
1190+func (conn *Conn) BusObject() BusObject {
1191+ return conn.busObj
1192+}
1193+
1194+// Close closes the connection. Any blocked operations will return with errors
1195+// and the channels passed to Eavesdrop and Signal are closed. This method must
1196+// not be called on shared connections.
1197+func (conn *Conn) Close() error {
1198+ conn.outLck.Lock()
1199+ if conn.closed {
1200+ // inWorker calls Close on read error, the read error may
1201+ // be caused by another caller calling Close to shutdown the
1202+ // dbus connection, a double-close scenario we prevent here.
1203+ conn.outLck.Unlock()
1204+ return nil
1205+ }
1206+ close(conn.out)
1207+ conn.closed = true
1208+ conn.outLck.Unlock()
1209+ conn.signalsLck.Lock()
1210+ for _, ch := range conn.signals {
1211+ close(ch)
1212+ }
1213+ conn.signalsLck.Unlock()
1214+ conn.eavesdroppedLck.Lock()
1215+ if conn.eavesdropped != nil {
1216+ close(conn.eavesdropped)
1217+ }
1218+ conn.eavesdroppedLck.Unlock()
1219+ return conn.transport.Close()
1220+}
1221+
1222+// Eavesdrop causes conn to send all incoming messages to the given channel
1223+// without further processing. Method replies, errors and signals will not be
1224+// sent to the appropiate channels and method calls will not be handled. If nil
1225+// is passed, the normal behaviour is restored.
1226+//
1227+// The caller has to make sure that ch is sufficiently buffered;
1228+// if a message arrives when a write to ch is not possible, the message is
1229+// discarded.
1230+func (conn *Conn) Eavesdrop(ch chan<- *Message) {
1231+ conn.eavesdroppedLck.Lock()
1232+ conn.eavesdropped = ch
1233+ conn.eavesdroppedLck.Unlock()
1234+}
1235+
1236+// getSerial returns an unused serial.
1237+func (conn *Conn) getSerial() uint32 {
1238+ conn.serialLck.Lock()
1239+ defer conn.serialLck.Unlock()
1240+ n := conn.nextSerial
1241+ for conn.serialUsed[n] {
1242+ n++
1243+ }
1244+ conn.serialUsed[n] = true
1245+ conn.nextSerial = n + 1
1246+ return n
1247+}
1248+
1249+// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
1250+// called after authentication, but before sending any other messages to the
1251+// bus. Hello must not be called for shared connections.
1252+func (conn *Conn) Hello() error {
1253+ var s string
1254+ err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s)
1255+ if err != nil {
1256+ return err
1257+ }
1258+ conn.namesLck.Lock()
1259+ conn.names = make([]string, 1)
1260+ conn.names[0] = s
1261+ conn.namesLck.Unlock()
1262+ return nil
1263+}
1264+
1265+// inWorker runs in an own goroutine, reading incoming messages from the
1266+// transport and dispatching them appropiately.
1267+func (conn *Conn) inWorker() {
1268+ for {
1269+ msg, err := conn.ReadMessage()
1270+ if err == nil {
1271+ conn.eavesdroppedLck.Lock()
1272+ if conn.eavesdropped != nil {
1273+ select {
1274+ case conn.eavesdropped <- msg:
1275+ default:
1276+ }
1277+ conn.eavesdroppedLck.Unlock()
1278+ continue
1279+ }
1280+ conn.eavesdroppedLck.Unlock()
1281+ dest, _ := msg.Headers[FieldDestination].value.(string)
1282+ found := false
1283+ if dest == "" {
1284+ found = true
1285+ } else {
1286+ conn.namesLck.RLock()
1287+ if len(conn.names) == 0 {
1288+ found = true
1289+ }
1290+ for _, v := range conn.names {
1291+ if dest == v {
1292+ found = true
1293+ break
1294+ }
1295+ }
1296+ conn.namesLck.RUnlock()
1297+ }
1298+ if !found {
1299+ // Eavesdropped a message, but no channel for it is registered.
1300+ // Ignore it.
1301+ continue
1302+ }
1303+ switch msg.Type {
1304+ case TypeMethodReply, TypeError:
1305+ serial := msg.Headers[FieldReplySerial].value.(uint32)
1306+ conn.callsLck.Lock()
1307+ if c, ok := conn.calls[serial]; ok {
1308+ if msg.Type == TypeError {
1309+ name, _ := msg.Headers[FieldErrorName].value.(string)
1310+ c.Err = Error{name, msg.Body}
1311+ } else {
1312+ c.Body = msg.Body
1313+ }
1314+ c.Done <- c
1315+ conn.serialLck.Lock()
1316+ delete(conn.serialUsed, serial)
1317+ conn.serialLck.Unlock()
1318+ delete(conn.calls, serial)
1319+ }
1320+ conn.callsLck.Unlock()
1321+ case TypeSignal:
1322+ iface := msg.Headers[FieldInterface].value.(string)
1323+ member := msg.Headers[FieldMember].value.(string)
1324+ // as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
1325+ // sender is optional for signals.
1326+ sender, _ := msg.Headers[FieldSender].value.(string)
1327+ if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
1328+ if member == "NameLost" {
1329+ // If we lost the name on the bus, remove it from our
1330+ // tracking list.
1331+ name, ok := msg.Body[0].(string)
1332+ if !ok {
1333+ panic("Unable to read the lost name")
1334+ }
1335+ conn.namesLck.Lock()
1336+ for i, v := range conn.names {
1337+ if v == name {
1338+ conn.names = append(conn.names[:i],
1339+ conn.names[i+1:]...)
1340+ }
1341+ }
1342+ conn.namesLck.Unlock()
1343+ } else if member == "NameAcquired" {
1344+ // If we acquired the name on the bus, add it to our
1345+ // tracking list.
1346+ name, ok := msg.Body[0].(string)
1347+ if !ok {
1348+ panic("Unable to read the acquired name")
1349+ }
1350+ conn.namesLck.Lock()
1351+ conn.names = append(conn.names, name)
1352+ conn.namesLck.Unlock()
1353+ }
1354+ }
1355+ signal := &Signal{
1356+ Sender: sender,
1357+ Path: msg.Headers[FieldPath].value.(ObjectPath),
1358+ Name: iface + "." + member,
1359+ Body: msg.Body,
1360+ }
1361+ conn.signalsLck.Lock()
1362+ for _, ch := range conn.signals {
1363+ ch <- signal
1364+ }
1365+ conn.signalsLck.Unlock()
1366+ case TypeMethodCall:
1367+ go conn.handleCall(msg)
1368+ }
1369+ } else if _, ok := err.(InvalidMessageError); !ok {
1370+ // Some read error occured (usually EOF); we can't really do
1371+ // anything but to shut down all stuff and returns errors to all
1372+ // pending replies.
1373+ conn.Close()
1374+ conn.callsLck.RLock()
1375+ for _, v := range conn.calls {
1376+ v.Err = err
1377+ v.Done <- v
1378+ }
1379+ conn.callsLck.RUnlock()
1380+ return
1381+ }
1382+ // invalid messages are ignored
1383+ }
1384+}
1385+
1386+// Names returns the list of all names that are currently owned by this
1387+// connection. The slice is always at least one element long, the first element
1388+// being the unique name of the connection.
1389+func (conn *Conn) Names() []string {
1390+ conn.namesLck.RLock()
1391+ // copy the slice so it can't be modified
1392+ s := make([]string, len(conn.names))
1393+ copy(s, conn.names)
1394+ conn.namesLck.RUnlock()
1395+ return s
1396+}
1397+
1398+// Object returns the object identified by the given destination name and path.
1399+func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
1400+ return &Object{conn, dest, path}
1401+}
1402+
1403+// outWorker runs in an own goroutine, encoding and sending messages that are
1404+// sent to conn.out.
1405+func (conn *Conn) outWorker() {
1406+ for msg := range conn.out {
1407+ err := conn.SendMessage(msg)
1408+ conn.callsLck.RLock()
1409+ if err != nil {
1410+ if c := conn.calls[msg.serial]; c != nil {
1411+ c.Err = err
1412+ c.Done <- c
1413+ }
1414+ conn.serialLck.Lock()
1415+ delete(conn.serialUsed, msg.serial)
1416+ conn.serialLck.Unlock()
1417+ } else if msg.Type != TypeMethodCall {
1418+ conn.serialLck.Lock()
1419+ delete(conn.serialUsed, msg.serial)
1420+ conn.serialLck.Unlock()
1421+ }
1422+ conn.callsLck.RUnlock()
1423+ }
1424+}
1425+
1426+// Send sends the given message to the message bus. You usually don't need to
1427+// use this; use the higher-level equivalents (Call / Go, Emit and Export)
1428+// instead. If msg is a method call and NoReplyExpected is not set, a non-nil
1429+// call is returned and the same value is sent to ch (which must be buffered)
1430+// once the call is complete. Otherwise, ch is ignored and a Call structure is
1431+// returned of which only the Err member is valid.
1432+func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
1433+ var call *Call
1434+
1435+ msg.serial = conn.getSerial()
1436+ if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
1437+ if ch == nil {
1438+ ch = make(chan *Call, 5)
1439+ } else if cap(ch) == 0 {
1440+ panic("dbus: unbuffered channel passed to (*Conn).Send")
1441+ }
1442+ call = new(Call)
1443+ call.Destination, _ = msg.Headers[FieldDestination].value.(string)
1444+ call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
1445+ iface, _ := msg.Headers[FieldInterface].value.(string)
1446+ member, _ := msg.Headers[FieldMember].value.(string)
1447+ call.Method = iface + "." + member
1448+ call.Args = msg.Body
1449+ call.Done = ch
1450+ conn.callsLck.Lock()
1451+ conn.calls[msg.serial] = call
1452+ conn.callsLck.Unlock()
1453+ conn.outLck.RLock()
1454+ if conn.closed {
1455+ call.Err = ErrClosed
1456+ call.Done <- call
1457+ } else {
1458+ conn.out <- msg
1459+ }
1460+ conn.outLck.RUnlock()
1461+ } else {
1462+ conn.outLck.RLock()
1463+ if conn.closed {
1464+ call = &Call{Err: ErrClosed}
1465+ } else {
1466+ conn.out <- msg
1467+ call = &Call{Err: nil}
1468+ }
1469+ conn.outLck.RUnlock()
1470+ }
1471+ return call
1472+}
1473+
1474+// sendError creates an error message corresponding to the parameters and sends
1475+// it to conn.out.
1476+func (conn *Conn) sendError(e Error, dest string, serial uint32) {
1477+ msg := new(Message)
1478+ msg.Type = TypeError
1479+ msg.serial = conn.getSerial()
1480+ msg.Headers = make(map[HeaderField]Variant)
1481+ if dest != "" {
1482+ msg.Headers[FieldDestination] = MakeVariant(dest)
1483+ }
1484+ msg.Headers[FieldErrorName] = MakeVariant(e.Name)
1485+ msg.Headers[FieldReplySerial] = MakeVariant(serial)
1486+ msg.Body = e.Body
1487+ if len(e.Body) > 0 {
1488+ msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
1489+ }
1490+ conn.outLck.RLock()
1491+ if !conn.closed {
1492+ conn.out <- msg
1493+ }
1494+ conn.outLck.RUnlock()
1495+}
1496+
1497+// sendReply creates a method reply message corresponding to the parameters and
1498+// sends it to conn.out.
1499+func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
1500+ msg := new(Message)
1501+ msg.Type = TypeMethodReply
1502+ msg.serial = conn.getSerial()
1503+ msg.Headers = make(map[HeaderField]Variant)
1504+ if dest != "" {
1505+ msg.Headers[FieldDestination] = MakeVariant(dest)
1506+ }
1507+ msg.Headers[FieldReplySerial] = MakeVariant(serial)
1508+ msg.Body = values
1509+ if len(values) > 0 {
1510+ msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
1511+ }
1512+ conn.outLck.RLock()
1513+ if !conn.closed {
1514+ conn.out <- msg
1515+ }
1516+ conn.outLck.RUnlock()
1517+}
1518+
1519+// Signal registers the given channel to be passed all received signal messages.
1520+// The caller has to make sure that ch is sufficiently buffered; if a message
1521+// arrives when a write to c is not possible, it is discarded.
1522+//
1523+// Multiple of these channels can be registered at the same time. Passing a
1524+// channel that already is registered will remove it from the list of the
1525+// registered channels.
1526+//
1527+// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
1528+// channel for eavesdropped messages, this channel receives all signals, and
1529+// none of the channels passed to Signal will receive any signals.
1530+func (conn *Conn) Signal(ch chan<- *Signal) {
1531+ conn.signalsLck.Lock()
1532+ conn.signals = append(conn.signals, ch)
1533+ conn.signalsLck.Unlock()
1534+}
1535+
1536+// SupportsUnixFDs returns whether the underlying transport supports passing of
1537+// unix file descriptors. If this is false, method calls containing unix file
1538+// descriptors will return an error and emitted signals containing them will
1539+// not be sent.
1540+func (conn *Conn) SupportsUnixFDs() bool {
1541+ return conn.unixFD
1542+}
1543+
1544+// Error represents a D-Bus message of type Error.
1545+type Error struct {
1546+ Name string
1547+ Body []interface{}
1548+}
1549+
1550+func NewError(name string, body []interface{}) *Error {
1551+ return &Error{name, body}
1552+}
1553+
1554+func (e Error) Error() string {
1555+ if len(e.Body) >= 1 {
1556+ s, ok := e.Body[0].(string)
1557+ if ok {
1558+ return s
1559+ }
1560+ }
1561+ return e.Name
1562+}
1563+
1564+// Signal represents a D-Bus message of type Signal. The name member is given in
1565+// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
1566+type Signal struct {
1567+ Sender string
1568+ Path ObjectPath
1569+ Name string
1570+ Body []interface{}
1571+}
1572+
1573+// transport is a D-Bus transport.
1574+type transport interface {
1575+ // Read and Write raw data (for example, for the authentication protocol).
1576+ io.ReadWriteCloser
1577+
1578+ // Send the initial null byte used for the EXTERNAL mechanism.
1579+ SendNullByte() error
1580+
1581+ // Returns whether this transport supports passing Unix FDs.
1582+ SupportsUnixFDs() bool
1583+
1584+ // Signal the transport that Unix FD passing is enabled for this connection.
1585+ EnableUnixFDs()
1586+
1587+ // Read / send a message, handling things like Unix FDs.
1588+ ReadMessage() (*Message, error)
1589+ SendMessage(*Message) error
1590+}
1591+
1592+var (
1593+ transports map[string]func(string) (transport, error) = make(map[string]func(string) (transport, error))
1594+)
1595+
1596+func getTransport(address string) (transport, error) {
1597+ var err error
1598+ var t transport
1599+
1600+ addresses := strings.Split(address, ";")
1601+ for _, v := range addresses {
1602+ i := strings.IndexRune(v, ':')
1603+ if i == -1 {
1604+ err = errors.New("dbus: invalid bus address (no transport)")
1605+ continue
1606+ }
1607+ f := transports[v[:i]]
1608+ if f == nil {
1609+ err = errors.New("dbus: invalid bus address (invalid or unsupported transport)")
1610+ }
1611+ t, err = f(v[i+1:])
1612+ if err == nil {
1613+ return t, nil
1614+ }
1615+ }
1616+ return nil, err
1617+}
1618+
1619+// dereferenceAll returns a slice that, assuming that vs is a slice of pointers
1620+// of arbitrary types, containes the values that are obtained from dereferencing
1621+// all elements in vs.
1622+func dereferenceAll(vs []interface{}) []interface{} {
1623+ for i := range vs {
1624+ v := reflect.ValueOf(vs[i])
1625+ v = v.Elem()
1626+ vs[i] = v.Interface()
1627+ }
1628+ return vs
1629+}
1630+
1631+// getKey gets a key from a the list of keys. Returns "" on error / not found...
1632+func getKey(s, key string) string {
1633+ i := strings.Index(s, key)
1634+ if i == -1 {
1635+ return ""
1636+ }
1637+ if i+len(key)+1 >= len(s) || s[i+len(key)] != '=' {
1638+ return ""
1639+ }
1640+ j := strings.Index(s, ",")
1641+ if j == -1 {
1642+ j = len(s)
1643+ }
1644+ return s[i+len(key)+1 : j]
1645+}
1646
1647=== added file 'service-ng/src/github.com/godbus/dbus/conn_darwin.go'
1648--- service-ng/src/github.com/godbus/dbus/conn_darwin.go 1970-01-01 00:00:00 +0000
1649+++ service-ng/src/github.com/godbus/dbus/conn_darwin.go 2015-09-03 16:43:03 +0000
1650@@ -0,0 +1,21 @@
1651+package dbus
1652+
1653+import (
1654+ "errors"
1655+ "os/exec"
1656+)
1657+
1658+func sessionBusPlatform() (*Conn, error) {
1659+ cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET")
1660+ b, err := cmd.CombinedOutput()
1661+
1662+ if err != nil {
1663+ return nil, err
1664+ }
1665+
1666+ if len(b) == 0 {
1667+ return nil, errors.New("dbus: couldn't determine address of session bus")
1668+ }
1669+
1670+ return Dial("unix:path=" + string(b[:len(b)-1]))
1671+}
1672
1673=== added file 'service-ng/src/github.com/godbus/dbus/conn_other.go'
1674--- service-ng/src/github.com/godbus/dbus/conn_other.go 1970-01-01 00:00:00 +0000
1675+++ service-ng/src/github.com/godbus/dbus/conn_other.go 2015-09-03 16:43:03 +0000
1676@@ -0,0 +1,27 @@
1677+// +build !darwin
1678+
1679+package dbus
1680+
1681+import (
1682+ "bytes"
1683+ "errors"
1684+ "os/exec"
1685+)
1686+
1687+func sessionBusPlatform() (*Conn, error) {
1688+ cmd := exec.Command("dbus-launch")
1689+ b, err := cmd.CombinedOutput()
1690+
1691+ if err != nil {
1692+ return nil, err
1693+ }
1694+
1695+ i := bytes.IndexByte(b, '=')
1696+ j := bytes.IndexByte(b, '\n')
1697+
1698+ if i == -1 || j == -1 {
1699+ return nil, errors.New("dbus: couldn't determine address of session bus")
1700+ }
1701+
1702+ return Dial(string(b[i+1 : j]))
1703+}
1704
1705=== added file 'service-ng/src/github.com/godbus/dbus/conn_test.go'
1706--- service-ng/src/github.com/godbus/dbus/conn_test.go 1970-01-01 00:00:00 +0000
1707+++ service-ng/src/github.com/godbus/dbus/conn_test.go 2015-09-03 16:43:03 +0000
1708@@ -0,0 +1,199 @@
1709+package dbus
1710+
1711+import "testing"
1712+
1713+func TestSessionBus(t *testing.T) {
1714+ _, err := SessionBus()
1715+ if err != nil {
1716+ t.Error(err)
1717+ }
1718+}
1719+
1720+func TestSystemBus(t *testing.T) {
1721+ _, err := SystemBus()
1722+ if err != nil {
1723+ t.Error(err)
1724+ }
1725+}
1726+
1727+func TestSend(t *testing.T) {
1728+ bus, err := SessionBus()
1729+ if err != nil {
1730+ t.Error(err)
1731+ }
1732+ ch := make(chan *Call, 1)
1733+ msg := &Message{
1734+ Type: TypeMethodCall,
1735+ Flags: 0,
1736+ Headers: map[HeaderField]Variant{
1737+ FieldDestination: MakeVariant(bus.Names()[0]),
1738+ FieldPath: MakeVariant(ObjectPath("/org/freedesktop/DBus")),
1739+ FieldInterface: MakeVariant("org.freedesktop.DBus.Peer"),
1740+ FieldMember: MakeVariant("Ping"),
1741+ },
1742+ }
1743+ call := bus.Send(msg, ch)
1744+ <-ch
1745+ if call.Err != nil {
1746+ t.Error(call.Err)
1747+ }
1748+}
1749+
1750+type server struct{}
1751+
1752+func (server) Double(i int64) (int64, *Error) {
1753+ return 2 * i, nil
1754+}
1755+
1756+func BenchmarkCall(b *testing.B) {
1757+ b.StopTimer()
1758+ var s string
1759+ bus, err := SessionBus()
1760+ if err != nil {
1761+ b.Fatal(err)
1762+ }
1763+ name := bus.Names()[0]
1764+ obj := bus.BusObject()
1765+ b.StartTimer()
1766+ for i := 0; i < b.N; i++ {
1767+ err := obj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&s)
1768+ if err != nil {
1769+ b.Fatal(err)
1770+ }
1771+ if s != name {
1772+ b.Errorf("got %s, wanted %s", s, name)
1773+ }
1774+ }
1775+}
1776+
1777+func BenchmarkCallAsync(b *testing.B) {
1778+ b.StopTimer()
1779+ bus, err := SessionBus()
1780+ if err != nil {
1781+ b.Fatal(err)
1782+ }
1783+ name := bus.Names()[0]
1784+ obj := bus.BusObject()
1785+ c := make(chan *Call, 50)
1786+ done := make(chan struct{})
1787+ go func() {
1788+ for i := 0; i < b.N; i++ {
1789+ v := <-c
1790+ if v.Err != nil {
1791+ b.Error(v.Err)
1792+ }
1793+ s := v.Body[0].(string)
1794+ if s != name {
1795+ b.Errorf("got %s, wanted %s", s, name)
1796+ }
1797+ }
1798+ close(done)
1799+ }()
1800+ b.StartTimer()
1801+ for i := 0; i < b.N; i++ {
1802+ obj.Go("org.freedesktop.DBus.GetNameOwner", 0, c, name)
1803+ }
1804+ <-done
1805+}
1806+
1807+func BenchmarkServe(b *testing.B) {
1808+ b.StopTimer()
1809+ srv, err := SessionBus()
1810+ if err != nil {
1811+ b.Fatal(err)
1812+ }
1813+ cli, err := SessionBusPrivate()
1814+ if err != nil {
1815+ b.Fatal(err)
1816+ }
1817+ if err = cli.Auth(nil); err != nil {
1818+ b.Fatal(err)
1819+ }
1820+ if err = cli.Hello(); err != nil {
1821+ b.Fatal(err)
1822+ }
1823+ benchmarkServe(b, srv, cli)
1824+}
1825+
1826+func BenchmarkServeAsync(b *testing.B) {
1827+ b.StopTimer()
1828+ srv, err := SessionBus()
1829+ if err != nil {
1830+ b.Fatal(err)
1831+ }
1832+ cli, err := SessionBusPrivate()
1833+ if err != nil {
1834+ b.Fatal(err)
1835+ }
1836+ if err = cli.Auth(nil); err != nil {
1837+ b.Fatal(err)
1838+ }
1839+ if err = cli.Hello(); err != nil {
1840+ b.Fatal(err)
1841+ }
1842+ benchmarkServeAsync(b, srv, cli)
1843+}
1844+
1845+func BenchmarkServeSameConn(b *testing.B) {
1846+ b.StopTimer()
1847+ bus, err := SessionBus()
1848+ if err != nil {
1849+ b.Fatal(err)
1850+ }
1851+
1852+ benchmarkServe(b, bus, bus)
1853+}
1854+
1855+func BenchmarkServeSameConnAsync(b *testing.B) {
1856+ b.StopTimer()
1857+ bus, err := SessionBus()
1858+ if err != nil {
1859+ b.Fatal(err)
1860+ }
1861+
1862+ benchmarkServeAsync(b, bus, bus)
1863+}
1864+
1865+func benchmarkServe(b *testing.B, srv, cli *Conn) {
1866+ var r int64
1867+ var err error
1868+ dest := srv.Names()[0]
1869+ srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
1870+ obj := cli.Object(dest, "/org/guelfey/DBus/Test")
1871+ b.StartTimer()
1872+ for i := 0; i < b.N; i++ {
1873+ err = obj.Call("org.guelfey.DBus.Test.Double", 0, int64(i)).Store(&r)
1874+ if err != nil {
1875+ b.Fatal(err)
1876+ }
1877+ if r != 2*int64(i) {
1878+ b.Errorf("got %d, wanted %d", r, 2*int64(i))
1879+ }
1880+ }
1881+}
1882+
1883+func benchmarkServeAsync(b *testing.B, srv, cli *Conn) {
1884+ dest := srv.Names()[0]
1885+ srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
1886+ obj := cli.Object(dest, "/org/guelfey/DBus/Test")
1887+ c := make(chan *Call, 50)
1888+ done := make(chan struct{})
1889+ go func() {
1890+ for i := 0; i < b.N; i++ {
1891+ v := <-c
1892+ if v.Err != nil {
1893+ b.Fatal(v.Err)
1894+ }
1895+ i, r := v.Args[0].(int64), v.Body[0].(int64)
1896+ if 2*i != r {
1897+ b.Errorf("got %d, wanted %d", r, 2*i)
1898+ }
1899+ }
1900+ close(done)
1901+ }()
1902+ b.StartTimer()
1903+ for i := 0; i < b.N; i++ {
1904+ obj.Go("org.guelfey.DBus.Test.Double", 0, c, int64(i))
1905+ }
1906+ <-done
1907+}
1908
1909=== added file 'service-ng/src/github.com/godbus/dbus/dbus.go'
1910--- service-ng/src/github.com/godbus/dbus/dbus.go 1970-01-01 00:00:00 +0000
1911+++ service-ng/src/github.com/godbus/dbus/dbus.go 2015-09-03 16:43:03 +0000
1912@@ -0,0 +1,258 @@
1913+package dbus
1914+
1915+import (
1916+ "errors"
1917+ "reflect"
1918+ "strings"
1919+)
1920+
1921+var (
1922+ byteType = reflect.TypeOf(byte(0))
1923+ boolType = reflect.TypeOf(false)
1924+ uint8Type = reflect.TypeOf(uint8(0))
1925+ int16Type = reflect.TypeOf(int16(0))
1926+ uint16Type = reflect.TypeOf(uint16(0))
1927+ int32Type = reflect.TypeOf(int32(0))
1928+ uint32Type = reflect.TypeOf(uint32(0))
1929+ int64Type = reflect.TypeOf(int64(0))
1930+ uint64Type = reflect.TypeOf(uint64(0))
1931+ float64Type = reflect.TypeOf(float64(0))
1932+ stringType = reflect.TypeOf("")
1933+ signatureType = reflect.TypeOf(Signature{""})
1934+ objectPathType = reflect.TypeOf(ObjectPath(""))
1935+ variantType = reflect.TypeOf(Variant{Signature{""}, nil})
1936+ interfacesType = reflect.TypeOf([]interface{}{})
1937+ unixFDType = reflect.TypeOf(UnixFD(0))
1938+ unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
1939+)
1940+
1941+// An InvalidTypeError signals that a value which cannot be represented in the
1942+// D-Bus wire format was passed to a function.
1943+type InvalidTypeError struct {
1944+ Type reflect.Type
1945+}
1946+
1947+func (e InvalidTypeError) Error() string {
1948+ return "dbus: invalid type " + e.Type.String()
1949+}
1950+
1951+// Store copies the values contained in src to dest, which must be a slice of
1952+// pointers. It converts slices of interfaces from src to corresponding structs
1953+// in dest. An error is returned if the lengths of src and dest or the types of
1954+// their elements don't match.
1955+func Store(src []interface{}, dest ...interface{}) error {
1956+ if len(src) != len(dest) {
1957+ return errors.New("dbus.Store: length mismatch")
1958+ }
1959+
1960+ for i := range src {
1961+ if err := store(src[i], dest[i]); err != nil {
1962+ return err
1963+ }
1964+ }
1965+ return nil
1966+}
1967+
1968+func store(src, dest interface{}) error {
1969+ if reflect.TypeOf(dest).Elem() == reflect.TypeOf(src) {
1970+ reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src))
1971+ return nil
1972+ } else if hasStruct(dest) {
1973+ rv := reflect.ValueOf(dest).Elem()
1974+ switch rv.Kind() {
1975+ case reflect.Struct:
1976+ vs, ok := src.([]interface{})
1977+ if !ok {
1978+ return errors.New("dbus.Store: type mismatch")
1979+ }
1980+ t := rv.Type()
1981+ ndest := make([]interface{}, 0, rv.NumField())
1982+ for i := 0; i < rv.NumField(); i++ {
1983+ field := t.Field(i)
1984+ if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
1985+ ndest = append(ndest, rv.Field(i).Addr().Interface())
1986+ }
1987+ }
1988+ if len(vs) != len(ndest) {
1989+ return errors.New("dbus.Store: type mismatch")
1990+ }
1991+ err := Store(vs, ndest...)
1992+ if err != nil {
1993+ return errors.New("dbus.Store: type mismatch")
1994+ }
1995+ case reflect.Slice:
1996+ sv := reflect.ValueOf(src)
1997+ if sv.Kind() != reflect.Slice {
1998+ return errors.New("dbus.Store: type mismatch")
1999+ }
2000+ rv.Set(reflect.MakeSlice(rv.Type(), sv.Len(), sv.Len()))
2001+ for i := 0; i < sv.Len(); i++ {
2002+ if err := store(sv.Index(i).Interface(), rv.Index(i).Addr().Interface()); err != nil {
2003+ return err
2004+ }
2005+ }
2006+ case reflect.Map:
2007+ sv := reflect.ValueOf(src)
2008+ if sv.Kind() != reflect.Map {
2009+ return errors.New("dbus.Store: type mismatch")
2010+ }
2011+ keys := sv.MapKeys()
2012+ rv.Set(reflect.MakeMap(sv.Type()))
2013+ for _, key := range keys {
2014+ v := reflect.New(sv.Type().Elem())
2015+ if err := store(v, sv.MapIndex(key).Interface()); err != nil {
2016+ return err
2017+ }
2018+ rv.SetMapIndex(key, v.Elem())
2019+ }
2020+ default:
2021+ return errors.New("dbus.Store: type mismatch")
2022+ }
2023+ return nil
2024+ } else {
2025+ return errors.New("dbus.Store: type mismatch")
2026+ }
2027+}
2028+
2029+func hasStruct(v interface{}) bool {
2030+ t := reflect.TypeOf(v)
2031+ for {
2032+ switch t.Kind() {
2033+ case reflect.Struct:
2034+ return true
2035+ case reflect.Slice, reflect.Ptr, reflect.Map:
2036+ t = t.Elem()
2037+ default:
2038+ return false
2039+ }
2040+ }
2041+}
2042+
2043+// An ObjectPath is an object path as defined by the D-Bus spec.
2044+type ObjectPath string
2045+
2046+// IsValid returns whether the object path is valid.
2047+func (o ObjectPath) IsValid() bool {
2048+ s := string(o)
2049+ if len(s) == 0 {
2050+ return false
2051+ }
2052+ if s[0] != '/' {
2053+ return false
2054+ }
2055+ if s[len(s)-1] == '/' && len(s) != 1 {
2056+ return false
2057+ }
2058+ // probably not used, but technically possible
2059+ if s == "/" {
2060+ return true
2061+ }
2062+ split := strings.Split(s[1:], "/")
2063+ for _, v := range split {
2064+ if len(v) == 0 {
2065+ return false
2066+ }
2067+ for _, c := range v {
2068+ if !isMemberChar(c) {
2069+ return false
2070+ }
2071+ }
2072+ }
2073+ return true
2074+}
2075+
2076+// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
2077+// documentation for more information about Unix file descriptor passsing.
2078+type UnixFD int32
2079+
2080+// A UnixFDIndex is the representation of a Unix file descriptor in a message.
2081+type UnixFDIndex uint32
2082+
2083+// alignment returns the alignment of values of type t.
2084+func alignment(t reflect.Type) int {
2085+ switch t {
2086+ case variantType:
2087+ return 1
2088+ case objectPathType:
2089+ return 4
2090+ case signatureType:
2091+ return 1
2092+ case interfacesType: // sometimes used for structs
2093+ return 8
2094+ }
2095+ switch t.Kind() {
2096+ case reflect.Uint8:
2097+ return 1
2098+ case reflect.Uint16, reflect.Int16:
2099+ return 2
2100+ case reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
2101+ return 4
2102+ case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
2103+ return 8
2104+ case reflect.Ptr:
2105+ return alignment(t.Elem())
2106+ }
2107+ return 1
2108+}
2109+
2110+// isKeyType returns whether t is a valid type for a D-Bus dict.
2111+func isKeyType(t reflect.Type) bool {
2112+ switch t.Kind() {
2113+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
2114+ reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
2115+ reflect.String:
2116+
2117+ return true
2118+ }
2119+ return false
2120+}
2121+
2122+// isValidInterface returns whether s is a valid name for an interface.
2123+func isValidInterface(s string) bool {
2124+ if len(s) == 0 || len(s) > 255 || s[0] == '.' {
2125+ return false
2126+ }
2127+ elem := strings.Split(s, ".")
2128+ if len(elem) < 2 {
2129+ return false
2130+ }
2131+ for _, v := range elem {
2132+ if len(v) == 0 {
2133+ return false
2134+ }
2135+ if v[0] >= '0' && v[0] <= '9' {
2136+ return false
2137+ }
2138+ for _, c := range v {
2139+ if !isMemberChar(c) {
2140+ return false
2141+ }
2142+ }
2143+ }
2144+ return true
2145+}
2146+
2147+// isValidMember returns whether s is a valid name for a member.
2148+func isValidMember(s string) bool {
2149+ if len(s) == 0 || len(s) > 255 {
2150+ return false
2151+ }
2152+ i := strings.Index(s, ".")
2153+ if i != -1 {
2154+ return false
2155+ }
2156+ if s[0] >= '0' && s[0] <= '9' {
2157+ return false
2158+ }
2159+ for _, c := range s {
2160+ if !isMemberChar(c) {
2161+ return false
2162+ }
2163+ }
2164+ return true
2165+}
2166+
2167+func isMemberChar(c rune) bool {
2168+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
2169+ (c >= 'a' && c <= 'z') || c == '_'
2170+}
2171
2172=== added file 'service-ng/src/github.com/godbus/dbus/decoder.go'
2173--- service-ng/src/github.com/godbus/dbus/decoder.go 1970-01-01 00:00:00 +0000
2174+++ service-ng/src/github.com/godbus/dbus/decoder.go 2015-09-03 16:43:03 +0000
2175@@ -0,0 +1,228 @@
2176+package dbus
2177+
2178+import (
2179+ "encoding/binary"
2180+ "io"
2181+ "reflect"
2182+)
2183+
2184+type decoder struct {
2185+ in io.Reader
2186+ order binary.ByteOrder
2187+ pos int
2188+}
2189+
2190+// newDecoder returns a new decoder that reads values from in. The input is
2191+// expected to be in the given byte order.
2192+func newDecoder(in io.Reader, order binary.ByteOrder) *decoder {
2193+ dec := new(decoder)
2194+ dec.in = in
2195+ dec.order = order
2196+ return dec
2197+}
2198+
2199+// align aligns the input to the given boundary and panics on error.
2200+func (dec *decoder) align(n int) {
2201+ if dec.pos%n != 0 {
2202+ newpos := (dec.pos + n - 1) & ^(n - 1)
2203+ empty := make([]byte, newpos-dec.pos)
2204+ if _, err := io.ReadFull(dec.in, empty); err != nil {
2205+ panic(err)
2206+ }
2207+ dec.pos = newpos
2208+ }
2209+}
2210+
2211+// Calls binary.Read(dec.in, dec.order, v) and panics on read errors.
2212+func (dec *decoder) binread(v interface{}) {
2213+ if err := binary.Read(dec.in, dec.order, v); err != nil {
2214+ panic(err)
2215+ }
2216+}
2217+
2218+func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
2219+ defer func() {
2220+ var ok bool
2221+ v := recover()
2222+ if err, ok = v.(error); ok {
2223+ if err == io.EOF || err == io.ErrUnexpectedEOF {
2224+ err = FormatError("unexpected EOF")
2225+ }
2226+ }
2227+ }()
2228+ vs = make([]interface{}, 0)
2229+ s := sig.str
2230+ for s != "" {
2231+ err, rem := validSingle(s, 0)
2232+ if err != nil {
2233+ return nil, err
2234+ }
2235+ v := dec.decode(s[:len(s)-len(rem)], 0)
2236+ vs = append(vs, v)
2237+ s = rem
2238+ }
2239+ return vs, nil
2240+}
2241+
2242+func (dec *decoder) decode(s string, depth int) interface{} {
2243+ dec.align(alignment(typeFor(s)))
2244+ switch s[0] {
2245+ case 'y':
2246+ var b [1]byte
2247+ if _, err := dec.in.Read(b[:]); err != nil {
2248+ panic(err)
2249+ }
2250+ dec.pos++
2251+ return b[0]
2252+ case 'b':
2253+ i := dec.decode("u", depth).(uint32)
2254+ switch {
2255+ case i == 0:
2256+ return false
2257+ case i == 1:
2258+ return true
2259+ default:
2260+ panic(FormatError("invalid value for boolean"))
2261+ }
2262+ case 'n':
2263+ var i int16
2264+ dec.binread(&i)
2265+ dec.pos += 2
2266+ return i
2267+ case 'i':
2268+ var i int32
2269+ dec.binread(&i)
2270+ dec.pos += 4
2271+ return i
2272+ case 'x':
2273+ var i int64
2274+ dec.binread(&i)
2275+ dec.pos += 8
2276+ return i
2277+ case 'q':
2278+ var i uint16
2279+ dec.binread(&i)
2280+ dec.pos += 2
2281+ return i
2282+ case 'u':
2283+ var i uint32
2284+ dec.binread(&i)
2285+ dec.pos += 4
2286+ return i
2287+ case 't':
2288+ var i uint64
2289+ dec.binread(&i)
2290+ dec.pos += 8
2291+ return i
2292+ case 'd':
2293+ var f float64
2294+ dec.binread(&f)
2295+ dec.pos += 8
2296+ return f
2297+ case 's':
2298+ length := dec.decode("u", depth).(uint32)
2299+ b := make([]byte, int(length)+1)
2300+ if _, err := io.ReadFull(dec.in, b); err != nil {
2301+ panic(err)
2302+ }
2303+ dec.pos += int(length) + 1
2304+ return string(b[:len(b)-1])
2305+ case 'o':
2306+ return ObjectPath(dec.decode("s", depth).(string))
2307+ case 'g':
2308+ length := dec.decode("y", depth).(byte)
2309+ b := make([]byte, int(length)+1)
2310+ if _, err := io.ReadFull(dec.in, b); err != nil {
2311+ panic(err)
2312+ }
2313+ dec.pos += int(length) + 1
2314+ sig, err := ParseSignature(string(b[:len(b)-1]))
2315+ if err != nil {
2316+ panic(err)
2317+ }
2318+ return sig
2319+ case 'v':
2320+ if depth >= 64 {
2321+ panic(FormatError("input exceeds container depth limit"))
2322+ }
2323+ var variant Variant
2324+ sig := dec.decode("g", depth).(Signature)
2325+ if len(sig.str) == 0 {
2326+ panic(FormatError("variant signature is empty"))
2327+ }
2328+ err, rem := validSingle(sig.str, 0)
2329+ if err != nil {
2330+ panic(err)
2331+ }
2332+ if rem != "" {
2333+ panic(FormatError("variant signature has multiple types"))
2334+ }
2335+ variant.sig = sig
2336+ variant.value = dec.decode(sig.str, depth+1)
2337+ return variant
2338+ case 'h':
2339+ return UnixFDIndex(dec.decode("u", depth).(uint32))
2340+ case 'a':
2341+ if len(s) > 1 && s[1] == '{' {
2342+ ksig := s[2:3]
2343+ vsig := s[3 : len(s)-1]
2344+ v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig)))
2345+ if depth >= 63 {
2346+ panic(FormatError("input exceeds container depth limit"))
2347+ }
2348+ length := dec.decode("u", depth).(uint32)
2349+ // Even for empty maps, the correct padding must be included
2350+ dec.align(8)
2351+ spos := dec.pos
2352+ for dec.pos < spos+int(length) {
2353+ dec.align(8)
2354+ if !isKeyType(v.Type().Key()) {
2355+ panic(InvalidTypeError{v.Type()})
2356+ }
2357+ kv := dec.decode(ksig, depth+2)
2358+ vv := dec.decode(vsig, depth+2)
2359+ v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv))
2360+ }
2361+ return v.Interface()
2362+ }
2363+ if depth >= 64 {
2364+ panic(FormatError("input exceeds container depth limit"))
2365+ }
2366+ length := dec.decode("u", depth).(uint32)
2367+ v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
2368+ // Even for empty arrays, the correct padding must be included
2369+ dec.align(alignment(typeFor(s[1:])))
2370+ spos := dec.pos
2371+ for dec.pos < spos+int(length) {
2372+ ev := dec.decode(s[1:], depth+1)
2373+ v = reflect.Append(v, reflect.ValueOf(ev))
2374+ }
2375+ return v.Interface()
2376+ case '(':
2377+ if depth >= 64 {
2378+ panic(FormatError("input exceeds container depth limit"))
2379+ }
2380+ dec.align(8)
2381+ v := make([]interface{}, 0)
2382+ s = s[1 : len(s)-1]
2383+ for s != "" {
2384+ err, rem := validSingle(s, 0)
2385+ if err != nil {
2386+ panic(err)
2387+ }
2388+ ev := dec.decode(s[:len(s)-len(rem)], depth+1)
2389+ v = append(v, ev)
2390+ s = rem
2391+ }
2392+ return v
2393+ default:
2394+ panic(SignatureError{Sig: s})
2395+ }
2396+}
2397+
2398+// A FormatError is an error in the wire format.
2399+type FormatError string
2400+
2401+func (e FormatError) Error() string {
2402+ return "dbus: wire format error: " + string(e)
2403+}
2404
2405=== added file 'service-ng/src/github.com/godbus/dbus/doc.go'
2406--- service-ng/src/github.com/godbus/dbus/doc.go 1970-01-01 00:00:00 +0000
2407+++ service-ng/src/github.com/godbus/dbus/doc.go 2015-09-03 16:43:03 +0000
2408@@ -0,0 +1,63 @@
2409+/*
2410+Package dbus implements bindings to the D-Bus message bus system.
2411+
2412+To use the message bus API, you first need to connect to a bus (usually the
2413+session or system bus). The acquired connection then can be used to call methods
2414+on remote objects and emit or receive signals. Using the Export method, you can
2415+arrange D-Bus methods calls to be directly translated to method calls on a Go
2416+value.
2417+
2418+Conversion Rules
2419+
2420+For outgoing messages, Go types are automatically converted to the
2421+corresponding D-Bus types. The following types are directly encoded as their
2422+respective D-Bus equivalents:
2423+
2424+ Go type | D-Bus type
2425+ ------------+-----------
2426+ byte | BYTE
2427+ bool | BOOLEAN
2428+ int16 | INT16
2429+ uint16 | UINT16
2430+ int32 | INT32
2431+ uint32 | UINT32
2432+ int64 | INT64
2433+ uint64 | UINT64
2434+ float64 | DOUBLE
2435+ string | STRING
2436+ ObjectPath | OBJECT_PATH
2437+ Signature | SIGNATURE
2438+ Variant | VARIANT
2439+ UnixFDIndex | UNIX_FD
2440+
2441+Slices and arrays encode as ARRAYs of their element type.
2442+
2443+Maps encode as DICTs, provided that their key type can be used as a key for
2444+a DICT.
2445+
2446+Structs other than Variant and Signature encode as a STRUCT containing their
2447+exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will
2448+be skipped.
2449+
2450+Pointers encode as the value they're pointed to.
2451+
2452+Trying to encode any other type or a slice, map or struct containing an
2453+unsupported type will result in an InvalidTypeError.
2454+
2455+For incoming messages, the inverse of these rules are used, with the exception
2456+of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces
2457+containing the struct fields in the correct order. The Store function can be
2458+used to convert such values to Go structs.
2459+
2460+Unix FD passing
2461+
2462+Handling Unix file descriptors deserves special mention. To use them, you should
2463+first check that they are supported on a connection by calling SupportsUnixFDs.
2464+If it returns true, all method of Connection will translate messages containing
2465+UnixFD's to messages that are accompanied by the given file descriptors with the
2466+UnixFD values being substituted by the correct indices. Similarily, the indices
2467+of incoming messages are automatically resolved. It shouldn't be necessary to use
2468+UnixFDIndex.
2469+
2470+*/
2471+package dbus
2472
2473=== added file 'service-ng/src/github.com/godbus/dbus/encoder.go'
2474--- service-ng/src/github.com/godbus/dbus/encoder.go 1970-01-01 00:00:00 +0000
2475+++ service-ng/src/github.com/godbus/dbus/encoder.go 2015-09-03 16:43:03 +0000
2476@@ -0,0 +1,208 @@
2477+package dbus
2478+
2479+import (
2480+ "bytes"
2481+ "encoding/binary"
2482+ "io"
2483+ "reflect"
2484+)
2485+
2486+// An encoder encodes values to the D-Bus wire format.
2487+type encoder struct {
2488+ out io.Writer
2489+ order binary.ByteOrder
2490+ pos int
2491+}
2492+
2493+// NewEncoder returns a new encoder that writes to out in the given byte order.
2494+func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
2495+ return newEncoderAtOffset(out, 0, order)
2496+}
2497+
2498+// newEncoderAtOffset returns a new encoder that writes to out in the given
2499+// byte order. Specify the offset to initialize pos for proper alignment
2500+// computation.
2501+func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder {
2502+ enc := new(encoder)
2503+ enc.out = out
2504+ enc.order = order
2505+ enc.pos = offset
2506+ return enc
2507+}
2508+
2509+// Aligns the next output to be on a multiple of n. Panics on write errors.
2510+func (enc *encoder) align(n int) {
2511+ pad := enc.padding(0, n)
2512+ if pad > 0 {
2513+ empty := make([]byte, pad)
2514+ if _, err := enc.out.Write(empty); err != nil {
2515+ panic(err)
2516+ }
2517+ enc.pos += pad
2518+ }
2519+}
2520+
2521+// pad returns the number of bytes of padding, based on current position and additional offset.
2522+// and alignment.
2523+func (enc *encoder) padding(offset, algn int) int {
2524+ abs := enc.pos + offset
2525+ if abs%algn != 0 {
2526+ newabs := (abs + algn - 1) & ^(algn - 1)
2527+ return newabs - abs
2528+ }
2529+ return 0
2530+}
2531+
2532+// Calls binary.Write(enc.out, enc.order, v) and panics on write errors.
2533+func (enc *encoder) binwrite(v interface{}) {
2534+ if err := binary.Write(enc.out, enc.order, v); err != nil {
2535+ panic(err)
2536+ }
2537+}
2538+
2539+// Encode encodes the given values to the underyling reader. All written values
2540+// are aligned properly as required by the D-Bus spec.
2541+func (enc *encoder) Encode(vs ...interface{}) (err error) {
2542+ defer func() {
2543+ err, _ = recover().(error)
2544+ }()
2545+ for _, v := range vs {
2546+ enc.encode(reflect.ValueOf(v), 0)
2547+ }
2548+ return nil
2549+}
2550+
2551+// encode encodes the given value to the writer and panics on error. depth holds
2552+// the depth of the container nesting.
2553+func (enc *encoder) encode(v reflect.Value, depth int) {
2554+ enc.align(alignment(v.Type()))
2555+ switch v.Kind() {
2556+ case reflect.Uint8:
2557+ var b [1]byte
2558+ b[0] = byte(v.Uint())
2559+ if _, err := enc.out.Write(b[:]); err != nil {
2560+ panic(err)
2561+ }
2562+ enc.pos++
2563+ case reflect.Bool:
2564+ if v.Bool() {
2565+ enc.encode(reflect.ValueOf(uint32(1)), depth)
2566+ } else {
2567+ enc.encode(reflect.ValueOf(uint32(0)), depth)
2568+ }
2569+ case reflect.Int16:
2570+ enc.binwrite(int16(v.Int()))
2571+ enc.pos += 2
2572+ case reflect.Uint16:
2573+ enc.binwrite(uint16(v.Uint()))
2574+ enc.pos += 2
2575+ case reflect.Int32:
2576+ enc.binwrite(int32(v.Int()))
2577+ enc.pos += 4
2578+ case reflect.Uint32:
2579+ enc.binwrite(uint32(v.Uint()))
2580+ enc.pos += 4
2581+ case reflect.Int64:
2582+ enc.binwrite(v.Int())
2583+ enc.pos += 8
2584+ case reflect.Uint64:
2585+ enc.binwrite(v.Uint())
2586+ enc.pos += 8
2587+ case reflect.Float64:
2588+ enc.binwrite(v.Float())
2589+ enc.pos += 8
2590+ case reflect.String:
2591+ enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
2592+ b := make([]byte, v.Len()+1)
2593+ copy(b, v.String())
2594+ b[len(b)-1] = 0
2595+ n, err := enc.out.Write(b)
2596+ if err != nil {
2597+ panic(err)
2598+ }
2599+ enc.pos += n
2600+ case reflect.Ptr:
2601+ enc.encode(v.Elem(), depth)
2602+ case reflect.Slice, reflect.Array:
2603+ if depth >= 64 {
2604+ panic(FormatError("input exceeds container depth limit"))
2605+ }
2606+ // Lookahead offset: 4 bytes for uint32 length (with alignment),
2607+ // plus alignment for elements.
2608+ n := enc.padding(0, 4) + 4
2609+ offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem()))
2610+
2611+ var buf bytes.Buffer
2612+ bufenc := newEncoderAtOffset(&buf, offset, enc.order)
2613+
2614+ for i := 0; i < v.Len(); i++ {
2615+ bufenc.encode(v.Index(i), depth+1)
2616+ }
2617+ enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
2618+ length := buf.Len()
2619+ enc.align(alignment(v.Type().Elem()))
2620+ if _, err := buf.WriteTo(enc.out); err != nil {
2621+ panic(err)
2622+ }
2623+ enc.pos += length
2624+ case reflect.Struct:
2625+ if depth >= 64 && v.Type() != signatureType {
2626+ panic(FormatError("input exceeds container depth limit"))
2627+ }
2628+ switch t := v.Type(); t {
2629+ case signatureType:
2630+ str := v.Field(0)
2631+ enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
2632+ b := make([]byte, str.Len()+1)
2633+ copy(b, str.String())
2634+ b[len(b)-1] = 0
2635+ n, err := enc.out.Write(b)
2636+ if err != nil {
2637+ panic(err)
2638+ }
2639+ enc.pos += n
2640+ case variantType:
2641+ variant := v.Interface().(Variant)
2642+ enc.encode(reflect.ValueOf(variant.sig), depth+1)
2643+ enc.encode(reflect.ValueOf(variant.value), depth+1)
2644+ default:
2645+ for i := 0; i < v.Type().NumField(); i++ {
2646+ field := t.Field(i)
2647+ if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
2648+ enc.encode(v.Field(i), depth+1)
2649+ }
2650+ }
2651+ }
2652+ case reflect.Map:
2653+ // Maps are arrays of structures, so they actually increase the depth by
2654+ // 2.
2655+ if depth >= 63 {
2656+ panic(FormatError("input exceeds container depth limit"))
2657+ }
2658+ if !isKeyType(v.Type().Key()) {
2659+ panic(InvalidTypeError{v.Type()})
2660+ }
2661+ keys := v.MapKeys()
2662+ // Lookahead offset: 4 bytes for uint32 length (with alignment),
2663+ // plus 8-byte alignment
2664+ n := enc.padding(0, 4) + 4
2665+ offset := enc.pos + n + enc.padding(n, 8)
2666+
2667+ var buf bytes.Buffer
2668+ bufenc := newEncoderAtOffset(&buf, offset, enc.order)
2669+ for _, k := range keys {
2670+ bufenc.align(8)
2671+ bufenc.encode(k, depth+2)
2672+ bufenc.encode(v.MapIndex(k), depth+2)
2673+ }
2674+ enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
2675+ length := buf.Len()
2676+ enc.align(8)
2677+ if _, err := buf.WriteTo(enc.out); err != nil {
2678+ panic(err)
2679+ }
2680+ enc.pos += length
2681+ default:
2682+ panic(InvalidTypeError{v.Type()})
2683+ }
2684+}
2685
2686=== added file 'service-ng/src/github.com/godbus/dbus/encoder_test.go'
2687--- service-ng/src/github.com/godbus/dbus/encoder_test.go 1970-01-01 00:00:00 +0000
2688+++ service-ng/src/github.com/godbus/dbus/encoder_test.go 2015-09-03 16:43:03 +0000
2689@@ -0,0 +1,58 @@
2690+package dbus
2691+
2692+import (
2693+ "bytes"
2694+ "encoding/binary"
2695+ "reflect"
2696+ "testing"
2697+)
2698+
2699+func TestEncodeArrayOfMaps(t *testing.T) {
2700+ tests := []struct {
2701+ name string
2702+ vs []interface{}
2703+ }{
2704+ {
2705+ "aligned at 8 at start of array",
2706+ []interface{}{
2707+ "12345",
2708+ []map[string]Variant{
2709+ {
2710+ "abcdefg": MakeVariant("foo"),
2711+ "cdef": MakeVariant(uint32(2)),
2712+ },
2713+ },
2714+ },
2715+ },
2716+ {
2717+ "not aligned at 8 for start of array",
2718+ []interface{}{
2719+ "1234567890",
2720+ []map[string]Variant{
2721+ {
2722+ "abcdefg": MakeVariant("foo"),
2723+ "cdef": MakeVariant(uint32(2)),
2724+ },
2725+ },
2726+ },
2727+ },
2728+ }
2729+ for _, order := range []binary.ByteOrder{binary.LittleEndian, binary.BigEndian} {
2730+ for _, tt := range tests {
2731+ buf := new(bytes.Buffer)
2732+ enc := newEncoder(buf, order)
2733+ enc.Encode(tt.vs...)
2734+
2735+ dec := newDecoder(buf, order)
2736+ v, err := dec.Decode(SignatureOf(tt.vs...))
2737+ if err != nil {
2738+ t.Errorf("%q: decode (%v) failed: %v", tt.name, order, err)
2739+ continue
2740+ }
2741+ if !reflect.DeepEqual(v, tt.vs) {
2742+ t.Errorf("%q: (%v) not equal: got '%v', want '%v'", tt.name, order, v, tt.vs)
2743+ continue
2744+ }
2745+ }
2746+ }
2747+}
2748
2749=== added file 'service-ng/src/github.com/godbus/dbus/examples_test.go'
2750--- service-ng/src/github.com/godbus/dbus/examples_test.go 1970-01-01 00:00:00 +0000
2751+++ service-ng/src/github.com/godbus/dbus/examples_test.go 2015-09-03 16:43:03 +0000
2752@@ -0,0 +1,50 @@
2753+package dbus
2754+
2755+import "fmt"
2756+
2757+func ExampleConn_Emit() {
2758+ conn, err := SessionBus()
2759+ if err != nil {
2760+ panic(err)
2761+ }
2762+
2763+ conn.Emit("/foo/bar", "foo.bar.Baz", uint32(0xDAEDBEEF))
2764+}
2765+
2766+func ExampleObject_Call() {
2767+ var list []string
2768+
2769+ conn, err := SessionBus()
2770+ if err != nil {
2771+ panic(err)
2772+ }
2773+
2774+ err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&list)
2775+ if err != nil {
2776+ panic(err)
2777+ }
2778+ for _, v := range list {
2779+ fmt.Println(v)
2780+ }
2781+}
2782+
2783+func ExampleObject_Go() {
2784+ conn, err := SessionBus()
2785+ if err != nil {
2786+ panic(err)
2787+ }
2788+
2789+ ch := make(chan *Call, 10)
2790+ conn.BusObject().Go("org.freedesktop.DBus.ListActivatableNames", 0, ch)
2791+ select {
2792+ case call := <-ch:
2793+ if call.Err != nil {
2794+ panic(err)
2795+ }
2796+ list := call.Body[0].([]string)
2797+ for _, v := range list {
2798+ fmt.Println(v)
2799+ }
2800+ // put some other cases here
2801+ }
2802+}
2803
2804=== added file 'service-ng/src/github.com/godbus/dbus/export.go'
2805--- service-ng/src/github.com/godbus/dbus/export.go 1970-01-01 00:00:00 +0000
2806+++ service-ng/src/github.com/godbus/dbus/export.go 2015-09-03 16:43:03 +0000
2807@@ -0,0 +1,410 @@
2808+package dbus
2809+
2810+import (
2811+ "errors"
2812+ "fmt"
2813+ "reflect"
2814+ "strings"
2815+)
2816+
2817+var (
2818+ errmsgInvalidArg = Error{
2819+ "org.freedesktop.DBus.Error.InvalidArgs",
2820+ []interface{}{"Invalid type / number of args"},
2821+ }
2822+ errmsgNoObject = Error{
2823+ "org.freedesktop.DBus.Error.NoSuchObject",
2824+ []interface{}{"No such object"},
2825+ }
2826+ errmsgUnknownMethod = Error{
2827+ "org.freedesktop.DBus.Error.UnknownMethod",
2828+ []interface{}{"Unknown / invalid method"},
2829+ }
2830+)
2831+
2832+// exportWithMapping represents an exported struct along with a method name
2833+// mapping to allow for exporting lower-case methods, etc.
2834+type exportWithMapping struct {
2835+ export interface{}
2836+
2837+ // Method name mapping; key -> struct method, value -> dbus method.
2838+ mapping map[string]string
2839+
2840+ // Whether or not this export is for the entire subtree
2841+ includeSubtree bool
2842+}
2843+
2844+// Sender is a type which can be used in exported methods to receive the message
2845+// sender.
2846+type Sender string
2847+
2848+func exportedMethod(export exportWithMapping, name string) reflect.Value {
2849+ if export.export == nil {
2850+ return reflect.Value{}
2851+ }
2852+
2853+ // If a mapping was included in the export, check the map to see if we
2854+ // should be looking for a different method in the export.
2855+ if export.mapping != nil {
2856+ for key, value := range export.mapping {
2857+ if value == name {
2858+ name = key
2859+ break
2860+ }
2861+
2862+ // Catch the case where a method is aliased but the client is calling
2863+ // the original, e.g. the "Foo" method was exported mapped to
2864+ // "foo," and dbus client called the original "Foo."
2865+ if key == name {
2866+ return reflect.Value{}
2867+ }
2868+ }
2869+ }
2870+
2871+ value := reflect.ValueOf(export.export)
2872+ m := value.MethodByName(name)
2873+
2874+ // Catch the case of attempting to call an unexported method
2875+ method, ok := value.Type().MethodByName(name)
2876+
2877+ if !m.IsValid() || !ok || method.PkgPath != "" {
2878+ return reflect.Value{}
2879+ }
2880+ t := m.Type()
2881+ if t.NumOut() == 0 ||
2882+ t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {
2883+
2884+ return reflect.Value{}
2885+ }
2886+ return m
2887+}
2888+
2889+// searchHandlers will look through all registered handlers looking for one
2890+// to handle the given path. If a verbatim one isn't found, it will check for
2891+// a subtree registration for the path as well.
2892+func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) {
2893+ conn.handlersLck.RLock()
2894+ defer conn.handlersLck.RUnlock()
2895+
2896+ handlers, ok := conn.handlers[path]
2897+
2898+ // If handlers weren't found for this exact path, look for a matching subtree
2899+ // registration
2900+ if !ok {
2901+ handlers = make(map[string]exportWithMapping)
2902+ path = path[:strings.LastIndex(string(path), "/")]
2903+ for len(path) > 0 {
2904+ var subtreeHandlers map[string]exportWithMapping
2905+ subtreeHandlers, ok = conn.handlers[path]
2906+ if ok {
2907+ for iface, handler := range subtreeHandlers {
2908+ // Only include this handler if it registered for the subtree
2909+ if handler.includeSubtree {
2910+ handlers[iface] = handler
2911+ }
2912+ }
2913+
2914+ break
2915+ }
2916+
2917+ path = path[:strings.LastIndex(string(path), "/")]
2918+ }
2919+ }
2920+
2921+ return handlers, ok
2922+}
2923+
2924+// handleCall handles the given method call (i.e. looks if it's one of the
2925+// pre-implemented ones and searches for a corresponding handler if not).
2926+func (conn *Conn) handleCall(msg *Message) {
2927+ name := msg.Headers[FieldMember].value.(string)
2928+ path := msg.Headers[FieldPath].value.(ObjectPath)
2929+ ifaceName, hasIface := msg.Headers[FieldInterface].value.(string)
2930+ sender, hasSender := msg.Headers[FieldSender].value.(string)
2931+ serial := msg.serial
2932+ if ifaceName == "org.freedesktop.DBus.Peer" {
2933+ switch name {
2934+ case "Ping":
2935+ conn.sendReply(sender, serial)
2936+ case "GetMachineId":
2937+ conn.sendReply(sender, serial, conn.uuid)
2938+ default:
2939+ conn.sendError(errmsgUnknownMethod, sender, serial)
2940+ }
2941+ return
2942+ }
2943+ if len(name) == 0 {
2944+ conn.sendError(errmsgUnknownMethod, sender, serial)
2945+ }
2946+
2947+ // Find the exported handler (if any) for this path
2948+ handlers, ok := conn.searchHandlers(path)
2949+ if !ok {
2950+ conn.sendError(errmsgNoObject, sender, serial)
2951+ return
2952+ }
2953+
2954+ var m reflect.Value
2955+ if hasIface {
2956+ iface := handlers[ifaceName]
2957+ m = exportedMethod(iface, name)
2958+ } else {
2959+ for _, v := range handlers {
2960+ m = exportedMethod(v, name)
2961+ if m.IsValid() {
2962+ break
2963+ }
2964+ }
2965+ }
2966+
2967+ if !m.IsValid() {
2968+ conn.sendError(errmsgUnknownMethod, sender, serial)
2969+ return
2970+ }
2971+
2972+ t := m.Type()
2973+ vs := msg.Body
2974+ pointers := make([]interface{}, t.NumIn())
2975+ decode := make([]interface{}, 0, len(vs))
2976+ for i := 0; i < t.NumIn(); i++ {
2977+ tp := t.In(i)
2978+ val := reflect.New(tp)
2979+ pointers[i] = val.Interface()
2980+ if tp == reflect.TypeOf((*Sender)(nil)).Elem() {
2981+ val.Elem().SetString(sender)
2982+ } else if tp == reflect.TypeOf((*Message)(nil)).Elem() {
2983+ val.Elem().Set(reflect.ValueOf(*msg))
2984+ } else {
2985+ decode = append(decode, pointers[i])
2986+ }
2987+ }
2988+
2989+ if len(decode) != len(vs) {
2990+ conn.sendError(errmsgInvalidArg, sender, serial)
2991+ return
2992+ }
2993+
2994+ if err := Store(vs, decode...); err != nil {
2995+ conn.sendError(errmsgInvalidArg, sender, serial)
2996+ return
2997+ }
2998+
2999+ // Extract parameters
3000+ params := make([]reflect.Value, len(pointers))
3001+ for i := 0; i < len(pointers); i++ {
3002+ params[i] = reflect.ValueOf(pointers[i]).Elem()
3003+ }
3004+
3005+ // Call method
3006+ ret := m.Call(params)
3007+ if em := ret[t.NumOut()-1].Interface().(*Error); em != nil {
3008+ conn.sendError(*em, sender, serial)
3009+ return
3010+ }
3011+
3012+ if msg.Flags&FlagNoReplyExpected == 0 {
3013+ reply := new(Message)
3014+ reply.Type = TypeMethodReply
3015+ reply.serial = conn.getSerial()
3016+ reply.Headers = make(map[HeaderField]Variant)
3017+ if hasSender {
3018+ reply.Headers[FieldDestination] = msg.Headers[FieldSender]
3019+ }
3020+ reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
3021+ reply.Body = make([]interface{}, len(ret)-1)
3022+ for i := 0; i < len(ret)-1; i++ {
3023+ reply.Body[i] = ret[i].Interface()
3024+ }
3025+ if len(ret) != 1 {
3026+ reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
3027+ }
3028+ conn.outLck.RLock()
3029+ if !conn.closed {
3030+ conn.out <- reply
3031+ }
3032+ conn.outLck.RUnlock()
3033+ }
3034+}
3035+
3036+// Emit emits the given signal on the message bus. The name parameter must be
3037+// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
3038+func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
3039+ if !path.IsValid() {
3040+ return errors.New("dbus: invalid object path")
3041+ }
3042+ i := strings.LastIndex(name, ".")
3043+ if i == -1 {
3044+ return errors.New("dbus: invalid method name")
3045+ }
3046+ iface := name[:i]
3047+ member := name[i+1:]
3048+ if !isValidMember(member) {
3049+ return errors.New("dbus: invalid method name")
3050+ }
3051+ if !isValidInterface(iface) {
3052+ return errors.New("dbus: invalid interface name")
3053+ }
3054+ msg := new(Message)
3055+ msg.Type = TypeSignal
3056+ msg.serial = conn.getSerial()
3057+ msg.Headers = make(map[HeaderField]Variant)
3058+ msg.Headers[FieldInterface] = MakeVariant(iface)
3059+ msg.Headers[FieldMember] = MakeVariant(member)
3060+ msg.Headers[FieldPath] = MakeVariant(path)
3061+ msg.Body = values
3062+ if len(values) > 0 {
3063+ msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
3064+ }
3065+ conn.outLck.RLock()
3066+ defer conn.outLck.RUnlock()
3067+ if conn.closed {
3068+ return ErrClosed
3069+ }
3070+ conn.out <- msg
3071+ return nil
3072+}
3073+
3074+// Export registers the given value to be exported as an object on the
3075+// message bus.
3076+//
3077+// If a method call on the given path and interface is received, an exported
3078+// method with the same name is called with v as the receiver if the
3079+// parameters match and the last return value is of type *Error. If this
3080+// *Error is not nil, it is sent back to the caller as an error.
3081+// Otherwise, a method reply is sent with the other return values as its body.
3082+//
3083+// Any parameters with the special type Sender are set to the sender of the
3084+// dbus message when the method is called. Parameters of this type do not
3085+// contribute to the dbus signature of the method (i.e. the method is exposed
3086+// as if the parameters of type Sender were not there).
3087+//
3088+// Similarly, any parameters with the type Message are set to the raw message
3089+// received on the bus. Again, parameters of this type do not contribute to the
3090+// dbus signature of the method.
3091+//
3092+// Every method call is executed in a new goroutine, so the method may be called
3093+// in multiple goroutines at once.
3094+//
3095+// Method calls on the interface org.freedesktop.DBus.Peer will be automatically
3096+// handled for every object.
3097+//
3098+// Passing nil as the first parameter will cause conn to cease handling calls on
3099+// the given combination of path and interface.
3100+//
3101+// Export returns an error if path is not a valid path name.
3102+func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
3103+ return conn.ExportWithMap(v, nil, path, iface)
3104+}
3105+
3106+// ExportWithMap works exactly like Export but provides the ability to remap
3107+// method names (e.g. export a lower-case method).
3108+//
3109+// The keys in the map are the real method names (exported on the struct), and
3110+// the values are the method names to be exported on DBus.
3111+func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
3112+ return conn.exportWithMap(v, mapping, path, iface, false)
3113+}
3114+
3115+// ExportSubtree works exactly like Export but registers the given value for
3116+// an entire subtree rather under the root path provided.
3117+//
3118+// In order to make this useful, one parameter in each of the value's exported
3119+// methods should be a Message, in which case it will contain the raw message
3120+// (allowing one to get access to the path that caused the method to be called).
3121+//
3122+// Note that more specific export paths take precedence over less specific. For
3123+// example, a method call using the ObjectPath /foo/bar/baz will call a method
3124+// exported on /foo/bar before a method exported on /foo.
3125+func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error {
3126+ return conn.ExportSubtreeWithMap(v, nil, path, iface)
3127+}
3128+
3129+// ExportSubtreeWithMap works exactly like ExportSubtree but provides the
3130+// ability to remap method names (e.g. export a lower-case method).
3131+//
3132+// The keys in the map are the real method names (exported on the struct), and
3133+// the values are the method names to be exported on DBus.
3134+func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
3135+ return conn.exportWithMap(v, mapping, path, iface, true)
3136+}
3137+
3138+// exportWithMap is the worker function for all exports/registrations.
3139+func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error {
3140+ if !path.IsValid() {
3141+ return fmt.Errorf(`dbus: Invalid path name: "%s"`, path)
3142+ }
3143+
3144+ conn.handlersLck.Lock()
3145+ defer conn.handlersLck.Unlock()
3146+
3147+ // Remove a previous export if the interface is nil
3148+ if v == nil {
3149+ if _, ok := conn.handlers[path]; ok {
3150+ delete(conn.handlers[path], iface)
3151+ if len(conn.handlers[path]) == 0 {
3152+ delete(conn.handlers, path)
3153+ }
3154+ }
3155+
3156+ return nil
3157+ }
3158+
3159+ // If this is the first handler for this path, make a new map to hold all
3160+ // handlers for this path.
3161+ if _, ok := conn.handlers[path]; !ok {
3162+ conn.handlers[path] = make(map[string]exportWithMapping)
3163+ }
3164+
3165+ // Finally, save this handler
3166+ conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree}
3167+
3168+ return nil
3169+}
3170+
3171+// ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response.
3172+func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) {
3173+ var r uint32
3174+ err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r)
3175+ if err != nil {
3176+ return 0, err
3177+ }
3178+ return ReleaseNameReply(r), nil
3179+}
3180+
3181+// RequestName calls org.freedesktop.DBus.RequestName and awaits a response.
3182+func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) {
3183+ var r uint32
3184+ err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r)
3185+ if err != nil {
3186+ return 0, err
3187+ }
3188+ return RequestNameReply(r), nil
3189+}
3190+
3191+// ReleaseNameReply is the reply to a ReleaseName call.
3192+type ReleaseNameReply uint32
3193+
3194+const (
3195+ ReleaseNameReplyReleased ReleaseNameReply = 1 + iota
3196+ ReleaseNameReplyNonExistent
3197+ ReleaseNameReplyNotOwner
3198+)
3199+
3200+// RequestNameFlags represents the possible flags for a RequestName call.
3201+type RequestNameFlags uint32
3202+
3203+const (
3204+ NameFlagAllowReplacement RequestNameFlags = 1 << iota
3205+ NameFlagReplaceExisting
3206+ NameFlagDoNotQueue
3207+)
3208+
3209+// RequestNameReply is the reply to a RequestName call.
3210+type RequestNameReply uint32
3211+
3212+const (
3213+ RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota
3214+ RequestNameReplyInQueue
3215+ RequestNameReplyExists
3216+ RequestNameReplyAlreadyOwner
3217+)
3218
3219=== added file 'service-ng/src/github.com/godbus/dbus/export_test.go'
3220--- service-ng/src/github.com/godbus/dbus/export_test.go 1970-01-01 00:00:00 +0000
3221+++ service-ng/src/github.com/godbus/dbus/export_test.go 2015-09-03 16:43:03 +0000
3222@@ -0,0 +1,374 @@
3223+package dbus
3224+
3225+import "testing"
3226+
3227+type lowerCaseExport struct{}
3228+
3229+func (export lowerCaseExport) foo() (string, *Error) {
3230+ return "bar", nil
3231+}
3232+
3233+type fooExport struct {
3234+ message Message
3235+}
3236+
3237+func (export *fooExport) Foo(message Message, param string) (string, *Error) {
3238+ export.message = message
3239+ return "foo", nil
3240+}
3241+
3242+type barExport struct{}
3243+
3244+func (export barExport) Foo(param string) (string, *Error) {
3245+ return "bar", nil
3246+}
3247+
3248+type badExport struct{}
3249+
3250+func (export badExport) Foo(param string) string {
3251+ return "bar"
3252+}
3253+
3254+// Test typical Export usage.
3255+func TestExport(t *testing.T) {
3256+ connection, err := SessionBus()
3257+ if err != nil {
3258+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3259+ }
3260+
3261+ name := connection.Names()[0]
3262+
3263+ connection.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3264+ object := connection.Object(name, "/org/guelfey/DBus/Test")
3265+ subtreeObject := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
3266+
3267+ var response int64
3268+ err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
3269+ if err != nil {
3270+ t.Errorf("Unexpected error calling Double: %s", err)
3271+ }
3272+
3273+ if response != 4 {
3274+ t.Errorf("Response was %d, expected 4", response)
3275+ }
3276+
3277+ // Verify that calling a subtree of a regular export does not result in a
3278+ // valid method call.
3279+ err = subtreeObject.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
3280+ if err == nil {
3281+ t.Error("Expected error due to no object being exported on that path")
3282+ }
3283+
3284+ // Now remove export
3285+ connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3286+ err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
3287+ if err == nil {
3288+ t.Error("Expected an error since the export was removed")
3289+ }
3290+}
3291+
3292+// Test that Exported handlers can obtain raw message.
3293+func TestExport_message(t *testing.T) {
3294+ connection, err := SessionBus()
3295+ if err != nil {
3296+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3297+ }
3298+
3299+ name := connection.Names()[0]
3300+
3301+ export := &fooExport{}
3302+ connection.Export(export, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3303+ object := connection.Object(name, "/org/guelfey/DBus/Test")
3304+
3305+ var response string
3306+ err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
3307+ if err != nil {
3308+ t.Errorf("Unexpected error calling Foo: %s", err)
3309+ }
3310+
3311+ if response != "foo" {
3312+ t.Errorf(`Response was %s, expected "foo"`, response)
3313+ }
3314+
3315+ if export.message.serial == 0 {
3316+ t.Error("Expected a valid message to be given to handler")
3317+ }
3318+}
3319+
3320+// Test Export with an invalid path.
3321+func TestExport_invalidPath(t *testing.T) {
3322+ connection, err := SessionBus()
3323+ if err != nil {
3324+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3325+ }
3326+
3327+ err = connection.Export(nil, "foo", "bar")
3328+ if err == nil {
3329+ t.Error("Expected an error due to exporting with an invalid path")
3330+ }
3331+}
3332+
3333+// Test Export with an un-exported method. This should not panic, but rather
3334+// result in an invalid method call.
3335+func TestExport_unexportedMethod(t *testing.T) {
3336+ connection, err := SessionBus()
3337+ if err != nil {
3338+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3339+ }
3340+
3341+ name := connection.Names()[0]
3342+
3343+ connection.Export(lowerCaseExport{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3344+ object := connection.Object(name, "/org/guelfey/DBus/Test")
3345+
3346+ var response string
3347+ call := object.Call("org.guelfey.DBus.Test.foo", 0)
3348+ err = call.Store(&response)
3349+ if err == nil {
3350+ t.Errorf("Expected an error due to calling unexported method")
3351+ }
3352+}
3353+
3354+// Test Export with a method lacking the correct return signature. This should
3355+// result in an invalid method call.
3356+func TestExport_badSignature(t *testing.T) {
3357+ connection, err := SessionBus()
3358+ if err != nil {
3359+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3360+ }
3361+
3362+ name := connection.Names()[0]
3363+
3364+ connection.Export(badExport{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3365+ object := connection.Object(name, "/org/guelfey/DBus/Test")
3366+
3367+ var response string
3368+ call := object.Call("org.guelfey.DBus.Test.Foo", 0)
3369+ err = call.Store(&response)
3370+ if err == nil {
3371+ t.Errorf("Expected an error due to the method lacking the right signature")
3372+ }
3373+}
3374+
3375+// Test typical ExportWithMap usage.
3376+func TestExportWithMap(t *testing.T) {
3377+ connection, err := SessionBus()
3378+ if err != nil {
3379+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3380+ }
3381+
3382+ name := connection.Names()[0]
3383+
3384+ mapping := make(map[string]string)
3385+ mapping["Double"] = "double" // Export this method as lower-case
3386+
3387+ connection.ExportWithMap(server{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3388+ object := connection.Object(name, "/org/guelfey/DBus/Test")
3389+
3390+ var response int64
3391+ err = object.Call("org.guelfey.DBus.Test.double", 0, int64(2)).Store(&response)
3392+ if err != nil {
3393+ t.Errorf("Unexpected error calling double: %s", err)
3394+ }
3395+
3396+ if response != 4 {
3397+ t.Errorf("Response was %d, expected 4", response)
3398+ }
3399+}
3400+
3401+// Test that ExportWithMap does not export both method alias and method.
3402+func TestExportWithMap_bypassAlias(t *testing.T) {
3403+ connection, err := SessionBus()
3404+ if err != nil {
3405+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3406+ }
3407+
3408+ name := connection.Names()[0]
3409+
3410+ mapping := make(map[string]string)
3411+ mapping["Double"] = "double" // Export this method as lower-case
3412+
3413+ connection.ExportWithMap(server{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3414+ object := connection.Object(name, "/org/guelfey/DBus/Test")
3415+
3416+ var response int64
3417+ // Call upper-case Double (i.e. the real method, not the alias)
3418+ err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
3419+ if err == nil {
3420+ t.Error("Expected an error due to calling actual method, not alias")
3421+ }
3422+}
3423+
3424+// Test typical ExportSubtree usage.
3425+func TestExportSubtree(t *testing.T) {
3426+ connection, err := SessionBus()
3427+ if err != nil {
3428+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3429+ }
3430+
3431+ name := connection.Names()[0]
3432+
3433+ export := &fooExport{}
3434+ connection.ExportSubtree(export, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3435+
3436+ // Call a subpath of the exported path
3437+ object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
3438+
3439+ var response string
3440+ err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
3441+ if err != nil {
3442+ t.Errorf("Unexpected error calling Foo: %s", err)
3443+ }
3444+
3445+ if response != "foo" {
3446+ t.Errorf(`Response was %s, expected "foo"`, response)
3447+ }
3448+
3449+ if export.message.serial == 0 {
3450+ t.Error("Expected the raw message, got an invalid one")
3451+ }
3452+
3453+ // Now remove export
3454+ connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3455+ err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
3456+ if err == nil {
3457+ t.Error("Expected an error since the export was removed")
3458+ }
3459+}
3460+
3461+// Test that using ExportSubtree with exported methods that don't contain a
3462+// Message still work, they just don't get the message.
3463+func TestExportSubtree_noMessage(t *testing.T) {
3464+ connection, err := SessionBus()
3465+ if err != nil {
3466+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3467+ }
3468+
3469+ name := connection.Names()[0]
3470+
3471+ connection.ExportSubtree(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3472+
3473+ // Call a subpath of the exported path
3474+ object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
3475+
3476+ var response int64
3477+ err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
3478+ if err != nil {
3479+ t.Errorf("Unexpected error calling Double: %s", err)
3480+ }
3481+
3482+ if response != 4 {
3483+ t.Errorf("Response was %d, expected 4", response)
3484+ }
3485+
3486+ // Now remove export
3487+ connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3488+ err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
3489+ if err == nil {
3490+ t.Error("Expected an error since the export was removed")
3491+ }
3492+}
3493+
3494+// Test that a regular Export takes precedence over ExportSubtree.
3495+func TestExportSubtree_exportPrecedence(t *testing.T) {
3496+ connection, err := SessionBus()
3497+ if err != nil {
3498+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3499+ }
3500+
3501+ name := connection.Names()[0]
3502+
3503+ // Register for the entire subtree of /org/guelfey/DBus/Test
3504+ connection.ExportSubtree(&fooExport{},
3505+ "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3506+
3507+ // Explicitly register for /org/guelfey/DBus/Test/Foo, a subpath of above
3508+ connection.Export(&barExport{}, "/org/guelfey/DBus/Test/Foo",
3509+ "org.guelfey.DBus.Test")
3510+
3511+ // Call the explicitly exported path
3512+ object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
3513+
3514+ var response string
3515+ err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
3516+ if err != nil {
3517+ t.Errorf("Unexpected error calling Foo: %s", err)
3518+ }
3519+
3520+ if response != "bar" {
3521+ t.Errorf(`Response was %s, expected "bar"`, response)
3522+ }
3523+
3524+ response = "" // Reset response so errors aren't confusing
3525+
3526+ // Now remove explicit export
3527+ connection.Export(nil, "/org/guelfey/DBus/Test/Foo", "org.guelfey.DBus.Test")
3528+ err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
3529+ if err != nil {
3530+ t.Errorf("Unexpected error calling Foo: %s", err)
3531+ }
3532+
3533+ // Now the subtree export should handle the call
3534+ if response != "foo" {
3535+ t.Errorf(`Response was %s, expected "foo"`, response)
3536+ }
3537+}
3538+
3539+// Test typical ExportSubtreeWithMap usage.
3540+func TestExportSubtreeWithMap(t *testing.T) {
3541+ connection, err := SessionBus()
3542+ if err != nil {
3543+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3544+ }
3545+
3546+ name := connection.Names()[0]
3547+
3548+ mapping := make(map[string]string)
3549+ mapping["Foo"] = "foo" // Export this method as lower-case
3550+
3551+ connection.ExportSubtreeWithMap(&fooExport{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3552+
3553+ // Call a subpath of the exported path
3554+ object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
3555+
3556+ var response string
3557+ // Call the lower-case method
3558+ err = object.Call("org.guelfey.DBus.Test.foo", 0, "qux").Store(&response)
3559+ if err != nil {
3560+ t.Errorf("Unexpected error calling Foo: %s", err)
3561+ }
3562+
3563+ if response != "foo" {
3564+ t.Errorf(`Response was %s, expected "foo"`, response)
3565+ }
3566+
3567+ // Now remove export
3568+ connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3569+ err = object.Call("org.guelfey.DBus.Test.foo", 0, "qux").Store(&response)
3570+ if err == nil {
3571+ t.Error("Expected an error since the export was removed")
3572+ }
3573+}
3574+
3575+// Test that ExportSubtreeWithMap does not export both method alias and method.
3576+func TestExportSubtreeWithMap_bypassAlias(t *testing.T) {
3577+ connection, err := SessionBus()
3578+ if err != nil {
3579+ t.Fatalf("Unexpected error connecting to session bus: %s", err)
3580+ }
3581+
3582+ name := connection.Names()[0]
3583+
3584+ mapping := make(map[string]string)
3585+ mapping["Foo"] = "foo" // Export this method as lower-case
3586+
3587+ connection.ExportSubtreeWithMap(&fooExport{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
3588+ object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
3589+
3590+ var response string
3591+ // Call upper-case Foo (i.e. the real method, not the alias)
3592+ err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
3593+ if err == nil {
3594+ t.Error("Expected an error due to calling actual method, not alias")
3595+ }
3596+}
3597
3598=== added file 'service-ng/src/github.com/godbus/dbus/homedir.go'
3599--- service-ng/src/github.com/godbus/dbus/homedir.go 1970-01-01 00:00:00 +0000
3600+++ service-ng/src/github.com/godbus/dbus/homedir.go 2015-09-03 16:43:03 +0000
3601@@ -0,0 +1,28 @@
3602+package dbus
3603+
3604+import (
3605+ "os"
3606+ "sync"
3607+)
3608+
3609+var (
3610+ homeDir string
3611+ homeDirLock sync.Mutex
3612+)
3613+
3614+func getHomeDir() string {
3615+ homeDirLock.Lock()
3616+ defer homeDirLock.Unlock()
3617+
3618+ if homeDir != "" {
3619+ return homeDir
3620+ }
3621+
3622+ homeDir = os.Getenv("HOME")
3623+ if homeDir != "" {
3624+ return homeDir
3625+ }
3626+
3627+ homeDir = lookupHomeDir()
3628+ return homeDir
3629+}
3630
3631=== added file 'service-ng/src/github.com/godbus/dbus/homedir_dynamic.go'
3632--- service-ng/src/github.com/godbus/dbus/homedir_dynamic.go 1970-01-01 00:00:00 +0000
3633+++ service-ng/src/github.com/godbus/dbus/homedir_dynamic.go 2015-09-03 16:43:03 +0000
3634@@ -0,0 +1,15 @@
3635+// +build !static_build
3636+
3637+package dbus
3638+
3639+import (
3640+ "os/user"
3641+)
3642+
3643+func lookupHomeDir() string {
3644+ u, err := user.Current()
3645+ if err != nil {
3646+ return "/"
3647+ }
3648+ return u.HomeDir
3649+}
3650
3651=== added file 'service-ng/src/github.com/godbus/dbus/homedir_static.go'
3652--- service-ng/src/github.com/godbus/dbus/homedir_static.go 1970-01-01 00:00:00 +0000
3653+++ service-ng/src/github.com/godbus/dbus/homedir_static.go 2015-09-03 16:43:03 +0000
3654@@ -0,0 +1,45 @@
3655+// +build static_build
3656+
3657+package dbus
3658+
3659+import (
3660+ "bufio"
3661+ "os"
3662+ "strconv"
3663+ "strings"
3664+)
3665+
3666+func lookupHomeDir() string {
3667+ myUid := os.Getuid()
3668+
3669+ f, err := os.Open("/etc/passwd")
3670+ if err != nil {
3671+ return "/"
3672+ }
3673+ defer f.Close()
3674+
3675+ s := bufio.NewScanner(f)
3676+
3677+ for s.Scan() {
3678+ if err := s.Err(); err != nil {
3679+ break
3680+ }
3681+
3682+ line := strings.TrimSpace(s.Text())
3683+ if line == "" {
3684+ continue
3685+ }
3686+
3687+ parts := strings.Split(line, ":")
3688+
3689+ if len(parts) >= 6 {
3690+ uid, err := strconv.Atoi(parts[2])
3691+ if err == nil && uid == myUid {
3692+ return parts[5]
3693+ }
3694+ }
3695+ }
3696+
3697+ // Default to / if we can't get a better value
3698+ return "/"
3699+}
3700
3701=== added directory 'service-ng/src/github.com/godbus/dbus/introspect'
3702=== added file 'service-ng/src/github.com/godbus/dbus/introspect/call.go'
3703--- service-ng/src/github.com/godbus/dbus/introspect/call.go 1970-01-01 00:00:00 +0000
3704+++ service-ng/src/github.com/godbus/dbus/introspect/call.go 2015-09-03 16:43:03 +0000
3705@@ -0,0 +1,27 @@
3706+package introspect
3707+
3708+import (
3709+ "encoding/xml"
3710+ "github.com/godbus/dbus"
3711+ "strings"
3712+)
3713+
3714+// Call calls org.freedesktop.Introspectable.Introspect on a remote object
3715+// and returns the introspection data.
3716+func Call(o *dbus.Object) (*Node, error) {
3717+ var xmldata string
3718+ var node Node
3719+
3720+ err := o.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xmldata)
3721+ if err != nil {
3722+ return nil, err
3723+ }
3724+ err = xml.NewDecoder(strings.NewReader(xmldata)).Decode(&node)
3725+ if err != nil {
3726+ return nil, err
3727+ }
3728+ if node.Name == "" {
3729+ node.Name = string(o.Path())
3730+ }
3731+ return &node, nil
3732+}
3733
3734=== added file 'service-ng/src/github.com/godbus/dbus/introspect/introspect.go'
3735--- service-ng/src/github.com/godbus/dbus/introspect/introspect.go 1970-01-01 00:00:00 +0000
3736+++ service-ng/src/github.com/godbus/dbus/introspect/introspect.go 2015-09-03 16:43:03 +0000
3737@@ -0,0 +1,86 @@
3738+// Package introspect provides some utilities for dealing with the DBus
3739+// introspection format.
3740+package introspect
3741+
3742+import "encoding/xml"
3743+
3744+// The introspection data for the org.freedesktop.DBus.Introspectable interface.
3745+var IntrospectData = Interface{
3746+ Name: "org.freedesktop.DBus.Introspectable",
3747+ Methods: []Method{
3748+ {
3749+ Name: "Introspect",
3750+ Args: []Arg{
3751+ {"out", "s", "out"},
3752+ },
3753+ },
3754+ },
3755+}
3756+
3757+// XML document type declaration of the introspection format version 1.0
3758+const IntrospectDeclarationString = `
3759+ <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
3760+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3761+`
3762+
3763+// The introspection data for the org.freedesktop.DBus.Introspectable interface,
3764+// as a string.
3765+const IntrospectDataString = `
3766+ <interface name="org.freedesktop.DBus.Introspectable">
3767+ <method name="Introspect">
3768+ <arg name="out" direction="out" type="s"/>
3769+ </method>
3770+ </interface>
3771+`
3772+
3773+// Node is the root element of an introspection.
3774+type Node struct {
3775+ XMLName xml.Name `xml:"node"`
3776+ Name string `xml:"name,attr,omitempty"`
3777+ Interfaces []Interface `xml:"interface"`
3778+ Children []Node `xml:"node,omitempty"`
3779+}
3780+
3781+// Interface describes a DBus interface that is available on the message bus.
3782+type Interface struct {
3783+ Name string `xml:"name,attr"`
3784+ Methods []Method `xml:"method"`
3785+ Signals []Signal `xml:"signal"`
3786+ Properties []Property `xml:"property"`
3787+ Annotations []Annotation `xml:"annotation"`
3788+}
3789+
3790+// Method describes a Method on an Interface as retured by an introspection.
3791+type Method struct {
3792+ Name string `xml:"name,attr"`
3793+ Args []Arg `xml:"arg"`
3794+ Annotations []Annotation `xml:"annotation"`
3795+}
3796+
3797+// Signal describes a Signal emitted on an Interface.
3798+type Signal struct {
3799+ Name string `xml:"name,attr"`
3800+ Args []Arg `xml:"arg"`
3801+ Annotations []Annotation `xml:"annotation"`
3802+}
3803+
3804+// Property describes a property of an Interface.
3805+type Property struct {
3806+ Name string `xml:"name,attr"`
3807+ Type string `xml:"type,attr"`
3808+ Access string `xml:"access,attr"`
3809+ Annotations []Annotation `xml:"annotation"`
3810+}
3811+
3812+// Arg represents an argument of a method or a signal.
3813+type Arg struct {
3814+ Name string `xml:"name,attr,omitempty"`
3815+ Type string `xml:"type,attr"`
3816+ Direction string `xml:"direction,attr,omitempty"`
3817+}
3818+
3819+// Annotation is an annotation in the introspection format.
3820+type Annotation struct {
3821+ Name string `xml:"name,attr"`
3822+ Value string `xml:"value,attr"`
3823+}
3824
3825=== added file 'service-ng/src/github.com/godbus/dbus/introspect/introspectable.go'
3826--- service-ng/src/github.com/godbus/dbus/introspect/introspectable.go 1970-01-01 00:00:00 +0000
3827+++ service-ng/src/github.com/godbus/dbus/introspect/introspectable.go 2015-09-03 16:43:03 +0000
3828@@ -0,0 +1,76 @@
3829+package introspect
3830+
3831+import (
3832+ "encoding/xml"
3833+ "github.com/godbus/dbus"
3834+ "reflect"
3835+ "strings"
3836+)
3837+
3838+// Introspectable implements org.freedesktop.Introspectable.
3839+//
3840+// You can create it by converting the XML-formatted introspection data from a
3841+// string to an Introspectable or call NewIntrospectable with a Node. Then,
3842+// export it as org.freedesktop.Introspectable on you object.
3843+type Introspectable string
3844+
3845+// NewIntrospectable returns an Introspectable that returns the introspection
3846+// data that corresponds to the given Node. If n.Interfaces doesn't contain the
3847+// data for org.freedesktop.DBus.Introspectable, it is added automatically.
3848+func NewIntrospectable(n *Node) Introspectable {
3849+ found := false
3850+ for _, v := range n.Interfaces {
3851+ if v.Name == "org.freedesktop.DBus.Introspectable" {
3852+ found = true
3853+ break
3854+ }
3855+ }
3856+ if !found {
3857+ n.Interfaces = append(n.Interfaces, IntrospectData)
3858+ }
3859+ b, err := xml.Marshal(n)
3860+ if err != nil {
3861+ panic(err)
3862+ }
3863+ return Introspectable(strings.TrimSpace(IntrospectDeclarationString) + string(b))
3864+}
3865+
3866+// Introspect implements org.freedesktop.Introspectable.Introspect.
3867+func (i Introspectable) Introspect() (string, *dbus.Error) {
3868+ return string(i), nil
3869+}
3870+
3871+// Methods returns the description of the methods of v. This can be used to
3872+// create a Node which can be passed to NewIntrospectable.
3873+func Methods(v interface{}) []Method {
3874+ t := reflect.TypeOf(v)
3875+ ms := make([]Method, 0, t.NumMethod())
3876+ for i := 0; i < t.NumMethod(); i++ {
3877+ if t.Method(i).PkgPath != "" {
3878+ continue
3879+ }
3880+ mt := t.Method(i).Type
3881+ if mt.NumOut() == 0 ||
3882+ mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{}) {
3883+
3884+ continue
3885+ }
3886+ var m Method
3887+ m.Name = t.Method(i).Name
3888+ m.Args = make([]Arg, 0, mt.NumIn()+mt.NumOut()-2)
3889+ for j := 1; j < mt.NumIn(); j++ {
3890+ if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() &&
3891+ mt.In(j) != reflect.TypeOf((*dbus.Message)(nil)).Elem() {
3892+ arg := Arg{"", dbus.SignatureOfType(mt.In(j)).String(), "in"}
3893+ m.Args = append(m.Args, arg)
3894+ }
3895+ }
3896+ for j := 0; j < mt.NumOut()-1; j++ {
3897+ arg := Arg{"", dbus.SignatureOfType(mt.Out(j)).String(), "out"}
3898+ m.Args = append(m.Args, arg)
3899+ }
3900+ m.Annotations = make([]Annotation, 0)
3901+ ms = append(ms, m)
3902+ }
3903+ return ms
3904+}
3905
3906=== added file 'service-ng/src/github.com/godbus/dbus/message.go'
3907--- service-ng/src/github.com/godbus/dbus/message.go 1970-01-01 00:00:00 +0000
3908+++ service-ng/src/github.com/godbus/dbus/message.go 2015-09-03 16:43:03 +0000
3909@@ -0,0 +1,346 @@
3910+package dbus
3911+
3912+import (
3913+ "bytes"
3914+ "encoding/binary"
3915+ "errors"
3916+ "io"
3917+ "reflect"
3918+ "strconv"
3919+)
3920+
3921+const protoVersion byte = 1
3922+
3923+// Flags represents the possible flags of a D-Bus message.
3924+type Flags byte
3925+
3926+const (
3927+ // FlagNoReplyExpected signals that the message is not expected to generate
3928+ // a reply. If this flag is set on outgoing messages, any possible reply
3929+ // will be discarded.
3930+ FlagNoReplyExpected Flags = 1 << iota
3931+ // FlagNoAutoStart signals that the message bus should not automatically
3932+ // start an application when handling this message.
3933+ FlagNoAutoStart
3934+)
3935+
3936+// Type represents the possible types of a D-Bus message.
3937+type Type byte
3938+
3939+const (
3940+ TypeMethodCall Type = 1 + iota
3941+ TypeMethodReply
3942+ TypeError
3943+ TypeSignal
3944+ typeMax
3945+)
3946+
3947+func (t Type) String() string {
3948+ switch t {
3949+ case TypeMethodCall:
3950+ return "method call"
3951+ case TypeMethodReply:
3952+ return "reply"
3953+ case TypeError:
3954+ return "error"
3955+ case TypeSignal:
3956+ return "signal"
3957+ }
3958+ return "invalid"
3959+}
3960+
3961+// HeaderField represents the possible byte codes for the headers
3962+// of a D-Bus message.
3963+type HeaderField byte
3964+
3965+const (
3966+ FieldPath HeaderField = 1 + iota
3967+ FieldInterface
3968+ FieldMember
3969+ FieldErrorName
3970+ FieldReplySerial
3971+ FieldDestination
3972+ FieldSender
3973+ FieldSignature
3974+ FieldUnixFDs
3975+ fieldMax
3976+)
3977+
3978+// An InvalidMessageError describes the reason why a D-Bus message is regarded as
3979+// invalid.
3980+type InvalidMessageError string
3981+
3982+func (e InvalidMessageError) Error() string {
3983+ return "dbus: invalid message: " + string(e)
3984+}
3985+
3986+// fieldType are the types of the various header fields.
3987+var fieldTypes = [fieldMax]reflect.Type{
3988+ FieldPath: objectPathType,
3989+ FieldInterface: stringType,
3990+ FieldMember: stringType,
3991+ FieldErrorName: stringType,
3992+ FieldReplySerial: uint32Type,
3993+ FieldDestination: stringType,
3994+ FieldSender: stringType,
3995+ FieldSignature: signatureType,
3996+ FieldUnixFDs: uint32Type,
3997+}
3998+
3999+// requiredFields lists the header fields that are required by the different
4000+// message types.
4001+var requiredFields = [typeMax][]HeaderField{
4002+ TypeMethodCall: {FieldPath, FieldMember},
4003+ TypeMethodReply: {FieldReplySerial},
4004+ TypeError: {FieldErrorName, FieldReplySerial},
4005+ TypeSignal: {FieldPath, FieldInterface, FieldMember},
4006+}
4007+
4008+// Message represents a single D-Bus message.
4009+type Message struct {
4010+ Type
4011+ Flags
4012+ Headers map[HeaderField]Variant
4013+ Body []interface{}
4014+
4015+ serial uint32
4016+}
4017+
4018+type header struct {
4019+ Field byte
4020+ Variant
4021+}
4022+
4023+// DecodeMessage tries to decode a single message in the D-Bus wire format
4024+// from the given reader. The byte order is figured out from the first byte.
4025+// The possibly returned error can be an error of the underlying reader, an
4026+// InvalidMessageError or a FormatError.
4027+func DecodeMessage(rd io.Reader) (msg *Message, err error) {
4028+ var order binary.ByteOrder
4029+ var hlength, length uint32
4030+ var typ, flags, proto byte
4031+ var headers []header
4032+
4033+ b := make([]byte, 1)
4034+ _, err = rd.Read(b)
4035+ if err != nil {
4036+ return
4037+ }
4038+ switch b[0] {
4039+ case 'l':
4040+ order = binary.LittleEndian
4041+ case 'B':
4042+ order = binary.BigEndian
4043+ default:
4044+ return nil, InvalidMessageError("invalid byte order")
4045+ }
4046+
4047+ dec := newDecoder(rd, order)
4048+ dec.pos = 1
4049+
4050+ msg = new(Message)
4051+ vs, err := dec.Decode(Signature{"yyyuu"})
4052+ if err != nil {
4053+ return nil, err
4054+ }
4055+ if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil {
4056+ return nil, err
4057+ }
4058+ msg.Type = Type(typ)
4059+ msg.Flags = Flags(flags)
4060+
4061+ // get the header length separately because we need it later
4062+ b = make([]byte, 4)
4063+ _, err = io.ReadFull(rd, b)
4064+ if err != nil {
4065+ return nil, err
4066+ }
4067+ binary.Read(bytes.NewBuffer(b), order, &hlength)
4068+ if hlength+length+16 > 1<<27 {
4069+ return nil, InvalidMessageError("message is too long")
4070+ }
4071+ dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order)
4072+ dec.pos = 12
4073+ vs, err = dec.Decode(Signature{"a(yv)"})
4074+ if err != nil {
4075+ return nil, err
4076+ }
4077+ if err = Store(vs, &headers); err != nil {
4078+ return nil, err
4079+ }
4080+
4081+ msg.Headers = make(map[HeaderField]Variant)
4082+ for _, v := range headers {
4083+ msg.Headers[HeaderField(v.Field)] = v.Variant
4084+ }
4085+
4086+ dec.align(8)
4087+ body := make([]byte, int(length))
4088+ if length != 0 {
4089+ _, err := io.ReadFull(rd, body)
4090+ if err != nil {
4091+ return nil, err
4092+ }
4093+ }
4094+
4095+ if err = msg.IsValid(); err != nil {
4096+ return nil, err
4097+ }
4098+ sig, _ := msg.Headers[FieldSignature].value.(Signature)
4099+ if sig.str != "" {
4100+ buf := bytes.NewBuffer(body)
4101+ dec = newDecoder(buf, order)
4102+ vs, err := dec.Decode(sig)
4103+ if err != nil {
4104+ return nil, err
4105+ }
4106+ msg.Body = vs
4107+ }
4108+
4109+ return
4110+}
4111+
4112+// EncodeTo encodes and sends a message to the given writer. The byte order must
4113+// be either binary.LittleEndian or binary.BigEndian. If the message is not
4114+// valid or an error occurs when writing, an error is returned.
4115+func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
4116+ if err := msg.IsValid(); err != nil {
4117+ return err
4118+ }
4119+ var vs [7]interface{}
4120+ switch order {
4121+ case binary.LittleEndian:
4122+ vs[0] = byte('l')
4123+ case binary.BigEndian:
4124+ vs[0] = byte('B')
4125+ default:
4126+ return errors.New("dbus: invalid byte order")
4127+ }
4128+ body := new(bytes.Buffer)
4129+ enc := newEncoder(body, order)
4130+ if len(msg.Body) != 0 {
4131+ enc.Encode(msg.Body...)
4132+ }
4133+ vs[1] = msg.Type
4134+ vs[2] = msg.Flags
4135+ vs[3] = protoVersion
4136+ vs[4] = uint32(len(body.Bytes()))
4137+ vs[5] = msg.serial
4138+ headers := make([]header, 0, len(msg.Headers))
4139+ for k, v := range msg.Headers {
4140+ headers = append(headers, header{byte(k), v})
4141+ }
4142+ vs[6] = headers
4143+ var buf bytes.Buffer
4144+ enc = newEncoder(&buf, order)
4145+ enc.Encode(vs[:]...)
4146+ enc.align(8)
4147+ body.WriteTo(&buf)
4148+ if buf.Len() > 1<<27 {
4149+ return InvalidMessageError("message is too long")
4150+ }
4151+ if _, err := buf.WriteTo(out); err != nil {
4152+ return err
4153+ }
4154+ return nil
4155+}
4156+
4157+// IsValid checks whether msg is a valid message and returns an
4158+// InvalidMessageError if it is not.
4159+func (msg *Message) IsValid() error {
4160+ if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected) != 0 {
4161+ return InvalidMessageError("invalid flags")
4162+ }
4163+ if msg.Type == 0 || msg.Type >= typeMax {
4164+ return InvalidMessageError("invalid message type")
4165+ }
4166+ for k, v := range msg.Headers {
4167+ if k == 0 || k >= fieldMax {
4168+ return InvalidMessageError("invalid header")
4169+ }
4170+ if reflect.TypeOf(v.value) != fieldTypes[k] {
4171+ return InvalidMessageError("invalid type of header field")
4172+ }
4173+ }
4174+ for _, v := range requiredFields[msg.Type] {
4175+ if _, ok := msg.Headers[v]; !ok {
4176+ return InvalidMessageError("missing required header")
4177+ }
4178+ }
4179+ if path, ok := msg.Headers[FieldPath]; ok {
4180+ if !path.value.(ObjectPath).IsValid() {
4181+ return InvalidMessageError("invalid path name")
4182+ }
4183+ }
4184+ if iface, ok := msg.Headers[FieldInterface]; ok {
4185+ if !isValidInterface(iface.value.(string)) {
4186+ return InvalidMessageError("invalid interface name")
4187+ }
4188+ }
4189+ if member, ok := msg.Headers[FieldMember]; ok {
4190+ if !isValidMember(member.value.(string)) {
4191+ return InvalidMessageError("invalid member name")
4192+ }
4193+ }
4194+ if errname, ok := msg.Headers[FieldErrorName]; ok {
4195+ if !isValidInterface(errname.value.(string)) {
4196+ return InvalidMessageError("invalid error name")
4197+ }
4198+ }
4199+ if len(msg.Body) != 0 {
4200+ if _, ok := msg.Headers[FieldSignature]; !ok {
4201+ return InvalidMessageError("missing signature")
4202+ }
4203+ }
4204+ return nil
4205+}
4206+
4207+// Serial returns the message's serial number. The returned value is only valid
4208+// for messages received by eavesdropping.
4209+func (msg *Message) Serial() uint32 {
4210+ return msg.serial
4211+}
4212+
4213+// String returns a string representation of a message similar to the format of
4214+// dbus-monitor.
4215+func (msg *Message) String() string {
4216+ if err := msg.IsValid(); err != nil {
4217+ return "<invalid>"
4218+ }
4219+ s := msg.Type.String()
4220+ if v, ok := msg.Headers[FieldSender]; ok {
4221+ s += " from " + v.value.(string)
4222+ }
4223+ if v, ok := msg.Headers[FieldDestination]; ok {
4224+ s += " to " + v.value.(string)
4225+ }
4226+ s += " serial " + strconv.FormatUint(uint64(msg.serial), 10)
4227+ if v, ok := msg.Headers[FieldReplySerial]; ok {
4228+ s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
4229+ }
4230+ if v, ok := msg.Headers[FieldUnixFDs]; ok {
4231+ s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
4232+ }
4233+ if v, ok := msg.Headers[FieldPath]; ok {
4234+ s += " path " + string(v.value.(ObjectPath))
4235+ }
4236+ if v, ok := msg.Headers[FieldInterface]; ok {
4237+ s += " interface " + v.value.(string)
4238+ }
4239+ if v, ok := msg.Headers[FieldErrorName]; ok {
4240+ s += " error " + v.value.(string)
4241+ }
4242+ if v, ok := msg.Headers[FieldMember]; ok {
4243+ s += " member " + v.value.(string)
4244+ }
4245+ if len(msg.Body) != 0 {
4246+ s += "\n"
4247+ }
4248+ for i, v := range msg.Body {
4249+ s += " " + MakeVariant(v).String()
4250+ if i != len(msg.Body)-1 {
4251+ s += "\n"
4252+ }
4253+ }
4254+ return s
4255+}
4256
4257=== added file 'service-ng/src/github.com/godbus/dbus/object.go'
4258--- service-ng/src/github.com/godbus/dbus/object.go 1970-01-01 00:00:00 +0000
4259+++ service-ng/src/github.com/godbus/dbus/object.go 2015-09-03 16:43:03 +0000
4260@@ -0,0 +1,126 @@
4261+package dbus
4262+
4263+import (
4264+ "errors"
4265+ "strings"
4266+)
4267+
4268+// BusObject is the interface of a remote object on which methods can be
4269+// invoked.
4270+type BusObject interface {
4271+ Call(method string, flags Flags, args ...interface{}) *Call
4272+ Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
4273+ GetProperty(p string) (Variant, error)
4274+ Destination() string
4275+ Path() ObjectPath
4276+}
4277+
4278+// Object represents a remote object on which methods can be invoked.
4279+type Object struct {
4280+ conn *Conn
4281+ dest string
4282+ path ObjectPath
4283+}
4284+
4285+// Call calls a method with (*Object).Go and waits for its reply.
4286+func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
4287+ return <-o.Go(method, flags, make(chan *Call, 1), args...).Done
4288+}
4289+
4290+// Go calls a method with the given arguments asynchronously. It returns a
4291+// Call structure representing this method call. The passed channel will
4292+// return the same value once the call is done. If ch is nil, a new channel
4293+// will be allocated. Otherwise, ch has to be buffered or Go will panic.
4294+//
4295+// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure
4296+// is returned of which only the Err member is valid.
4297+//
4298+// If the method parameter contains a dot ('.'), the part before the last dot
4299+// specifies the interface on which the method is called.
4300+func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
4301+ iface := ""
4302+ i := strings.LastIndex(method, ".")
4303+ if i != -1 {
4304+ iface = method[:i]
4305+ }
4306+ method = method[i+1:]
4307+ msg := new(Message)
4308+ msg.Type = TypeMethodCall
4309+ msg.serial = o.conn.getSerial()
4310+ msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
4311+ msg.Headers = make(map[HeaderField]Variant)
4312+ msg.Headers[FieldPath] = MakeVariant(o.path)
4313+ msg.Headers[FieldDestination] = MakeVariant(o.dest)
4314+ msg.Headers[FieldMember] = MakeVariant(method)
4315+ if iface != "" {
4316+ msg.Headers[FieldInterface] = MakeVariant(iface)
4317+ }
4318+ msg.Body = args
4319+ if len(args) > 0 {
4320+ msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
4321+ }
4322+ if msg.Flags&FlagNoReplyExpected == 0 {
4323+ if ch == nil {
4324+ ch = make(chan *Call, 10)
4325+ } else if cap(ch) == 0 {
4326+ panic("dbus: unbuffered channel passed to (*Object).Go")
4327+ }
4328+ call := &Call{
4329+ Destination: o.dest,
4330+ Path: o.path,
4331+ Method: method,
4332+ Args: args,
4333+ Done: ch,
4334+ }
4335+ o.conn.callsLck.Lock()
4336+ o.conn.calls[msg.serial] = call
4337+ o.conn.callsLck.Unlock()
4338+ o.conn.outLck.RLock()
4339+ if o.conn.closed {
4340+ call.Err = ErrClosed
4341+ call.Done <- call
4342+ } else {
4343+ o.conn.out <- msg
4344+ }
4345+ o.conn.outLck.RUnlock()
4346+ return call
4347+ }
4348+ o.conn.outLck.RLock()
4349+ defer o.conn.outLck.RUnlock()
4350+ if o.conn.closed {
4351+ return &Call{Err: ErrClosed}
4352+ }
4353+ o.conn.out <- msg
4354+ return &Call{Err: nil}
4355+}
4356+
4357+// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given
4358+// object. The property name must be given in interface.member notation.
4359+func (o *Object) GetProperty(p string) (Variant, error) {
4360+ idx := strings.LastIndex(p, ".")
4361+ if idx == -1 || idx+1 == len(p) {
4362+ return Variant{}, errors.New("dbus: invalid property " + p)
4363+ }
4364+
4365+ iface := p[:idx]
4366+ prop := p[idx+1:]
4367+
4368+ result := Variant{}
4369+ err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result)
4370+
4371+ if err != nil {
4372+ return Variant{}, err
4373+ }
4374+
4375+ return result, nil
4376+}
4377+
4378+// Destination returns the destination that calls on o are sent to.
4379+func (o *Object) Destination() string {
4380+ return o.dest
4381+}
4382+
4383+// Path returns the path that calls on o are sent to.
4384+func (o *Object) Path() ObjectPath {
4385+ return o.path
4386+}
4387
4388=== added directory 'service-ng/src/github.com/godbus/dbus/prop'
4389=== added file 'service-ng/src/github.com/godbus/dbus/prop/prop.go'
4390--- service-ng/src/github.com/godbus/dbus/prop/prop.go 1970-01-01 00:00:00 +0000
4391+++ service-ng/src/github.com/godbus/dbus/prop/prop.go 2015-09-03 16:43:03 +0000
4392@@ -0,0 +1,264 @@
4393+// Package prop provides the Properties struct which can be used to implement
4394+// org.freedesktop.DBus.Properties.
4395+package prop
4396+
4397+import (
4398+ "github.com/godbus/dbus"
4399+ "github.com/godbus/dbus/introspect"
4400+ "sync"
4401+)
4402+
4403+// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is
4404+// emitted for a property. If it is EmitTrue, the signal is emitted. If it is
4405+// EmitInvalidates, the signal is also emitted, but the new value of the property
4406+// is not disclosed.
4407+type EmitType byte
4408+
4409+const (
4410+ EmitFalse EmitType = iota
4411+ EmitTrue
4412+ EmitInvalidates
4413+)
4414+
4415+// ErrIfaceNotFound is the error returned to peers who try to access properties
4416+// on interfaces that aren't found.
4417+var ErrIfaceNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil)
4418+
4419+// ErrPropNotFound is the error returned to peers trying to access properties
4420+// that aren't found.
4421+var ErrPropNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil)
4422+
4423+// ErrReadOnly is the error returned to peers trying to set a read-only
4424+// property.
4425+var ErrReadOnly = dbus.NewError("org.freedesktop.DBus.Properties.Error.ReadOnly", nil)
4426+
4427+// ErrInvalidArg is returned to peers if the type of the property that is being
4428+// changed and the argument don't match.
4429+var ErrInvalidArg = dbus.NewError("org.freedesktop.DBus.Properties.Error.InvalidArg", nil)
4430+
4431+// The introspection data for the org.freedesktop.DBus.Properties interface.
4432+var IntrospectData = introspect.Interface{
4433+ Name: "org.freedesktop.DBus.Properties",
4434+ Methods: []introspect.Method{
4435+ {
4436+ Name: "Get",
4437+ Args: []introspect.Arg{
4438+ {"interface", "s", "in"},
4439+ {"property", "s", "in"},
4440+ {"value", "v", "out"},
4441+ },
4442+ },
4443+ {
4444+ Name: "GetAll",
4445+ Args: []introspect.Arg{
4446+ {"interface", "s", "in"},
4447+ {"props", "a{sv}", "out"},
4448+ },
4449+ },
4450+ {
4451+ Name: "Set",
4452+ Args: []introspect.Arg{
4453+ {"interface", "s", "in"},
4454+ {"property", "s", "in"},
4455+ {"value", "v", "in"},
4456+ },
4457+ },
4458+ },
4459+ Signals: []introspect.Signal{
4460+ {
4461+ Name: "PropertiesChanged",
4462+ Args: []introspect.Arg{
4463+ {"interface", "s", "out"},
4464+ {"changed_properties", "a{sv}", "out"},
4465+ {"invalidates_properties", "as", "out"},
4466+ },
4467+ },
4468+ },
4469+}
4470+
4471+// The introspection data for the org.freedesktop.DBus.Properties interface, as
4472+// a string.
4473+const IntrospectDataString = `
4474+ <interface name="org.freedesktop.DBus.Introspectable">
4475+ <method name="Get">
4476+ <arg name="interface" direction="in" type="s"/>
4477+ <arg name="property" direction="in" type="s"/>
4478+ <arg name="value" direction="out" type="v"/>
4479+ </method>
4480+ <method name="GetAll">
4481+ <arg name="interface" direction="in" type="s"/>
4482+ <arg name="props" direction="out" type="a{sv}"/>
4483+ </method>
4484+ <method name="Set">
4485+ <arg name="interface" direction="in" type="s"/>
4486+ <arg name="property" direction="in" type="s"/>
4487+ <arg name="value" direction="in" type="v"/>
4488+ </method>
4489+ <signal name="PropertiesChanged">
4490+ <arg name="interface" type="s"/>
4491+ <arg name="changed_properties" type="a{sv}"/>
4492+ <arg name="invalidates_properties" type="as"/>
4493+ </signal>
4494+ </interface>
4495+`
4496+
4497+// Prop represents a single property. It is used for creating a Properties
4498+// value.
4499+type Prop struct {
4500+ // Initial value. Must be a DBus-representable type.
4501+ Value interface{}
4502+
4503+ // If true, the value can be modified by calls to Set.
4504+ Writable bool
4505+
4506+ // Controls how org.freedesktop.DBus.Properties.PropertiesChanged is
4507+ // emitted if this property changes.
4508+ Emit EmitType
4509+
4510+ // If not nil, anytime this property is changed by Set, this function is
4511+ // called with an appropiate Change as its argument. If the returned error
4512+ // is not nil, it is sent back to the caller of Set and the property is not
4513+ // changed.
4514+ Callback func(*Change) *dbus.Error
4515+}
4516+
4517+// Change represents a change of a property by a call to Set.
4518+type Change struct {
4519+ Props *Properties
4520+ Iface string
4521+ Name string
4522+ Value interface{}
4523+}
4524+
4525+// Properties is a set of values that can be made available to the message bus
4526+// using the org.freedesktop.DBus.Properties interface. It is safe for
4527+// concurrent use by multiple goroutines.
4528+type Properties struct {
4529+ m map[string]map[string]*Prop
4530+ mut sync.RWMutex
4531+ conn *dbus.Conn
4532+ path dbus.ObjectPath
4533+}
4534+
4535+// New returns a new Properties structure that manages the given properties.
4536+// The key for the first-level map of props is the name of the interface; the
4537+// second-level key is the name of the property. The returned structure will be
4538+// exported as org.freedesktop.DBus.Properties on path.
4539+func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties {
4540+ p := &Properties{m: props, conn: conn, path: path}
4541+ conn.Export(p, path, "org.freedesktop.DBus.Properties")
4542+ return p
4543+}
4544+
4545+// Get implements org.freedesktop.DBus.Properties.Get.
4546+func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) {
4547+ p.mut.RLock()
4548+ defer p.mut.RUnlock()
4549+ m, ok := p.m[iface]
4550+ if !ok {
4551+ return dbus.Variant{}, ErrIfaceNotFound
4552+ }
4553+ prop, ok := m[property]
4554+ if !ok {
4555+ return dbus.Variant{}, ErrPropNotFound
4556+ }
4557+ return dbus.MakeVariant(prop.Value), nil
4558+}
4559+
4560+// GetAll implements org.freedesktop.DBus.Properties.GetAll.
4561+func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) {
4562+ p.mut.RLock()
4563+ defer p.mut.RUnlock()
4564+ m, ok := p.m[iface]
4565+ if !ok {
4566+ return nil, ErrIfaceNotFound
4567+ }
4568+ rm := make(map[string]dbus.Variant, len(m))
4569+ for k, v := range m {
4570+ rm[k] = dbus.MakeVariant(v.Value)
4571+ }
4572+ return rm, nil
4573+}
4574+
4575+// GetMust returns the value of the given property and panics if either the
4576+// interface or the property name are invalid.
4577+func (p *Properties) GetMust(iface, property string) interface{} {
4578+ p.mut.RLock()
4579+ defer p.mut.RUnlock()
4580+ return p.m[iface][property].Value
4581+}
4582+
4583+// Introspection returns the introspection data that represents the properties
4584+// of iface.
4585+func (p *Properties) Introspection(iface string) []introspect.Property {
4586+ p.mut.RLock()
4587+ defer p.mut.RUnlock()
4588+ m := p.m[iface]
4589+ s := make([]introspect.Property, 0, len(m))
4590+ for k, v := range m {
4591+ p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()}
4592+ if v.Writable {
4593+ p.Access = "readwrite"
4594+ } else {
4595+ p.Access = "read"
4596+ }
4597+ s = append(s, p)
4598+ }
4599+ return s
4600+}
4601+
4602+// set sets the given property and emits PropertyChanged if appropiate. p.mut
4603+// must already be locked.
4604+func (p *Properties) set(iface, property string, v interface{}) {
4605+ prop := p.m[iface][property]
4606+ prop.Value = v
4607+ switch prop.Emit {
4608+ case EmitFalse:
4609+ // do nothing
4610+ case EmitInvalidates:
4611+ p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
4612+ iface, map[string]dbus.Variant{}, []string{property})
4613+ case EmitTrue:
4614+ p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
4615+ iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)},
4616+ []string{})
4617+ default:
4618+ panic("invalid value for EmitType")
4619+ }
4620+}
4621+
4622+// Set implements org.freedesktop.Properties.Set.
4623+func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error {
4624+ p.mut.Lock()
4625+ defer p.mut.Unlock()
4626+ m, ok := p.m[iface]
4627+ if !ok {
4628+ return ErrIfaceNotFound
4629+ }
4630+ prop, ok := m[property]
4631+ if !ok {
4632+ return ErrPropNotFound
4633+ }
4634+ if !prop.Writable {
4635+ return ErrReadOnly
4636+ }
4637+ if newv.Signature() != dbus.SignatureOf(prop.Value) {
4638+ return ErrInvalidArg
4639+ }
4640+ if prop.Callback != nil {
4641+ err := prop.Callback(&Change{p, iface, property, newv.Value()})
4642+ if err != nil {
4643+ return err
4644+ }
4645+ }
4646+ p.set(iface, property, newv.Value())
4647+ return nil
4648+}
4649+
4650+// SetMust sets the value of the given property and panics if the interface or
4651+// the property name are invalid.
4652+func (p *Properties) SetMust(iface, property string, v interface{}) {
4653+ p.mut.Lock()
4654+ p.set(iface, property, v)
4655+ p.mut.Unlock()
4656+}
4657
4658=== added file 'service-ng/src/github.com/godbus/dbus/proto_test.go'
4659--- service-ng/src/github.com/godbus/dbus/proto_test.go 1970-01-01 00:00:00 +0000
4660+++ service-ng/src/github.com/godbus/dbus/proto_test.go 2015-09-03 16:43:03 +0000
4661@@ -0,0 +1,369 @@
4662+package dbus
4663+
4664+import (
4665+ "bytes"
4666+ "encoding/binary"
4667+ "io/ioutil"
4668+ "math"
4669+ "reflect"
4670+ "testing"
4671+)
4672+
4673+var protoTests = []struct {
4674+ vs []interface{}
4675+ bigEndian []byte
4676+ littleEndian []byte
4677+}{
4678+ {
4679+ []interface{}{int32(0)},
4680+ []byte{0, 0, 0, 0},
4681+ []byte{0, 0, 0, 0},
4682+ },
4683+ {
4684+ []interface{}{true, false},
4685+ []byte{0, 0, 0, 1, 0, 0, 0, 0},
4686+ []byte{1, 0, 0, 0, 0, 0, 0, 0},
4687+ },
4688+ {
4689+ []interface{}{byte(0), uint16(12), int16(32), uint32(43)},
4690+ []byte{0, 0, 0, 12, 0, 32, 0, 0, 0, 0, 0, 43},
4691+ []byte{0, 0, 12, 0, 32, 0, 0, 0, 43, 0, 0, 0},
4692+ },
4693+ {
4694+ []interface{}{int64(-1), uint64(1<<64 - 1)},
4695+ bytes.Repeat([]byte{255}, 16),
4696+ bytes.Repeat([]byte{255}, 16),
4697+ },
4698+ {
4699+ []interface{}{math.Inf(+1)},
4700+ []byte{0x7f, 0xf0, 0, 0, 0, 0, 0, 0},
4701+ []byte{0, 0, 0, 0, 0, 0, 0xf0, 0x7f},
4702+ },
4703+ {
4704+ []interface{}{"foo"},
4705+ []byte{0, 0, 0, 3, 'f', 'o', 'o', 0},
4706+ []byte{3, 0, 0, 0, 'f', 'o', 'o', 0},
4707+ },
4708+ {
4709+ []interface{}{Signature{"ai"}},
4710+ []byte{2, 'a', 'i', 0},
4711+ []byte{2, 'a', 'i', 0},
4712+ },
4713+ {
4714+ []interface{}{[]int16{42, 256}},
4715+ []byte{0, 0, 0, 4, 0, 42, 1, 0},
4716+ []byte{4, 0, 0, 0, 42, 0, 0, 1},
4717+ },
4718+ {
4719+ []interface{}{MakeVariant("foo")},
4720+ []byte{1, 's', 0, 0, 0, 0, 0, 3, 'f', 'o', 'o', 0},
4721+ []byte{1, 's', 0, 0, 3, 0, 0, 0, 'f', 'o', 'o', 0},
4722+ },
4723+ {
4724+ []interface{}{MakeVariant(MakeVariant(Signature{"v"}))},
4725+ []byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0},
4726+ []byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0},
4727+ },
4728+ {
4729+ []interface{}{map[int32]bool{42: true}},
4730+ []byte{0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1},
4731+ []byte{8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1, 0, 0, 0},
4732+ },
4733+ {
4734+ []interface{}{map[string]Variant{}, byte(42)},
4735+ []byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
4736+ []byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
4737+ },
4738+ {
4739+ []interface{}{[]uint64{}, byte(42)},
4740+ []byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
4741+ []byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
4742+ },
4743+}
4744+
4745+func TestProto(t *testing.T) {
4746+ for i, v := range protoTests {
4747+ buf := new(bytes.Buffer)
4748+ bigEnc := newEncoder(buf, binary.BigEndian)
4749+ bigEnc.Encode(v.vs...)
4750+ marshalled := buf.Bytes()
4751+ if bytes.Compare(marshalled, v.bigEndian) != 0 {
4752+ t.Errorf("test %d (marshal be): got '%v', but expected '%v'\n", i+1, marshalled,
4753+ v.bigEndian)
4754+ }
4755+ buf.Reset()
4756+ litEnc := newEncoder(buf, binary.LittleEndian)
4757+ litEnc.Encode(v.vs...)
4758+ marshalled = buf.Bytes()
4759+ if bytes.Compare(marshalled, v.littleEndian) != 0 {
4760+ t.Errorf("test %d (marshal le): got '%v', but expected '%v'\n", i+1, marshalled,
4761+ v.littleEndian)
4762+ }
4763+ unmarshalled := reflect.MakeSlice(reflect.TypeOf(v.vs),
4764+ 0, 0)
4765+ for i := range v.vs {
4766+ unmarshalled = reflect.Append(unmarshalled,
4767+ reflect.New(reflect.TypeOf(v.vs[i])))
4768+ }
4769+ bigDec := newDecoder(bytes.NewReader(v.bigEndian), binary.BigEndian)
4770+ vs, err := bigDec.Decode(SignatureOf(v.vs...))
4771+ if err != nil {
4772+ t.Errorf("test %d (unmarshal be): %s\n", i+1, err)
4773+ continue
4774+ }
4775+ if !reflect.DeepEqual(vs, v.vs) {
4776+ t.Errorf("test %d (unmarshal be): got %#v, but expected %#v\n", i+1, vs, v.vs)
4777+ }
4778+ litDec := newDecoder(bytes.NewReader(v.littleEndian), binary.LittleEndian)
4779+ vs, err = litDec.Decode(SignatureOf(v.vs...))
4780+ if err != nil {
4781+ t.Errorf("test %d (unmarshal le): %s\n", i+1, err)
4782+ continue
4783+ }
4784+ if !reflect.DeepEqual(vs, v.vs) {
4785+ t.Errorf("test %d (unmarshal le): got %#v, but expected %#v\n", i+1, vs, v.vs)
4786+ }
4787+
4788+ }
4789+}
4790+
4791+func TestProtoMap(t *testing.T) {
4792+ m := map[string]uint8{
4793+ "foo": 23,
4794+ "bar": 2,
4795+ }
4796+ var n map[string]uint8
4797+ buf := new(bytes.Buffer)
4798+ enc := newEncoder(buf, binary.LittleEndian)
4799+ enc.Encode(m)
4800+ dec := newDecoder(buf, binary.LittleEndian)
4801+ vs, err := dec.Decode(Signature{"a{sy}"})
4802+ if err != nil {
4803+ t.Fatal(err)
4804+ }
4805+ if err = Store(vs, &n); err != nil {
4806+ t.Fatal(err)
4807+ }
4808+ if len(n) != 2 || n["foo"] != 23 || n["bar"] != 2 {
4809+ t.Error("got", n)
4810+ }
4811+}
4812+
4813+func TestProtoVariantStruct(t *testing.T) {
4814+ var variant Variant
4815+ v := MakeVariant(struct {
4816+ A int32
4817+ B int16
4818+ }{1, 2})
4819+ buf := new(bytes.Buffer)
4820+ enc := newEncoder(buf, binary.LittleEndian)
4821+ enc.Encode(v)
4822+ dec := newDecoder(buf, binary.LittleEndian)
4823+ vs, err := dec.Decode(Signature{"v"})
4824+ if err != nil {
4825+ t.Fatal(err)
4826+ }
4827+ if err = Store(vs, &variant); err != nil {
4828+ t.Fatal(err)
4829+ }
4830+ sl := variant.Value().([]interface{})
4831+ v1, v2 := sl[0].(int32), sl[1].(int16)
4832+ if v1 != int32(1) {
4833+ t.Error("got", v1, "as first int")
4834+ }
4835+ if v2 != int16(2) {
4836+ t.Error("got", v2, "as second int")
4837+ }
4838+}
4839+
4840+func TestProtoStructTag(t *testing.T) {
4841+ type Bar struct {
4842+ A int32
4843+ B chan interface{} `dbus:"-"`
4844+ C int32
4845+ }
4846+ var bar1, bar2 Bar
4847+ bar1.A = 234
4848+ bar2.C = 345
4849+ buf := new(bytes.Buffer)
4850+ enc := newEncoder(buf, binary.LittleEndian)
4851+ enc.Encode(bar1)
4852+ dec := newDecoder(buf, binary.LittleEndian)
4853+ vs, err := dec.Decode(Signature{"(ii)"})
4854+ if err != nil {
4855+ t.Fatal(err)
4856+ }
4857+ if err = Store(vs, &bar2); err != nil {
4858+ t.Fatal(err)
4859+ }
4860+ if bar1 != bar2 {
4861+ t.Error("struct tag test: got", bar2)
4862+ }
4863+}
4864+
4865+func TestProtoStoreStruct(t *testing.T) {
4866+ var foo struct {
4867+ A int32
4868+ B string
4869+ c chan interface{}
4870+ D interface{} `dbus:"-"`
4871+ }
4872+ src := []interface{}{[]interface{}{int32(42), "foo"}}
4873+ err := Store(src, &foo)
4874+ if err != nil {
4875+ t.Fatal(err)
4876+ }
4877+}
4878+
4879+func TestProtoStoreNestedStruct(t *testing.T) {
4880+ var foo struct {
4881+ A int32
4882+ B struct {
4883+ C string
4884+ D float64
4885+ }
4886+ }
4887+ src := []interface{}{
4888+ []interface{}{
4889+ int32(42),
4890+ []interface{}{
4891+ "foo",
4892+ 3.14,
4893+ },
4894+ },
4895+ }
4896+ err := Store(src, &foo)
4897+ if err != nil {
4898+ t.Fatal(err)
4899+ }
4900+}
4901+
4902+func TestMessage(t *testing.T) {
4903+ buf := new(bytes.Buffer)
4904+ message := new(Message)
4905+ message.Type = TypeMethodCall
4906+ message.serial = 32
4907+ message.Headers = map[HeaderField]Variant{
4908+ FieldPath: MakeVariant(ObjectPath("/org/foo/bar")),
4909+ FieldMember: MakeVariant("baz"),
4910+ }
4911+ message.Body = make([]interface{}, 0)
4912+ err := message.EncodeTo(buf, binary.LittleEndian)
4913+ if err != nil {
4914+ t.Error(err)
4915+ }
4916+ _, err = DecodeMessage(buf)
4917+ if err != nil {
4918+ t.Error(err)
4919+ }
4920+}
4921+
4922+func TestProtoStructInterfaces(t *testing.T) {
4923+ b := []byte{42}
4924+ vs, err := newDecoder(bytes.NewReader(b), binary.LittleEndian).Decode(Signature{"(y)"})
4925+ if err != nil {
4926+ t.Fatal(err)
4927+ }
4928+ if vs[0].([]interface{})[0].(byte) != 42 {
4929+ t.Errorf("wrongs results (got %v)", vs)
4930+ }
4931+}
4932+
4933+// ordinary org.freedesktop.DBus.Hello call
4934+var smallMessage = &Message{
4935+ Type: TypeMethodCall,
4936+ serial: 1,
4937+ Headers: map[HeaderField]Variant{
4938+ FieldDestination: MakeVariant("org.freedesktop.DBus"),
4939+ FieldPath: MakeVariant(ObjectPath("/org/freedesktop/DBus")),
4940+ FieldInterface: MakeVariant("org.freedesktop.DBus"),
4941+ FieldMember: MakeVariant("Hello"),
4942+ },
4943+}
4944+
4945+// org.freedesktop.Notifications.Notify
4946+var bigMessage = &Message{
4947+ Type: TypeMethodCall,
4948+ serial: 2,
4949+ Headers: map[HeaderField]Variant{
4950+ FieldDestination: MakeVariant("org.freedesktop.Notifications"),
4951+ FieldPath: MakeVariant(ObjectPath("/org/freedesktop/Notifications")),
4952+ FieldInterface: MakeVariant("org.freedesktop.Notifications"),
4953+ FieldMember: MakeVariant("Notify"),
4954+ FieldSignature: MakeVariant(Signature{"susssasa{sv}i"}),
4955+ },
4956+ Body: []interface{}{
4957+ "app_name",
4958+ uint32(0),
4959+ "dialog-information",
4960+ "Notification",
4961+ "This is the body of a notification",
4962+ []string{"ok", "Ok"},
4963+ map[string]Variant{
4964+ "sound-name": MakeVariant("dialog-information"),
4965+ },
4966+ int32(-1),
4967+ },
4968+}
4969+
4970+func BenchmarkDecodeMessageSmall(b *testing.B) {
4971+ var err error
4972+ var rd *bytes.Reader
4973+
4974+ b.StopTimer()
4975+ buf := new(bytes.Buffer)
4976+ err = smallMessage.EncodeTo(buf, binary.LittleEndian)
4977+ if err != nil {
4978+ b.Fatal(err)
4979+ }
4980+ decoded := buf.Bytes()
4981+ b.StartTimer()
4982+ for i := 0; i < b.N; i++ {
4983+ rd = bytes.NewReader(decoded)
4984+ _, err = DecodeMessage(rd)
4985+ if err != nil {
4986+ b.Fatal(err)
4987+ }
4988+ }
4989+}
4990+
4991+func BenchmarkDecodeMessageBig(b *testing.B) {
4992+ var err error
4993+ var rd *bytes.Reader
4994+
4995+ b.StopTimer()
4996+ buf := new(bytes.Buffer)
4997+ err = bigMessage.EncodeTo(buf, binary.LittleEndian)
4998+ if err != nil {
4999+ b.Fatal(err)
5000+ }
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: