Merge lp:~dobey/pay-service/initial-iap into lp:pay-service/15.04
- initial-iap
- Merge into trunk.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 |
Related bugs: |
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.
Description of the change
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.
PASSED: Continuous integration, rev:52 jenkins. qa.ubuntu. com/job/ pay-service- 15.04-ci/ 6/ jenkins. qa.ubuntu. com/job/ pay-service- 15.04-vivid- amd64-ci/ 6 jenkins. qa.ubuntu. com/job/ pay-service- 15.04-vivid- armhf-ci/ 6 jenkins. qa.ubuntu. com/job/ pay-service- 15.04-vivid- armhf-ci/ 6/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/pay- service- 15.04-ci/ 6/rebuild
http://