]> git.feebdaed.xyz Git - 0xmirror/cilium.git/commitdiff
go.mod: upgrade godbus/dbus to latest release
authorDimitri John Ledkov <dimitri.ledkov@surgut.co.uk>
Tue, 9 Dec 2025 22:31:31 +0000 (22:31 +0000)
committerAndré Martins <aanm@users.noreply.github.com>
Thu, 18 Dec 2025 12:13:30 +0000 (12:13 +0000)
It has many improvements and drops needless usage of crypto/sha1 on
unix like platfroms.

Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@surgut.co.uk>
37 files changed:
go.mod
go.sum
vendor/github.com/godbus/dbus/v5/.cirrus.yml [new file with mode: 0644]
vendor/github.com/godbus/dbus/v5/.golangci.yml [new file with mode: 0644]
vendor/github.com/godbus/dbus/v5/README.md
vendor/github.com/godbus/dbus/v5/SECURITY.md [new file with mode: 0644]
vendor/github.com/godbus/dbus/v5/auth.go
vendor/github.com/godbus/dbus/v5/auth_default_other.go [new file with mode: 0644]
vendor/github.com/godbus/dbus/v5/auth_default_windows.go [new file with mode: 0644]
vendor/github.com/godbus/dbus/v5/auth_sha1.go [deleted file]
vendor/github.com/godbus/dbus/v5/auth_sha1_windows.go [new file with mode: 0644]
vendor/github.com/godbus/dbus/v5/call.go
vendor/github.com/godbus/dbus/v5/conn.go
vendor/github.com/godbus/dbus/v5/conn_darwin.go
vendor/github.com/godbus/dbus/v5/conn_other.go
vendor/github.com/godbus/dbus/v5/conn_unix.go
vendor/github.com/godbus/dbus/v5/conn_windows.go
vendor/github.com/godbus/dbus/v5/dbus.go
vendor/github.com/godbus/dbus/v5/decoder.go
vendor/github.com/godbus/dbus/v5/default_handler.go
vendor/github.com/godbus/dbus/v5/doc.go
vendor/github.com/godbus/dbus/v5/encoder.go
vendor/github.com/godbus/dbus/v5/export.go
vendor/github.com/godbus/dbus/v5/homedir.go [deleted file]
vendor/github.com/godbus/dbus/v5/match.go
vendor/github.com/godbus/dbus/v5/message.go
vendor/github.com/godbus/dbus/v5/object.go
vendor/github.com/godbus/dbus/v5/sequential_handler.go
vendor/github.com/godbus/dbus/v5/server_interfaces.go
vendor/github.com/godbus/dbus/v5/sig.go
vendor/github.com/godbus/dbus/v5/transport_nonce_tcp.go
vendor/github.com/godbus/dbus/v5/transport_unix.go
vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go
vendor/github.com/godbus/dbus/v5/variant.go
vendor/github.com/godbus/dbus/v5/variant_lexer.go
vendor/github.com/godbus/dbus/v5/variant_parser.go
vendor/modules.txt

diff --git a/go.mod b/go.mod
index 8518a2b2af6f76340e81186f7b7358c9f5220100..f2202ba60e9309920f1aa6dcb818ebcf60a3e311 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -216,7 +216,7 @@ require (
        github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
        github.com/gobuffalo/flect v1.0.3 // indirect
        github.com/gobwas/glob v0.2.3 // indirect
-       github.com/godbus/dbus/v5 v5.1.0 // indirect
+       github.com/godbus/dbus/v5 v5.2.0 // indirect
        github.com/gogo/protobuf v1.3.2 // indirect
        github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
        github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
diff --git a/go.sum b/go.sum
index 67773b3a55a0a47af0b12791e6a6d692002b7496..9b4fec2aee5596647baabf6e66dac4bc354c0068 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -320,8 +320,8 @@ github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4
 github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
-github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
+github.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
diff --git a/vendor/github.com/godbus/dbus/v5/.cirrus.yml b/vendor/github.com/godbus/dbus/v5/.cirrus.yml
new file mode 100644 (file)
index 0000000..0c9b365
--- /dev/null
@@ -0,0 +1,11 @@
+# See https://cirrus-ci.org/guide/FreeBSD/
+freebsd_instance:
+  image_family: freebsd-14-2
+
+task:
+  name: Test on FreeBSD
+  install_script: pkg install -y go122 dbus
+  test_script: |
+    /usr/local/etc/rc.d/dbus onestart && \
+    eval `dbus-launch --sh-syntax` && \
+    go122 test -v ./...
diff --git a/vendor/github.com/godbus/dbus/v5/.golangci.yml b/vendor/github.com/godbus/dbus/v5/.golangci.yml
new file mode 100644 (file)
index 0000000..f2d7910
--- /dev/null
@@ -0,0 +1,7 @@
+# For documentation, see https://golangci-lint.run/usage/configuration/
+
+linters:
+  enable:
+    - gofumpt
+    - unconvert
+    - unparam
index 5c24125838d267642f6cbde4f1c96c6ca3a1efa2..da848a98dc338656705058fc3bb471c6fc76f5cb 100644 (file)
@@ -14,7 +14,7 @@ D-Bus message bus system.
 
 ### Installation
 
-This packages requires Go 1.12 or later. It can be installed by running the command below:
+This packages requires Go 1.20 or later. It can be installed by running the command below:
 
 ```
 go get github.com/godbus/dbus/v5
@@ -23,7 +23,7 @@ go get github.com/godbus/dbus/v5
 ### Usage
 
 The complete package documentation and some simple examples are available at
-[godoc.org](http://godoc.org/github.com/godbus/dbus). Also, the
+[pkg.go.dev](https://pkg.go.dev/github.com/godbus/dbus/v5). Also, the
 [_examples](https://github.com/godbus/dbus/tree/master/_examples) directory
 gives a short overview over the basic usage. 
 
@@ -34,6 +34,7 @@ gives a short overview over the basic usage.
 - [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
 - [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
 - [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
+- [rpic](https://github.com/stephenhu/rpic) lightweight web app and RESTful API for managing a Raspberry Pi
 
 Please note that the API is considered unstable for now and may change without
 further notice.
diff --git a/vendor/github.com/godbus/dbus/v5/SECURITY.md b/vendor/github.com/godbus/dbus/v5/SECURITY.md
new file mode 100644 (file)
index 0000000..7d262fb
--- /dev/null
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Supported Versions
+
+Security updates are applied only to the latest release.
+
+## Reporting a Vulnerability
+
+If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
+
+Please disclose it at [security advisory](https://github.com/godbus/dbus/security/advisories/new).
+
+This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base.
index 0f3b252c070f7ff93c4044f3c20ad40e2e1a45c3..5924690b85549082f2756d43ea4c4fc43882fad9 100644 (file)
@@ -54,7 +54,7 @@ type Auth interface {
 func (conn *Conn) Auth(methods []Auth) error {
        if methods == nil {
                uid := strconv.Itoa(os.Geteuid())
-               methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
+               methods = getDefaultAuthMethods(uid)
        }
        in := bufio.NewReader(conn.transport)
        err := conn.transport.SendNullByte()
@@ -83,9 +83,9 @@ func (conn *Conn) Auth(methods []Auth) error {
                                }
                                switch status {
                                case AuthOk:
-                                       err, ok = conn.tryAuth(m, waitingForOk, in)
+                                       ok, err = conn.tryAuth(m, waitingForOk, in)
                                case AuthContinue:
-                                       err, ok = conn.tryAuth(m, waitingForData, in)
+                                       ok, err = conn.tryAuth(m, waitingForData, in)
                                default:
                                        panic("dbus: invalid authentication status")
                                }
@@ -125,21 +125,21 @@ func (conn *Conn) Auth(methods []Auth) error {
 }
 
 // tryAuth tries to authenticate with m as the mechanism, using state as the
-// initial authState and in for reading input. It returns (nil, true) on
-// success, (nil, false) on a REJECTED and (someErr, false) if some other
+// initial authState and in for reading input. It returns (true, nil) on
+// success, (false, nil) on a REJECTED and (false, someErr) if some other
 // error occurred.
-func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) {
+func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (bool, error) {
        for {
                s, err := authReadLine(in)
                if err != nil {
-                       return err, false
+                       return false, err
                }
                switch {
                case state == waitingForData && string(s[0]) == "DATA":
                        if len(s) != 2 {
                                err = authWriteLine(conn.transport, []byte("ERROR"))
                                if err != nil {
-                                       return err, false
+                                       return false, err
                                }
                                continue
                        }
@@ -149,7 +149,7 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo
                                if len(data) != 0 {
                                        err = authWriteLine(conn.transport, []byte("DATA"), data)
                                        if err != nil {
-                                               return err, false
+                                               return false, err
                                        }
                                }
                                if status == AuthOk {
@@ -158,66 +158,66 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo
                        case AuthError:
                                err = authWriteLine(conn.transport, []byte("ERROR"))
                                if err != nil {
-                                       return err, false
+                                       return false, err
                                }
                        }
                case state == waitingForData && string(s[0]) == "REJECTED":
-                       return nil, false
+                       return false, nil
                case state == waitingForData && string(s[0]) == "ERROR":
                        err = authWriteLine(conn.transport, []byte("CANCEL"))
                        if err != nil {
-                               return err, false
+                               return false, err
                        }
                        state = waitingForReject
                case state == waitingForData && string(s[0]) == "OK":
                        if len(s) != 2 {
                                err = authWriteLine(conn.transport, []byte("CANCEL"))
                                if err != nil {
-                                       return err, false
+                                       return false, err
                                }
                                state = waitingForReject
                        } else {
                                conn.uuid = string(s[1])
-                               return nil, true
+                               return true, nil
                        }
                case state == waitingForData:
                        err = authWriteLine(conn.transport, []byte("ERROR"))
                        if err != nil {
-                               return err, false
+                               return false, err
                        }
                case state == waitingForOk && string(s[0]) == "OK":
                        if len(s) != 2 {
                                err = authWriteLine(conn.transport, []byte("CANCEL"))
                                if err != nil {
-                                       return err, false
+                                       return false, err
                                }
                                state = waitingForReject
                        } else {
                                conn.uuid = string(s[1])
-                               return nil, true
+                               return true, nil
                        }
                case state == waitingForOk && string(s[0]) == "DATA":
                        err = authWriteLine(conn.transport, []byte("DATA"))
                        if err != nil {
-                               return err, false
+                               return false, nil
                        }
                case state == waitingForOk && string(s[0]) == "REJECTED":
-                       return nil, false
+                       return false, nil
                case state == waitingForOk && string(s[0]) == "ERROR":
                        err = authWriteLine(conn.transport, []byte("CANCEL"))
                        if err != nil {
-                               return err, false
+                               return false, err
                        }
                        state = waitingForReject
                case state == waitingForOk:
                        err = authWriteLine(conn.transport, []byte("ERROR"))
                        if err != nil {
-                               return err, false
+                               return false, err
                        }
                case state == waitingForReject && string(s[0]) == "REJECTED":
-                       return nil, false
+                       return false, nil
                case state == waitingForReject:
-                       return errors.New("dbus: authentication protocol error"), false
+                       return false, errors.New("dbus: authentication protocol error")
                default:
                        panic("dbus: invalid auth state")
                }
diff --git a/vendor/github.com/godbus/dbus/v5/auth_default_other.go b/vendor/github.com/godbus/dbus/v5/auth_default_other.go
new file mode 100644 (file)
index 0000000..64c911d
--- /dev/null
@@ -0,0 +1,8 @@
+//go:build !windows
+// +build !windows
+
+package dbus
+
+func getDefaultAuthMethods(user string) []Auth {
+       return []Auth{AuthExternal(user)}
+}
diff --git a/vendor/github.com/godbus/dbus/v5/auth_default_windows.go b/vendor/github.com/godbus/dbus/v5/auth_default_windows.go
new file mode 100644 (file)
index 0000000..2289850
--- /dev/null
@@ -0,0 +1,5 @@
+package dbus
+
+func getDefaultAuthMethods(user string) []Auth {
+       return []Auth{AuthCookieSha1(user, getHomeDir())}
+}
diff --git a/vendor/github.com/godbus/dbus/v5/auth_sha1.go b/vendor/github.com/godbus/dbus/v5/auth_sha1.go
deleted file mode 100644 (file)
index 8028670..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-package dbus
-
-import (
-       "bufio"
-       "bytes"
-       "crypto/rand"
-       "crypto/sha1"
-       "encoding/hex"
-       "os"
-)
-
-// AuthCookieSha1 returns an Auth that authenticates as the given user with the
-// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home
-// directory of the user.
-func AuthCookieSha1(user, home string) Auth {
-       return authCookieSha1{user, home}
-}
-
-type authCookieSha1 struct {
-       user, home string
-}
-
-func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) {
-       b := make([]byte, 2*len(a.user))
-       hex.Encode(b, []byte(a.user))
-       return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue
-}
-
-func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
-       challenge := make([]byte, len(data)/2)
-       _, err := hex.Decode(challenge, data)
-       if err != nil {
-               return nil, AuthError
-       }
-       b := bytes.Split(challenge, []byte{' '})
-       if len(b) != 3 {
-               return nil, AuthError
-       }
-       context := b[0]
-       id := b[1]
-       svchallenge := b[2]
-       cookie := a.getCookie(context, id)
-       if cookie == nil {
-               return nil, AuthError
-       }
-       clchallenge := a.generateChallenge()
-       if clchallenge == nil {
-               return nil, AuthError
-       }
-       hash := sha1.New()
-       hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'}))
-       hexhash := make([]byte, 2*hash.Size())
-       hex.Encode(hexhash, hash.Sum(nil))
-       data = append(clchallenge, ' ')
-       data = append(data, hexhash...)
-       resp := make([]byte, 2*len(data))
-       hex.Encode(resp, data)
-       return resp, AuthOk
-}
-
-// getCookie searches for the cookie identified by id in context and returns
-// the cookie content or nil. (Since HandleData can't return a specific error,
-// but only whether an error occurred, this function also doesn't bother to
-// return an error.)
-func (a authCookieSha1) getCookie(context, id []byte) []byte {
-       file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
-       if err != nil {
-               return nil
-       }
-       defer file.Close()
-       rd := bufio.NewReader(file)
-       for {
-               line, err := rd.ReadBytes('\n')
-               if err != nil {
-                       return nil
-               }
-               line = line[:len(line)-1]
-               b := bytes.Split(line, []byte{' '})
-               if len(b) != 3 {
-                       return nil
-               }
-               if bytes.Equal(b[0], id) {
-                       return b[2]
-               }
-       }
-}
-
-// generateChallenge returns a random, hex-encoded challenge, or nil on error
-// (see above).
-func (a authCookieSha1) generateChallenge() []byte {
-       b := make([]byte, 16)
-       n, err := rand.Read(b)
-       if err != nil {
-               return nil
-       }
-       if n != 16 {
-               return nil
-       }
-       enc := make([]byte, 32)
-       hex.Encode(enc, b)
-       return enc
-}
diff --git a/vendor/github.com/godbus/dbus/v5/auth_sha1_windows.go b/vendor/github.com/godbus/dbus/v5/auth_sha1_windows.go
new file mode 100644 (file)
index 0000000..fecc18a
--- /dev/null
@@ -0,0 +1,122 @@
+package dbus
+
+import (
+       "bufio"
+       "bytes"
+       "crypto/rand"
+       "crypto/sha1"
+       "encoding/hex"
+       "os"
+       "os/user"
+)
+
+// AuthCookieSha1 returns an Auth that authenticates as the given user with the
+// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home
+// directory of the user.
+func AuthCookieSha1(user, home string) Auth {
+       return authCookieSha1{user, home}
+}
+
+type authCookieSha1 struct {
+       user, home string
+}
+
+func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) {
+       b := make([]byte, 2*len(a.user))
+       hex.Encode(b, []byte(a.user))
+       return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue
+}
+
+func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
+       challenge := make([]byte, len(data)/2)
+       _, err := hex.Decode(challenge, data)
+       if err != nil {
+               return nil, AuthError
+       }
+       b := bytes.Split(challenge, []byte{' '})
+       if len(b) != 3 {
+               return nil, AuthError
+       }
+       context := b[0]
+       id := b[1]
+       svchallenge := b[2]
+       cookie := a.getCookie(context, id)
+       if cookie == nil {
+               return nil, AuthError
+       }
+       clchallenge := a.generateChallenge()
+       if clchallenge == nil {
+               return nil, AuthError
+       }
+       hash := sha1.New()
+       hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'}))
+       hexhash := make([]byte, 2*hash.Size())
+       hex.Encode(hexhash, hash.Sum(nil))
+       data = append(clchallenge, ' ')
+       data = append(data, hexhash...)
+       resp := make([]byte, 2*len(data))
+       hex.Encode(resp, data)
+       return resp, AuthOk
+}
+
+// getCookie searches for the cookie identified by id in context and returns
+// the cookie content or nil. (Since HandleData can't return a specific error,
+// but only whether an error occurred, this function also doesn't bother to
+// return an error.)
+func (a authCookieSha1) getCookie(context, id []byte) []byte {
+       file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
+       if err != nil {
+               return nil
+       }
+       defer file.Close()
+       rd := bufio.NewReader(file)
+       for {
+               line, err := rd.ReadBytes('\n')
+               if err != nil {
+                       return nil
+               }
+               line = line[:len(line)-1]
+               b := bytes.Split(line, []byte{' '})
+               if len(b) != 3 {
+                       return nil
+               }
+               if bytes.Equal(b[0], id) {
+                       return b[2]
+               }
+       }
+}
+
+// generateChallenge returns a random, hex-encoded challenge, or nil on error
+// (see above).
+func (a authCookieSha1) generateChallenge() []byte {
+       b := make([]byte, 16)
+       n, err := rand.Read(b)
+       if err != nil {
+               return nil
+       }
+       if n != 16 {
+               return nil
+       }
+       enc := make([]byte, 32)
+       hex.Encode(enc, b)
+       return enc
+}
+
+// Get returns the home directory of the current user, which is usually the
+// value of HOME environment variable. In case it is not set or empty, os/user
+// package is used.
+//
+// If linking statically with cgo enabled against glibc, make sure the
+// osusergo build tag is used.
+//
+// If needing to do nss lookups, do not disable cgo or set osusergo.
+func getHomeDir() string {
+       homeDir := os.Getenv("HOME")
+       if homeDir != "" {
+               return homeDir
+       }
+       if u, err := user.Current(); err == nil {
+               return u.HomeDir
+       }
+       return "/"
+}
index b06b063580fc533aa4f368579a201df3d3573971..d16171ab91d419af5babc80ac502b54c1c9e39db 100644 (file)
@@ -2,17 +2,14 @@ package dbus
 
 import (
        "context"
-       "errors"
 )
 
-var errSignature = errors.New("dbus: mismatched signature")
-
 // Call represents a pending or completed method call.
 type Call struct {
        Destination string
        Path        ObjectPath
        Method      string
-       Args        []interface{}
+       Args        []any
 
        // Strobes when the call is complete.
        Done chan *Call
@@ -22,7 +19,7 @@ type Call struct {
        Err error
 
        // Holds the response once the call is done.
-       Body []interface{}
+       Body []any
 
        // ResponseSequence stores the sequence number of the DBus message containing
        // the call response (or error). This can be compared to the sequence number
@@ -55,7 +52,7 @@ func (c *Call) ContextCancel() {
 // Store stores the body of the reply into the provided pointers. It returns
 // an error if the signatures of the body and retvalues don't match, or if
 // the error status is not nil.
-func (c *Call) Store(retvalues ...interface{}) error {
+func (c *Call) Store(retvalues ...any) error {
        if c.Err != nil {
                return c.Err
        }
index 69978ea26ab6340e612d6f65adfab70fbb8b07c7..4551be6305d35d9cc180e765f63c29f092647f27 100644 (file)
@@ -3,6 +3,7 @@ package dbus
 import (
        "context"
        "errors"
+       "fmt"
        "io"
        "os"
        "strings"
@@ -76,7 +77,6 @@ func SessionBus() (conn *Conn, err error) {
 func getSessionBusAddress(autolaunch bool) (string, error) {
        if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
                return address, nil
-
        } else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
                os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
                return address, nil
@@ -97,7 +97,7 @@ func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
        return Dial(address, opts...)
 }
 
-// SessionBusPrivate returns a new private connection to the session bus.  If
+// SessionBusPrivateNoAutoStartup returns a new private connection to the session bus.  If
 // the session bus is not already open, do not attempt to launch it.
 func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
        address, err := getSessionBusAddress(false)
@@ -108,7 +108,7 @@ func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
        return Dial(address, opts...)
 }
 
-// SessionBusPrivate returns a new private connection to the session bus.
+// SessionBusPrivateHandler returns a new private connection to the session bus.
 //
 // Deprecated: use SessionBusPrivate with options instead.
 func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
@@ -485,7 +485,7 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
        return &Object{conn, dest, path}
 }
 
-func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
+func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) error {
        if msg.serial == 0 {
                msg.serial = conn.getSerial()
        }
@@ -498,14 +498,29 @@ func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
        } else if msg.Type != TypeMethodCall {
                conn.serialGen.RetireSerial(msg.serial)
        }
+       return err
+}
+
+func isEncodingError(err error) bool {
+       switch err.(type) {
+       case FormatError:
+               return true
+       case InvalidMessageError:
+               return true
+       }
+       return false
 }
 
 func (conn *Conn) handleSendError(msg *Message, err error) {
        if msg.Type == TypeMethodCall {
                conn.calls.handleSendError(msg, err)
        } else if msg.Type == TypeMethodReply {
-               if _, ok := err.(FormatError); ok {
-                       conn.sendError(err, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32))
+               if isEncodingError(err) {
+                       // Make sure that the caller gets some kind of error response if
+                       // the application code tried to respond, but the resulting message
+                       // was malformed in the end
+                       returnedErr := fmt.Errorf("destination tried to respond with invalid message (%w)", err)
+                       conn.sendError(returnedErr, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32))
                }
        }
        conn.serialGen.RetireSerial(msg.serial)
@@ -560,7 +575,8 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
                        <-ctx.Done()
                        conn.calls.handleSendError(msg, ctx.Err())
                }()
-               conn.sendMessageAndIfClosed(msg, func() {
+               // error is handled in handleSendError
+               _ = conn.sendMessageAndIfClosed(msg, func() {
                        conn.calls.handleSendError(msg, ErrClosed)
                        canceler()
                })
@@ -568,7 +584,8 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
                canceler()
                call = &Call{Err: nil, Done: ch}
                ch <- call
-               conn.sendMessageAndIfClosed(msg, func() {
+               // error is handled in handleSendError
+               _ = conn.sendMessageAndIfClosed(msg, func() {
                        call = &Call{Err: ErrClosed}
                })
        }
@@ -602,12 +619,13 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
        if len(e.Body) > 0 {
                msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
        }
-       conn.sendMessageAndIfClosed(msg, nil)
+       // not much we can do to handle a possible error here
+       _ = conn.sendMessageAndIfClosed(msg, nil)
 }
 
 // sendReply creates a method reply message corresponding to the parameters and
 // sends it to conn.out.
-func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
+func (conn *Conn) sendReply(dest string, serial uint32, values ...any) {
        msg := new(Message)
        msg.Type = TypeMethodReply
        msg.Headers = make(map[HeaderField]Variant)
@@ -619,7 +637,8 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
        if len(values) > 0 {
                msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
        }
-       conn.sendMessageAndIfClosed(msg, nil)
+       // not much we can do to handle a possible error here
+       _ = conn.sendMessageAndIfClosed(msg, nil)
 }
 
 // AddMatchSignal registers the given match rule to receive broadcast
@@ -630,7 +649,7 @@ func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
 
 // AddMatchSignalContext acts like AddMatchSignal but takes a context.
 func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error {
-       options = append([]MatchOption{withMatchType("signal")}, options...)
+       options = append([]MatchOption{withMatchTypeSignal()}, options...)
        return conn.busObj.CallWithContext(
                ctx,
                "org.freedesktop.DBus.AddMatch", 0,
@@ -645,7 +664,7 @@ func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
 
 // RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context.
 func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error {
-       options = append([]MatchOption{withMatchType("signal")}, options...)
+       options = append([]MatchOption{withMatchTypeSignal()}, options...)
        return conn.busObj.CallWithContext(
                ctx,
                "org.freedesktop.DBus.RemoveMatch", 0,
@@ -694,10 +713,10 @@ func (conn *Conn) SupportsUnixFDs() bool {
 // Error represents a D-Bus message of type Error.
 type Error struct {
        Name string
-       Body []interface{}
+       Body []any
 }
 
-func NewError(name string, body []interface{}) *Error {
+func NewError(name string, body []any) *Error {
        return &Error{name, body}
 }
 
@@ -717,7 +736,7 @@ type Signal struct {
        Sender   string
        Path     ObjectPath
        Name     string
-       Body     []interface{}
+       Body     []any
        Sequence Sequence
 }
 
@@ -740,9 +759,7 @@ type transport interface {
        SendMessage(*Message) error
 }
 
-var (
-       transports = make(map[string]func(string) (transport, error))
-)
+var transports = make(map[string]func(string) (transport, error))
 
 func getTransport(address string) (transport, error) {
        var err error
@@ -770,10 +787,10 @@ func getTransport(address string) (transport, error) {
 
 // getKey gets a key from a the list of keys. Returns "" on error / not found...
 func getKey(s, key string) string {
-       for _, keyEqualsValue := range strings.Split(s, ",") {
-               keyValue := strings.SplitN(keyEqualsValue, "=", 2)
-               if len(keyValue) == 2 && keyValue[0] == key {
-                       val, err := UnescapeBusAddressValue(keyValue[1])
+       keyEq := key + "="
+       for _, kv := range strings.Split(s, ",") {
+               if v, ok := strings.CutPrefix(kv, keyEq); ok {
+                       val, err := UnescapeBusAddressValue(v)
                        if err != nil {
                                // No way to return an error.
                                return ""
@@ -853,16 +870,19 @@ type nameTracker struct {
 func newNameTracker() *nameTracker {
        return &nameTracker{names: map[string]struct{}{}}
 }
+
 func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
        tracker.lck.Lock()
        defer tracker.lck.Unlock()
        tracker.unique = name
 }
+
 func (tracker *nameTracker) acquireName(name string) {
        tracker.lck.Lock()
        defer tracker.lck.Unlock()
        tracker.names[name] = struct{}{}
 }
+
 func (tracker *nameTracker) loseName(name string) {
        tracker.lck.Lock()
        defer tracker.lck.Unlock()
@@ -874,12 +894,14 @@ func (tracker *nameTracker) uniqueNameIsKnown() bool {
        defer tracker.lck.RUnlock()
        return tracker.unique != ""
 }
+
 func (tracker *nameTracker) isKnownName(name string) bool {
        tracker.lck.RLock()
        defer tracker.lck.RUnlock()
        _, ok := tracker.names[name]
        return ok || name == tracker.unique
 }
+
 func (tracker *nameTracker) listKnownNames() []string {
        tracker.lck.RLock()
        defer tracker.lck.RUnlock()
@@ -941,18 +963,7 @@ func (tracker *callTracker) handleSendError(msg *Message, err error) {
        }
 }
 
-// finalize was the only func that did not strobe Done
-func (tracker *callTracker) finalize(sn uint32) {
-       tracker.lck.Lock()
-       defer tracker.lck.Unlock()
-       c, ok := tracker.calls[sn]
-       if ok {
-               delete(tracker.calls, sn)
-               c.ContextCancel()
-       }
-}
-
-func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) {
+func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []any) {
        tracker.lck.Lock()
        c, ok := tracker.calls[sn]
        if ok {
index 6e2e4020216500fdc0b4c2862ed5ea3f4bc6d115..cb2325a01b4e8d24a2ec6917569c9678bca72292 100644 (file)
@@ -12,7 +12,6 @@ const defaultSystemBusAddress = "unix:path=/opt/local/var/run/dbus/system_bus_so
 func getSessionBusPlatformAddress() (string, error) {
        cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET")
        b, err := cmd.CombinedOutput()
-
        if err != nil {
                return "", err
        }
index 90289ca85a28a300d92802d157978b9c2c5e0777..9c1284c27457602296243b54d4dd2217e9b5fd91 100644 (file)
@@ -1,3 +1,4 @@
+//go:build !darwin
 // +build !darwin
 
 package dbus
@@ -6,7 +7,6 @@ import (
        "bytes"
        "errors"
        "fmt"
-       "io/ioutil"
        "os"
        "os/exec"
        "os/user"
@@ -19,7 +19,6 @@ var execCommand = exec.Command
 func getSessionBusPlatformAddress() (string, error) {
        cmd := execCommand("dbus-launch")
        b, err := cmd.CombinedOutput()
-
        if err != nil {
                return "", err
        }
@@ -42,10 +41,10 @@ func getSessionBusPlatformAddress() (string, error) {
 // It tries different techniques employed by different operating systems,
 // returning the first valid address it finds, or an empty string.
 //
-// * /run/user/<uid>/bus           if this exists, it *is* the bus socket. present on
-//                                 Ubuntu 18.04
-// * /run/user/<uid>/dbus-session: if this exists, it can be parsed for the bus
-//                                 address. present on Ubuntu 16.04
+//   - /run/user/<uid>/bus           if this exists, it *is* the bus socket. present on
+//     Ubuntu 18.04
+//   - /run/user/<uid>/dbus-session: if this exists, it can be parsed for the bus
+//     address. present on Ubuntu 16.04
 //
 // See https://dbus.freedesktop.org/doc/dbus-launch.1.html
 func tryDiscoverDbusSessionBusAddress() string {
@@ -61,14 +60,9 @@ func tryDiscoverDbusSessionBusAddress() string {
                        // text file // containing the address of the socket, e.g.:
                        // DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG
 
-                       if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil {
-                               fileContent := string(f)
-
-                               prefix := "DBUS_SESSION_BUS_ADDRESS="
-
-                               if strings.HasPrefix(fileContent, prefix) {
-                                       address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r")
-                                       return address
+                       if f, err := os.ReadFile(runUserSessionDbusFile); err == nil {
+                               if addr, ok := strings.CutPrefix(string(f), "DBUS_SESSION_BUS_ADDRESS="); ok {
+                                       return strings.TrimRight(addr, "\n\r")
                                }
                        }
                }
index 58aee7d2af5eb770bbcded7404a202e1b9aadd0b..84e1dc652dd4bbc288db976116bb2a81a5a2cd40 100644 (file)
@@ -1,8 +1,10 @@
-//+build !windows,!solaris,!darwin
+//go:build !windows && !solaris && !darwin
+// +build !windows,!solaris,!darwin
 
 package dbus
 
 import (
+       "net"
        "os"
 )
 
@@ -15,3 +17,25 @@ func getSystemBusPlatformAddress() string {
        }
        return defaultSystemBusAddress
 }
+
+// DialUnix establishes a new private connection to the message bus specified by UnixConn.
+func DialUnix(conn *net.UnixConn, opts ...ConnOption) (*Conn, error) {
+       tr := newUnixTransportFromConn(conn)
+       return newConn(tr, opts...)
+}
+
+func ConnectUnix(uconn *net.UnixConn, opts ...ConnOption) (*Conn, error) {
+       conn, err := DialUnix(uconn, opts...)
+       if err != nil {
+               return nil, err
+       }
+       if err = conn.Auth(conn.auth); err != nil {
+               _ = conn.Close()
+               return nil, err
+       }
+       if err = conn.Hello(); err != nil {
+               _ = conn.Close()
+               return nil, err
+       }
+       return conn, nil
+}
index 4291e4519cc016f16d9d5d1503c5b6560a38abcb..fa839d2a228247215cb5927af93b41fd9bc1afa2 100644 (file)
@@ -1,5 +1,3 @@
-//+build windows
-
 package dbus
 
 import "os"
index c188d104854fa9094fc4d7b6241452db42c89f25..d3622d80794621537fec88bb7e9dd4166c0b698b 100644 (file)
@@ -10,11 +10,8 @@ import (
 var (
        byteType        = reflect.TypeOf(byte(0))
        boolType        = reflect.TypeOf(false)
-       uint8Type       = reflect.TypeOf(uint8(0))
        int16Type       = reflect.TypeOf(int16(0))
        uint16Type      = reflect.TypeOf(uint16(0))
-       intType         = reflect.TypeOf(int(0))
-       uintType        = reflect.TypeOf(uint(0))
        int32Type       = reflect.TypeOf(int32(0))
        uint32Type      = reflect.TypeOf(uint32(0))
        int64Type       = reflect.TypeOf(int64(0))
@@ -24,8 +21,8 @@ var (
        signatureType   = reflect.TypeOf(Signature{""})
        objectPathType  = reflect.TypeOf(ObjectPath(""))
        variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
-       interfacesType  = reflect.TypeOf([]interface{}{})
-       interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
+       interfacesType  = reflect.TypeOf([]any{})
+       interfaceType   = reflect.TypeOf((*any)(nil)).Elem()
        unixFDType      = reflect.TypeOf(UnixFD(0))
        unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
        errType         = reflect.TypeOf((*error)(nil)).Elem()
@@ -45,7 +42,7 @@ func (e InvalidTypeError) Error() string {
 // pointers. It converts slices of interfaces from src to corresponding structs
 // in dest. An error is returned if the lengths of src and dest or the types of
 // their elements don't match.
-func Store(src []interface{}, dest ...interface{}) error {
+func Store(src []any, dest ...any) error {
        if len(src) != len(dest) {
                return errors.New("dbus.Store: length mismatch")
        }
@@ -58,7 +55,7 @@ func Store(src []interface{}, dest ...interface{}) error {
        return nil
 }
 
-func storeInterfaces(src, dest interface{}) error {
+func storeInterfaces(src, dest any) error {
        return store(reflect.ValueOf(dest), reflect.ValueOf(src))
 }
 
@@ -85,7 +82,7 @@ func storeBase(dest, src reflect.Value) error {
 
 func setDest(dest, src reflect.Value) error {
        if !isVariant(src.Type()) && isVariant(dest.Type()) {
-               //special conversion for dbus.Variant
+               // special conversion for dbus.Variant
                dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
                return nil
        }
@@ -166,8 +163,8 @@ func storeMapIntoVariant(dest, src reflect.Value) error {
 func storeMapIntoInterface(dest, src reflect.Value) error {
        var dv reflect.Value
        if isVariant(src.Type().Elem()) {
-               //Convert variants to interface{} recursively when converting
-               //to interface{}
+               // Convert variants to interface{} recursively when converting
+               // to interface{}
                dv = reflect.MakeMap(
                        reflect.MapOf(src.Type().Key(), interfaceType))
        } else {
@@ -200,7 +197,7 @@ func storeMapIntoMap(dest, src reflect.Value) error {
 func storeSlice(dest, src reflect.Value) error {
        switch {
        case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
-               //The decoder always decodes structs as slices of interface{}
+               // The decoder always decodes structs as slices of interface{}
                return storeStruct(dest, src)
        case !kindsAreCompatible(dest.Type(), src.Type()):
                return fmt.Errorf(
@@ -225,7 +222,7 @@ func storeStruct(dest, src reflect.Value) error {
        if isVariant(dest.Type()) {
                return storeBase(dest, src)
        }
-       dval := make([]interface{}, 0, dest.NumField())
+       dval := make([]any, 0, dest.NumField())
        dtype := dest.Type()
        for i := 0; i < dest.NumField(); i++ {
                field := dest.Field(i)
@@ -245,7 +242,7 @@ func storeStruct(dest, src reflect.Value) error {
                                "enough fields need: %d have: %d",
                        src.Len(), len(dval))
        }
-       return Store(src.Interface().([]interface{}), dval...)
+       return Store(src.Interface().([]any), dval...)
 }
 
 func storeSliceIntoVariant(dest, src reflect.Value) error {
@@ -260,8 +257,8 @@ func storeSliceIntoVariant(dest, src reflect.Value) error {
 func storeSliceIntoInterface(dest, src reflect.Value) error {
        var dv reflect.Value
        if isVariant(src.Type().Elem()) {
-               //Convert variants to interface{} recursively when converting
-               //to interface{}
+               // Convert variants to interface{} recursively when converting
+               // to interface{}
                dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
                        src.Len(), src.Cap())
        } else {
@@ -334,7 +331,7 @@ func (o ObjectPath) IsValid() bool {
 }
 
 // A UnixFD is a Unix file descriptor sent over the wire. See the package-level
-// documentation for more information about Unix file descriptor passsing.
+// documentation for more information about Unix file descriptor passing.
 type UnixFD int32
 
 // A UnixFDIndex is the representation of a Unix file descriptor in a message.
index 89bfed9d1a1c532aea1437cdbb00035bf05ffb2c..1e6198f5bf10143f77a0617b1ad228e2c7aeb323 100644 (file)
@@ -4,6 +4,7 @@ import (
        "encoding/binary"
        "io"
        "reflect"
+       "unsafe"
 )
 
 type decoder struct {
@@ -11,6 +12,12 @@ type decoder struct {
        order binary.ByteOrder
        pos   int
        fds   []int
+
+       // The following fields are used to reduce memory allocs.
+       conv *stringConverter
+       buf  []byte
+       d    float64
+       y    [1]byte
 }
 
 // newDecoder returns a new decoder that reads values from in. The input is
@@ -20,29 +27,39 @@ func newDecoder(in io.Reader, order binary.ByteOrder, fds []int) *decoder {
        dec.in = in
        dec.order = order
        dec.fds = fds
+       dec.conv = newStringConverter(stringConverterBufferSize)
        return dec
 }
 
+// Reset resets the decoder to be reading from in.
+func (dec *decoder) Reset(in io.Reader, order binary.ByteOrder, fds []int) {
+       dec.in = in
+       dec.order = order
+       dec.pos = 0
+       dec.fds = fds
+
+       if dec.conv == nil {
+               dec.conv = newStringConverter(stringConverterBufferSize)
+       }
+}
+
 // align aligns the input to the given boundary and panics on error.
 func (dec *decoder) align(n int) {
        if dec.pos%n != 0 {
                newpos := (dec.pos + n - 1) & ^(n - 1)
-               empty := make([]byte, newpos-dec.pos)
-               if _, err := io.ReadFull(dec.in, empty); err != nil {
-                       panic(err)
-               }
+               dec.read2buf(newpos - dec.pos)
                dec.pos = newpos
        }
 }
 
 // Calls binary.Read(dec.in, dec.order, v) and panics on read errors.
-func (dec *decoder) binread(v interface{}) {
+func (dec *decoder) binread(v any) {
        if err := binary.Read(dec.in, dec.order, v); err != nil {
                panic(err)
        }
 }
 
-func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
+func (dec *decoder) Decode(sig Signature) (vs []any, err error) {
        defer func() {
                var ok bool
                v := recover()
@@ -52,7 +69,7 @@ func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
                        }
                }
        }()
-       vs = make([]interface{}, 0)
+       vs = make([]any, 0)
        s := sig.str
        for s != "" {
                err, rem := validSingle(s, &depthCounter{})
@@ -66,79 +83,89 @@ func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
        return vs, nil
 }
 
-func (dec *decoder) decode(s string, depth int) interface{} {
+// read2buf reads exactly n bytes from the reader dec.in into the buffer dec.buf
+// to reduce memory allocs.
+// The buffer grows automatically.
+func (dec *decoder) read2buf(n int) {
+       if cap(dec.buf) < n {
+               dec.buf = make([]byte, n)
+       } else {
+               dec.buf = dec.buf[:n]
+       }
+       if _, err := io.ReadFull(dec.in, dec.buf); err != nil {
+               panic(err)
+       }
+}
+
+// decodeU decodes uint32 obtained from the reader dec.in.
+// The goal is to reduce memory allocs.
+func (dec *decoder) decodeU() uint32 {
+       dec.align(4)
+       dec.read2buf(4)
+       dec.pos += 4
+       return dec.order.Uint32(dec.buf)
+}
+
+func (dec *decoder) decode(s string, depth int) any {
        dec.align(alignment(typeFor(s)))
        switch s[0] {
        case 'y':
-               var b [1]byte
-               if _, err := dec.in.Read(b[:]); err != nil {
+               if _, err := dec.in.Read(dec.y[:]); err != nil {
                        panic(err)
                }
                dec.pos++
-               return b[0]
+               return dec.y[0]
        case 'b':
-               i := dec.decode("u", depth).(uint32)
-               switch {
-               case i == 0:
+               switch dec.decodeU() {
+               case 0:
                        return false
-               case i == 1:
+               case 1:
                        return true
                default:
                        panic(FormatError("invalid value for boolean"))
                }
        case 'n':
-               var i int16
-               dec.binread(&i)
+               dec.read2buf(2)
                dec.pos += 2
-               return i
+               return int16(dec.order.Uint16(dec.buf))
        case 'i':
-               var i int32
-               dec.binread(&i)
+               dec.read2buf(4)
                dec.pos += 4
-               return i
+               return int32(dec.order.Uint32(dec.buf))
        case 'x':
-               var i int64
-               dec.binread(&i)
+               dec.read2buf(8)
                dec.pos += 8
-               return i
+               return int64(dec.order.Uint64(dec.buf))
        case 'q':
-               var i uint16
-               dec.binread(&i)
+               dec.read2buf(2)
                dec.pos += 2
-               return i
+               return dec.order.Uint16(dec.buf)
        case 'u':
-               var i uint32
-               dec.binread(&i)
-               dec.pos += 4
-               return i
+               return dec.decodeU()
        case 't':
-               var i uint64
-               dec.binread(&i)
+               dec.read2buf(8)
                dec.pos += 8
-               return i
+               return dec.order.Uint64(dec.buf)
        case 'd':
-               var f float64
-               dec.binread(&f)
+               dec.binread(&dec.d)
                dec.pos += 8
-               return f
+               return dec.d
        case 's':
-               length := dec.decode("u", depth).(uint32)
-               b := make([]byte, int(length)+1)
-               if _, err := io.ReadFull(dec.in, b); err != nil {
-                       panic(err)
-               }
-               dec.pos += int(length) + 1
-               return string(b[:len(b)-1])
+               length := dec.decodeU()
+               p := int(length) + 1
+               dec.read2buf(p)
+               dec.pos += p
+               return dec.conv.String(dec.buf[:len(dec.buf)-1])
        case 'o':
                return ObjectPath(dec.decode("s", depth).(string))
        case 'g':
                length := dec.decode("y", depth).(byte)
-               b := make([]byte, int(length)+1)
-               if _, err := io.ReadFull(dec.in, b); err != nil {
-                       panic(err)
-               }
-               dec.pos += int(length) + 1
-               sig, err := ParseSignature(string(b[:len(b)-1]))
+               p := int(length) + 1
+               dec.read2buf(p)
+               dec.pos += p
+               sig, err := ParseSignature(
+                       dec.conv.String(dec.buf[:len(dec.buf)-1]),
+               )
                if err != nil {
                        panic(err)
                }
@@ -163,7 +190,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
                variant.value = dec.decode(sig.str, depth+1)
                return variant
        case 'h':
-               idx := dec.decode("u", depth).(uint32)
+               idx := dec.decodeU()
                if int(idx) < len(dec.fds) {
                        return UnixFD(dec.fds[idx])
                }
@@ -176,7 +203,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
                        if depth >= 63 {
                                panic(FormatError("input exceeds container depth limit"))
                        }
-                       length := dec.decode("u", depth).(uint32)
+                       length := dec.decodeU()
                        // Even for empty maps, the correct padding must be included
                        dec.align(8)
                        spos := dec.pos
@@ -195,7 +222,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
                        panic(FormatError("input exceeds container depth limit"))
                }
                sig := s[1:]
-               length := dec.decode("u", depth).(uint32)
+               length := dec.decodeU()
                // capacity can be determined only for fixed-size element types
                var capacity int
                if s := sigByteSize(sig); s != 0 {
@@ -205,9 +232,9 @@ func (dec *decoder) decode(s string, depth int) interface{} {
                // Even for empty arrays, the correct padding must be included
                align := alignment(typeFor(s[1:]))
                if len(s) > 1 && s[1] == '(' {
-                       //Special case for arrays of structs
-                       //structs decode as a slice of interface{} values
-                       //but the dbus alignment does not match this
+                       // Special case for arrays of structs
+                       // structs decode as a slice of interface{} values
+                       // but the dbus alignment does not match this
                        align = 8
                }
                dec.align(align)
@@ -222,7 +249,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
                        panic(FormatError("input exceeds container depth limit"))
                }
                dec.align(8)
-               v := make([]interface{}, 0)
+               v := make([]any, 0)
                s = s[1 : len(s)-1]
                for s != "" {
                        err, rem := validSingle(s, &depthCounter{})
@@ -290,3 +317,59 @@ type FormatError string
 func (e FormatError) Error() string {
        return "dbus: wire format error: " + string(e)
 }
+
+// stringConverterBufferSize defines the recommended buffer size of 4KB.
+// It showed good results in a benchmark when decoding 35KB message,
+// see https://github.com/marselester/systemd#testing.
+const stringConverterBufferSize = 4096
+
+func newStringConverter(capacity int) *stringConverter {
+       return &stringConverter{
+               buf:    make([]byte, 0, capacity),
+               offset: 0,
+       }
+}
+
+// stringConverter converts bytes to strings with less allocs.
+// The idea is to accumulate bytes in a buffer with specified capacity
+// and create strings with unsafe package using bytes from a buffer.
+// For example, 10 "fizz" strings written to a 40-byte buffer
+// will result in 1 alloc instead of 10.
+//
+// Once a buffer is filled, a new one is created with the same capacity.
+// Old buffers will be eventually GC-ed
+// with no side effects to the returned strings.
+type stringConverter struct {
+       // buf is a temporary buffer where decoded strings are batched.
+       buf []byte
+       // offset is a buffer position where the last string was written.
+       offset int
+}
+
+// String converts bytes to a string.
+func (c *stringConverter) String(b []byte) string {
+       n := len(b)
+       if n == 0 {
+               return ""
+       }
+       // Must allocate because a string doesn't fit into the buffer.
+       if n > cap(c.buf) {
+               return string(b)
+       }
+
+       if len(c.buf)+n > cap(c.buf) {
+               c.buf = make([]byte, 0, cap(c.buf))
+               c.offset = 0
+       }
+       c.buf = append(c.buf, b...)
+
+       b = c.buf[c.offset:]
+       s := toString(b)
+       c.offset += n
+       return s
+}
+
+// toString converts a byte slice to a string without allocating.
+func toString(b []byte) string {
+       return unsafe.String(&b[0], len(b))
+}
index 13132c6b47970036f721043d8fdceb9cbc7449e1..c17ab0b97de112d09b18c0d0c08167526125a16d 100644 (file)
@@ -18,9 +18,9 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf {
        return newExportedIntf(methods, true)
 }
 
-//NewDefaultHandler returns an instance of the default
-//call handler. This is useful if you want to implement only
-//one of the two handlers but not both.
+// NewDefaultHandler returns an instance of the default
+// call handler. This is useful if you want to implement only
+// one of the two handlers but not both.
 //
 // Deprecated: this is the default value, don't use it, it will be unexported.
 func NewDefaultHandler() *defaultHandler {
@@ -52,9 +52,9 @@ func (h *defaultHandler) introspectPath(path ObjectPath) string {
                if p != "/" {
                        p += "/"
                }
-               if strings.HasPrefix(string(obj), p) {
-                       node_name := strings.Split(string(obj[len(p):]), "/")[0]
-                       subpath[node_name] = struct{}{}
+               if after, ok := strings.CutPrefix(string(obj), p); ok {
+                       name, _, _ := strings.Cut(after, "/")
+                       subpath[name] = struct{}{}
                }
        }
        for s := range subpath {
@@ -117,7 +117,7 @@ type exportedMethod struct {
        reflect.Value
 }
 
-func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
+func (m exportedMethod) Call(args ...any) ([]any, error) {
        t := m.Type()
 
        params := make([]reflect.Value, len(args))
@@ -143,12 +143,12 @@ func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
                        ret = ret[:t.NumOut()-1]
                }
        }
-       out := make([]interface{}, len(ret))
+       out := make([]any, len(ret))
        for i, val := range ret {
                out[i] = val.Interface()
        }
        if nilErr || err == nil {
-               //concrete type to interface nil is a special case
+               // concrete type to interface nil is a special case
                return out, nil
        }
        return out, err
@@ -158,7 +158,7 @@ func (m exportedMethod) NumArguments() int {
        return m.Value.Type().NumIn()
 }
 
-func (m exportedMethod) ArgumentValue(i int) interface{} {
+func (m exportedMethod) ArgumentValue(i int) any {
        return reflect.Zero(m.Type().In(i)).Interface()
 }
 
@@ -166,7 +166,7 @@ func (m exportedMethod) NumReturns() int {
        return m.Value.Type().NumOut()
 }
 
-func (m exportedMethod) ReturnValue(i int) interface{} {
+func (m exportedMethod) ReturnValue(i int) any {
        return reflect.Zero(m.Type().Out(i)).Interface()
 }
 
@@ -215,10 +215,6 @@ func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
        return nil, false
 }
 
-func (obj *exportedObj) isFallbackInterface() bool {
-       return false
-}
-
 func newExportedIntf(methods map[string]Method, includeSubtree bool) *exportedIntf {
        return &exportedIntf{
                methods:        methods,
@@ -242,9 +238,9 @@ func (obj *exportedIntf) isFallbackInterface() bool {
        return obj.includeSubtree
 }
 
-//NewDefaultSignalHandler returns an instance of the default
-//signal handler. This is useful if you want to implement only
-//one of the two handlers but not both.
+// NewDefaultSignalHandler returns an instance of the default
+// signal handler. This is useful if you want to implement only
+// one of the two handlers but not both.
 //
 // Deprecated: this is the default value, don't use it, it will be unexported.
 func NewDefaultSignalHandler() *defaultSignalHandler {
index 8f25a00d61e26eb40ff85aec7596205345d20250..09eedc71e610e5eec859680b9c2db49df36cb848 100644 (file)
@@ -7,7 +7,7 @@ on remote objects and emit or receive signals. Using the Export method, you can
 arrange D-Bus methods calls to be directly translated to method calls on a Go
 value.
 
-Conversion Rules
+Conversion Rules
 
 For outgoing messages, Go types are automatically converted to the
 corresponding D-Bus types. See the official specification at
@@ -15,25 +15,25 @@ https://dbus.freedesktop.org/doc/dbus-specification.html#type-system for more
 information on the D-Bus type system. The following types are directly encoded
 as their respective D-Bus equivalents:
 
-     Go type     | D-Bus type
-     ------------+-----------
-     byte        | BYTE
-     bool        | BOOLEAN
-     int16       | INT16
-     uint16      | UINT16
-     int         | INT32
-     uint        | UINT32
-     int32       | INT32
-     uint32      | UINT32
-     int64       | INT64
-     uint64      | UINT64
-     float64     | DOUBLE
-     string      | STRING
-     ObjectPath  | OBJECT_PATH
-     Signature   | SIGNATURE
-     Variant     | VARIANT
-     interface{} | VARIANT
-     UnixFDIndex | UNIX_FD
+       Go type     | D-Bus type
+       ------------+-----------
+       byte        | BYTE
+       bool        | BOOLEAN
+       int16       | INT16
+       uint16      | UINT16
+       int         | INT32
+       uint        | UINT32
+       int32       | INT32
+       uint32      | UINT32
+       int64       | INT64
+       uint64      | UINT64
+       float64     | DOUBLE
+       string      | STRING
+       ObjectPath  | OBJECT_PATH
+       Signature   | SIGNATURE
+       Variant     | VARIANT
+       interface{} | VARIANT
+       UnixFDIndex | UNIX_FD
 
 Slices and arrays encode as ARRAYs of their element type.
 
@@ -57,7 +57,7 @@ of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces
 containing the struct fields in the correct order. The Store function can be
 used to convert such values to Go structs.
 
-Unix FD passing
+Unix FD passing
 
 Handling Unix file descriptors deserves special mention. To use them, you should
 first check that they are supported on a connection by calling SupportsUnixFDs.
@@ -66,6 +66,5 @@ UnixFD's to messages that are accompanied by the given file descriptors with the
 UnixFD values being substituted by the correct indices. Similarly, the indices
 of incoming messages are automatically resolved. It shouldn't be necessary to use
 UnixFDIndex.
-
 */
 package dbus
index 015b26cd5c495dff5c749b6c250c7af68023c2f4..5901ab42a9c301aaab84d1cd7885a1e2b7c8f42a 100644 (file)
@@ -59,7 +59,7 @@ func (enc *encoder) padding(offset, algn int) int {
 }
 
 // Calls binary.Write(enc.out, enc.order, v) and panics on write errors.
-func (enc *encoder) binwrite(v interface{}) {
+func (enc *encoder) binwrite(v any) {
        if err := binary.Write(enc.out, enc.order, v); err != nil {
                panic(err)
        }
@@ -67,7 +67,7 @@ func (enc *encoder) binwrite(v interface{}) {
 
 // Encode encodes the given values to the underlying reader. All written values
 // are aligned properly as required by the D-Bus spec.
-func (enc *encoder) Encode(vs ...interface{}) (err error) {
+func (enc *encoder) Encode(vs ...any) (err error) {
        defer func() {
                err, _ = recover().(error)
        }()
index d3dd9f7cd62d5c82943e81a05bcf3d8042fabdcf..20d8cb38fa495a2c3519947442c86d6b8c72f4cb 100644 (file)
@@ -11,47 +11,47 @@ import (
 var (
        ErrMsgInvalidArg = Error{
                "org.freedesktop.DBus.Error.InvalidArgs",
-               []interface{}{"Invalid type / number of args"},
+               []any{"Invalid type / number of args"},
        }
        ErrMsgNoObject = Error{
                "org.freedesktop.DBus.Error.NoSuchObject",
-               []interface{}{"No such object"},
+               []any{"No such object"},
        }
        ErrMsgUnknownMethod = Error{
                "org.freedesktop.DBus.Error.UnknownMethod",
-               []interface{}{"Unknown / invalid method"},
+               []any{"Unknown / invalid method"},
        }
        ErrMsgUnknownInterface = Error{
                "org.freedesktop.DBus.Error.UnknownInterface",
-               []interface{}{"Object does not implement the interface"},
+               []any{"Object does not implement the interface"},
        }
 )
 
 func MakeNoObjectError(path ObjectPath) Error {
        return Error{
                "org.freedesktop.DBus.Error.NoSuchObject",
-               []interface{}{fmt.Sprintf("No such object '%s'", string(path))},
+               []any{fmt.Sprintf("No such object '%s'", string(path))},
        }
 }
 
 func MakeUnknownMethodError(methodName string) Error {
        return Error{
                "org.freedesktop.DBus.Error.UnknownMethod",
-               []interface{}{fmt.Sprintf("Unknown / invalid method '%s'", methodName)},
+               []any{fmt.Sprintf("Unknown / invalid method '%s'", methodName)},
        }
 }
 
 func MakeUnknownInterfaceError(ifaceName string) Error {
        return Error{
                "org.freedesktop.DBus.Error.UnknownInterface",
-               []interface{}{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)},
+               []any{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)},
        }
 }
 
 func MakeFailedError(err error) *Error {
        return &Error{
                "org.freedesktop.DBus.Error.Failed",
-               []interface{}{err.Error()},
+               []any{err.Error()},
        }
 }
 
@@ -67,7 +67,7 @@ func computeMethodName(name string, mapping map[string]string) string {
        return name
 }
 
-func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
+func getMethods(in any, mapping map[string]string) map[string]reflect.Value {
        if in == nil {
                return nil
        }
@@ -91,7 +91,7 @@ func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Va
        return methods
 }
 
-func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
+func getAllMethods(in any, mapping map[string]string) map[string]reflect.Value {
        if in == nil {
                return nil
        }
@@ -107,9 +107,9 @@ func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect
        return methods
 }
 
-func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) {
-       pointers := make([]interface{}, m.NumArguments())
-       decode := make([]interface{}, 0, len(body))
+func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []any) ([]any, error) {
+       pointers := make([]any, m.NumArguments())
+       decode := make([]any, 0, len(body))
 
        for i := 0; i < m.NumArguments(); i++ {
                tp := reflect.TypeOf(m.ArgumentValue(i))
@@ -135,7 +135,7 @@ func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []
        return pointers, nil
 }
 
-func (conn *Conn) decodeArguments(m Method, sender string, msg *Message) ([]interface{}, error) {
+func (conn *Conn) decodeArguments(m Method, sender string, msg *Message) ([]any, error) {
        if decoder, ok := m.(ArgumentDecoder); ok {
                return decoder.DecodeArguments(conn, sender, msg, msg.Body)
        }
@@ -204,23 +204,21 @@ func (conn *Conn) handleCall(msg *Message) {
                        reply.Headers[FieldDestination] = msg.Headers[FieldSender]
                }
                reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
-               reply.Body = make([]interface{}, len(ret))
-               for i := 0; i < len(ret); i++ {
-                       reply.Body[i] = ret[i]
-               }
+               reply.Body = make([]any, len(ret))
+               copy(reply.Body, ret)
                reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
 
-               if err := reply.IsValid(); err != nil {
-                       fmt.Fprintf(os.Stderr, "dbus: dropping invalid reply to %s.%s on obj %s: %s\n", ifaceName, name, path, err)
-               } else {
-                       conn.sendMessageAndIfClosed(reply, nil)
+               if err := conn.sendMessageAndIfClosed(reply, nil); err != nil {
+                       if _, ok := err.(FormatError); ok {
+                               fmt.Fprintf(os.Stderr, "dbus: replacing invalid reply to %s.%s on obj %s: %s\n", ifaceName, name, path, err)
+                       }
                }
        }
 }
 
 // Emit emits the given signal on the message bus. The name parameter must be
 // formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
-func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
+func (conn *Conn) Emit(path ObjectPath, name string, values ...any) error {
        i := strings.LastIndex(name, ".")
        if i == -1 {
                return errors.New("dbus: invalid method name")
@@ -237,18 +235,15 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
        if len(values) > 0 {
                msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
        }
-       if err := msg.IsValid(); err != nil {
-               return err
-       }
 
        var closed bool
-       conn.sendMessageAndIfClosed(msg, func() {
+       err := conn.sendMessageAndIfClosed(msg, func() {
                closed = true
        })
        if closed {
                return ErrClosed
        }
-       return nil
+       return err
 }
 
 // Export registers the given value to be exported as an object on the
@@ -279,7 +274,7 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
 // the given combination of path and interface.
 //
 // Export returns an error if path is not a valid path name.
-func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
+func (conn *Conn) Export(v any, path ObjectPath, iface string) error {
        return conn.ExportWithMap(v, nil, path, iface)
 }
 
@@ -291,7 +286,7 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
 // type parameter to your method signature. If the error returned is not nil,
 // it is sent back to the caller as an error. Otherwise, a method reply is
 // sent with the other return values as its body.
-func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error {
+func (conn *Conn) ExportAll(v any, path ObjectPath, iface string) error {
        return conn.export(getAllMethods(v, nil), path, iface, false)
 }
 
@@ -300,7 +295,7 @@ func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error
 //
 // The keys in the map are the real method names (exported on the struct), and
 // the values are the method names to be exported on DBus.
-func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
+func (conn *Conn) ExportWithMap(v any, mapping map[string]string, path ObjectPath, iface string) error {
        return conn.export(getMethods(v, mapping), path, iface, false)
 }
 
@@ -314,7 +309,7 @@ func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path O
 // Note that more specific export paths take precedence over less specific. For
 // example, a method call using the ObjectPath /foo/bar/baz will call a method
 // exported on /foo/bar before a method exported on /foo.
-func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error {
+func (conn *Conn) ExportSubtree(v any, path ObjectPath, iface string) error {
        return conn.ExportSubtreeWithMap(v, nil, path, iface)
 }
 
@@ -323,7 +318,7 @@ func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) er
 //
 // The keys in the map are the real method names (exported on the struct), and
 // the values are the method names to be exported on DBus.
-func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
+func (conn *Conn) ExportSubtreeWithMap(v any, mapping map[string]string, path ObjectPath, iface string) error {
        return conn.export(getMethods(v, mapping), path, iface, true)
 }
 
@@ -337,16 +332,16 @@ func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string,
 // methods on the fly.
 //
 // Any non-function objects in the method table are ignored.
-func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
+func (conn *Conn) ExportMethodTable(methods map[string]any, path ObjectPath, iface string) error {
        return conn.exportMethodTable(methods, path, iface, false)
 }
 
 // Like ExportSubtree, but with the same caveats as ExportMethodTable.
-func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
+func (conn *Conn) ExportSubtreeMethodTable(methods map[string]any, path ObjectPath, iface string) error {
        return conn.exportMethodTable(methods, path, iface, true)
 }
 
-func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
+func (conn *Conn) exportMethodTable(methods map[string]any, path ObjectPath, iface string, includeSubtree bool) error {
        var out map[string]reflect.Value
        if methods != nil {
                out = make(map[string]reflect.Value)
@@ -443,6 +438,18 @@ const (
        ReleaseNameReplyNotOwner
 )
 
+func (rep ReleaseNameReply) String() string {
+       switch rep {
+       case ReleaseNameReplyReleased:
+               return "released"
+       case ReleaseNameReplyNonExistent:
+               return "non existent"
+       case ReleaseNameReplyNotOwner:
+               return "not owner"
+       }
+       return "unknown"
+}
+
 // RequestNameFlags represents the possible flags for a RequestName call.
 type RequestNameFlags uint32
 
@@ -461,3 +468,17 @@ const (
        RequestNameReplyExists
        RequestNameReplyAlreadyOwner
 )
+
+func (rep RequestNameReply) String() string {
+       switch rep {
+       case RequestNameReplyPrimaryOwner:
+               return "primary owner"
+       case RequestNameReplyInQueue:
+               return "in queue"
+       case RequestNameReplyExists:
+               return "exists"
+       case RequestNameReplyAlreadyOwner:
+               return "already owner"
+       }
+       return "unknown"
+}
diff --git a/vendor/github.com/godbus/dbus/v5/homedir.go b/vendor/github.com/godbus/dbus/v5/homedir.go
deleted file mode 100644 (file)
index c44d9b5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package dbus
-
-import (
-       "os"
-       "os/user"
-)
-
-// Get returns the home directory of the current user, which is usually the
-// value of HOME environment variable. In case it is not set or empty, os/user
-// package is used.
-//
-// If linking statically with cgo enabled against glibc, make sure the
-// osusergo build tag is used.
-//
-// If needing to do nss lookups, do not disable cgo or set osusergo.
-func getHomeDir() string {
-       homeDir := os.Getenv("HOME")
-       if homeDir != "" {
-               return homeDir
-       }
-       if u, err := user.Current(); err == nil {
-               return u.HomeDir
-       }
-       return "/"
-}
index 5a607e53e41070eba2db1dd261fc59a6f63f18d3..ffb01344755c0562888f1e83815066a138dfc7d5 100644 (file)
@@ -26,10 +26,10 @@ func WithMatchOption(key, value string) MatchOption {
        return MatchOption{key, value}
 }
 
-// doesn't make sense to export this option because clients can only
-// subscribe to messages with signal type.
-func withMatchType(typ string) MatchOption {
-       return WithMatchOption("type", typ)
+// It does not make sense to have a public WithMatchType function
+// because clients can only subscribe to messages with signal type.
+func withMatchTypeSignal() MatchOption {
+       return WithMatchOption("type", "signal")
 }
 
 // WithMatchSender sets sender match option.
index bdf43fdd6e59c7ddee9148a3ef60c84cc85ef5b9..097ca3a7fa8109ae087a387ae90303cbf8aaf62a 100644 (file)
@@ -108,7 +108,7 @@ type Message struct {
        Type
        Flags
        Headers map[HeaderField]Variant
-       Body    []interface{}
+       Body    []any
 
        serial uint32
 }
@@ -158,7 +158,9 @@ func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
        if err != nil {
                return nil, err
        }
-       binary.Read(bytes.NewBuffer(b), order, &hlength)
+       if err := binary.Read(bytes.NewBuffer(b), order, &hlength); err != nil {
+               return nil, err
+       }
        if hlength+length+16 > 1<<27 {
                return nil, InvalidMessageError("message is too long")
        }
@@ -186,7 +188,7 @@ func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
                }
        }
 
-       if err = msg.IsValid(); err != nil {
+       if err = msg.validateHeader(); err != nil {
                return nil, err
        }
        sig, _ := msg.Headers[FieldSignature].value.(Signature)
@@ -230,7 +232,7 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds
        if err := msg.validateHeader(); err != nil {
                return nil, err
        }
-       var vs [7]interface{}
+       var vs [7]any
        switch order {
        case binary.LittleEndian:
                vs[0] = byte('l')
@@ -265,12 +267,14 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds
                return
        }
        enc.align(8)
-       body.WriteTo(&buf)
+       if _, err := body.WriteTo(&buf); err != nil {
+               return nil, err
+       }
        if buf.Len() > 1<<27 {
-               return make([]int, 0), InvalidMessageError("message is too long")
+               return nil, InvalidMessageError("message is too long")
        }
        if _, err := buf.WriteTo(out); err != nil {
-               return make([]int, 0), err
+               return nil, err
        }
        return enc.fds, nil
 }
@@ -286,8 +290,7 @@ func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error)
 // IsValid checks whether msg is a valid message and returns an
 // InvalidMessageError or FormatError if it is not.
 func (msg *Message) IsValid() error {
-       var b bytes.Buffer
-       return msg.EncodeTo(&b, nativeEndian)
+       return msg.EncodeTo(io.Discard, nativeEndian)
 }
 
 func (msg *Message) validateHeader() error {
index 664abb7fbabb6fe927c097b64a9cfbebd914cf79..954d3807123f1caba4c2fc1846b11ec5746102ca 100644 (file)
@@ -9,15 +9,15 @@ import (
 // BusObject is the interface of a remote object on which methods can be
 // invoked.
 type BusObject interface {
-       Call(method string, flags Flags, args ...interface{}) *Call
-       CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
-       Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
-       GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call
+       Call(method string, flags Flags, args ...any) *Call
+       CallWithContext(ctx context.Context, method string, flags Flags, args ...any) *Call
+       Go(method string, flags Flags, ch chan *Call, args ...any) *Call
+       GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...any) *Call
        AddMatchSignal(iface, member string, options ...MatchOption) *Call
        RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
        GetProperty(p string) (Variant, error)
-       StoreProperty(p string, value interface{}) error
-       SetProperty(p string, v interface{}) error
+       StoreProperty(p string, value any) error
+       SetProperty(p string, v any) error
        Destination() string
        Path() ObjectPath
 }
@@ -30,12 +30,12 @@ type Object struct {
 }
 
 // Call calls a method with (*Object).Go and waits for its reply.
-func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
+func (o *Object) Call(method string, flags Flags, args ...any) *Call {
        return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done
 }
 
 // CallWithContext acts like Call but takes a context
-func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
+func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...any) *Call {
        return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
 }
 
@@ -46,7 +46,7 @@ func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags
 // Deprecated: use (*Conn) AddMatchSignal instead.
 func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
        base := []MatchOption{
-               withMatchType("signal"),
+               withMatchTypeSignal(),
                WithMatchInterface(iface),
                WithMatchMember(member),
        }
@@ -65,7 +65,7 @@ func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *C
 // Deprecated: use (*Conn) RemoveMatchSignal instead.
 func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
        base := []MatchOption{
-               withMatchType("signal"),
+               withMatchTypeSignal(),
                WithMatchInterface(iface),
                WithMatchMember(member),
        }
@@ -89,16 +89,16 @@ func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption)
 //
 // If the method parameter contains a dot ('.'), the part before the last dot
 // specifies the interface on which the method is called.
-func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
+func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...any) *Call {
        return o.createCall(context.Background(), method, flags, ch, args...)
 }
 
 // GoWithContext acts like Go but takes a context
-func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
+func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...any) *Call {
        return o.createCall(ctx, method, flags, ch, args...)
 }
 
-func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
+func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...any) *Call {
        if ctx == nil {
                panic("nil context")
        }
@@ -136,7 +136,7 @@ func (o *Object) GetProperty(p string) (Variant, error) {
 // StoreProperty calls org.freedesktop.DBus.Properties.Get on the given
 // object. The property name must be given in interface.member notation.
 // It stores the returned property into the provided value.
-func (o *Object) StoreProperty(p string, value interface{}) error {
+func (o *Object) StoreProperty(p string, value any) error {
        idx := strings.LastIndex(p, ".")
        if idx == -1 || idx+1 == len(p) {
                return errors.New("dbus: invalid property " + p)
@@ -151,7 +151,14 @@ func (o *Object) StoreProperty(p string, value interface{}) error {
 
 // SetProperty calls org.freedesktop.DBus.Properties.Set on the given
 // object. The property name must be given in interface.member notation.
-func (o *Object) SetProperty(p string, v interface{}) error {
+// Panics if v is not a valid Variant type.
+func (o *Object) SetProperty(p string, v any) error {
+       // v might already be a variant...
+       variant, ok := v.(Variant)
+       if !ok {
+               // Otherwise, make it into one.
+               variant = MakeVariant(v)
+       }
        idx := strings.LastIndex(p, ".")
        if idx == -1 || idx+1 == len(p) {
                return errors.New("dbus: invalid property " + p)
@@ -160,7 +167,7 @@ func (o *Object) SetProperty(p string, v interface{}) error {
        iface := p[:idx]
        prop := p[idx+1:]
 
-       return o.Call("org.freedesktop.DBus.Properties.Set", 0, iface, prop, v).Err
+       return o.Call("org.freedesktop.DBus.Properties.Set", 0, iface, prop, variant).Err
 }
 
 // Destination returns the destination that calls on (o *Object) are sent to.
index ef2fcdba179cf83942d8bb235601935b249a649d..886b5eb16b381714c1f2d0a93174602bf2a09efd 100644 (file)
@@ -93,7 +93,7 @@ func (scd *sequentialSignalChannelData) bufferSignals() {
        var queue []*Signal
        for {
                if len(queue) == 0 {
-                       signal, ok := <- scd.in
+                       signal, ok := <-scd.in
                        if !ok {
                                return
                        }
index e4e0389fdf091c672f27e8852ee05b8170dd7777..24d4ad6329b9ac891464a943e590a3395ca8d0c9 100644 (file)
@@ -22,7 +22,7 @@ type Handler interface {
 // of Interface lookup is up to the implementation of
 // the ServerObject. The ServerObject implementation may
 // choose to implement empty string as a valid interface
-// represeting all methods or not per the D-Bus specification.
+// representing all methods or not per the D-Bus specification.
 type ServerObject interface {
        LookupInterface(name string) (Interface, bool)
 }
@@ -38,17 +38,17 @@ type Interface interface {
 // A Method represents the exposed methods on D-Bus.
 type Method interface {
        // Call requires that all arguments are decoded before being passed to it.
-       Call(args ...interface{}) ([]interface{}, error)
+       Call(args ...any) ([]any, error)
        NumArguments() int
        NumReturns() int
        // ArgumentValue returns a representative value for the argument at position
        // it should be of the proper type. reflect.Zero would be a good mechanism
        // to use for this Value.
-       ArgumentValue(position int) interface{}
+       ArgumentValue(position int) any
        // ReturnValue returns a representative value for the return at position
        // it should be of the proper type. reflect.Zero would be a good mechanism
        // to use for this Value.
-       ReturnValue(position int) interface{}
+       ReturnValue(position int) any
 }
 
 // An Argument Decoder can decode arguments using the non-standard mechanism
@@ -65,7 +65,7 @@ type ArgumentDecoder interface {
        // To decode the arguments of a method the sender and message are
        // provided in case the semantics of the implementer provides access
        // to these as part of the method invocation.
-       DecodeArguments(conn *Conn, sender string, msg *Message, args []interface{}) ([]interface{}, error)
+       DecodeArguments(conn *Conn, sender string, msg *Message, args []any) ([]any, error)
 }
 
 // A SignalHandler is responsible for delivering a signal.
@@ -93,7 +93,7 @@ type SignalRegistrar interface {
 // "org.freedesktop.DBus.Error.Failed" error. By implementing this
 // interface as well a custom encoding may be provided.
 type DBusError interface {
-       DBusError() (string, []interface{})
+       DBusError() (string, []any)
 }
 
 // SerialGenerator is responsible for serials generation.
index 6b9cadb5fbc377c82af39b7c01f96fb0aa59054a..ed5accc94d28330c25d76ee7ac0a004b19eb25ef 100644 (file)
@@ -31,7 +31,7 @@ type Signature struct {
 
 // SignatureOf returns the concatenation of all the signatures of the given
 // values. It panics if one of them is not representable in D-Bus.
-func SignatureOf(vs ...interface{}) Signature {
+func SignatureOf(vs ...any) Signature {
        var s string
        for _, v := range vs {
                s += getSignature(reflect.TypeOf(v), &depthCounter{})
@@ -183,19 +183,19 @@ func (cnt *depthCounter) Valid() bool {
        return cnt.arrayDepth <= 32 && cnt.structDepth <= 32 && cnt.dictEntryDepth <= 32
 }
 
-func (cnt depthCounter) EnterArray() *depthCounter {
+func (cnt *depthCounter) EnterArray() *depthCounter {
        cnt.arrayDepth++
-       return &cnt
+       return cnt
 }
 
-func (cnt depthCounter) EnterStruct() *depthCounter {
+func (cnt *depthCounter) EnterStruct() *depthCounter {
        cnt.structDepth++
-       return &cnt
+       return cnt
 }
 
-func (cnt depthCounter) EnterDictEntry() *depthCounter {
+func (cnt *depthCounter) EnterDictEntry() *depthCounter {
        cnt.dictEntryDepth++
-       return &cnt
+       return cnt
 }
 
 // Try to read a single type from this string. If it was successful, err is nil
@@ -221,6 +221,9 @@ func validSingle(s string, depth *depthCounter) (err error, rem string) {
                        i++
                        rem = s[i+1:]
                        s = s[2:i]
+                       if len(s) == 0 {
+                               return SignatureError{Sig: s, Reason: "empty dict"}, ""
+                       }
                        if err, _ = validSingle(s[:1], depth.EnterArray().EnterDictEntry()); err != nil {
                                return err, ""
                        }
index 697739efafbfb4757f8762a6e9d392b26a378e9f..916e17b6eefbca4f8eb390e8c88614da84e59f92 100644 (file)
@@ -1,11 +1,12 @@
-//+build !windows
+//go:build !windows
+// +build !windows
 
 package dbus
 
 import (
        "errors"
-       "io/ioutil"
        "net"
+       "os"
 )
 
 func init() {
@@ -27,12 +28,14 @@ func newNonceTcpTransport(keys string) (transport, error) {
        if err != nil {
                return nil, err
        }
-       b, err := ioutil.ReadFile(noncefile)
+       b, err := os.ReadFile(noncefile)
        if err != nil {
+               socket.Close()
                return nil, err
        }
        _, err = socket.Write(b)
        if err != nil {
+               socket.Close()
                return nil, err
        }
        return NewConn(socket)
index 0a8c712ebdfa568689b79a23c00bfcefa23a67c8..6a59637ae8a588bf5f35e8b47dfc92c6b1f61f87 100644 (file)
@@ -1,4 +1,5 @@
-//+build !windows,!solaris
+//go:build !windows && !solaris
+// +build !windows,!solaris
 
 package dbus
 
@@ -11,10 +12,29 @@ import (
        "syscall"
 )
 
+// msghead represents the part of the message header
+// that has a constant size (byte order + 15 bytes).
+type msghead struct {
+       Type      Type
+       Flags     Flags
+       Proto     byte
+       BodyLen   uint32
+       Serial    uint32
+       HeaderLen uint32
+}
+
 type oobReader struct {
        conn *net.UnixConn
        oob  []byte
        buf  [4096]byte
+
+       // The following fields are used to reduce memory allocs.
+       headers  []header
+       csheader []byte
+       b        *bytes.Buffer
+       r        *bytes.Reader
+       dec      *decoder
+       msghead
 }
 
 func (o *oobReader) Read(b []byte) (n int, err error) {
@@ -35,6 +55,14 @@ type unixTransport struct {
        hasUnixFDs bool
 }
 
+func newUnixTransportFromConn(conn *net.UnixConn) transport {
+       t := new(unixTransport)
+       t.UnixConn = conn
+       t.hasUnixFDs = true
+
+       return t
+}
+
 func newUnixTransport(keys string) (transport, error) {
        var err error
 
@@ -70,28 +98,36 @@ func (t *unixTransport) EnableUnixFDs() {
 }
 
 func (t *unixTransport) ReadMessage() (*Message, error) {
-       var (
-               blen, hlen uint32
-               csheader   [16]byte
-               headers    []header
-               order      binary.ByteOrder
-               unixfds    uint32
-       )
        // To be sure that all bytes of out-of-band data are read, we use a special
        // reader that uses ReadUnix on the underlying connection instead of Read
        // and gathers the out-of-band data in a buffer.
        if t.rdr == nil {
-               t.rdr = &oobReader{conn: t.UnixConn}
+               t.rdr = &oobReader{
+                       conn: t.UnixConn,
+                       // This buffer is used to decode the part of the header that has a constant size.
+                       csheader: make([]byte, 16),
+                       b:        &bytes.Buffer{},
+                       // The reader helps to read from the buffer several times.
+                       r:   &bytes.Reader{},
+                       dec: &decoder{},
+               }
        } else {
-               t.rdr.oob = nil
+               t.rdr.oob = t.rdr.oob[:0]
+               t.rdr.headers = t.rdr.headers[:0]
        }
+       var (
+               r   = t.rdr.r
+               b   = t.rdr.b
+               dec = t.rdr.dec
+       )
 
-       // read the first 16 bytes (the part of the header that has a constant size),
-       // from which we can figure out the length of the rest of the message
-       if _, err := io.ReadFull(t.rdr, csheader[:]); err != nil {
+       _, err := io.ReadFull(t.rdr, t.rdr.csheader)
+       if err != nil {
                return nil, err
        }
-       switch csheader[0] {
+
+       var order binary.ByteOrder
+       switch t.rdr.csheader[0] {
        case 'l':
                order = binary.LittleEndian
        case 'B':
@@ -99,38 +135,62 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
        default:
                return nil, InvalidMessageError("invalid byte order")
        }
-       // csheader[4:8] -> length of message body, csheader[12:16] -> length of
-       // header fields (without alignment)
-       binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen)
-       binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen)
+
+       r.Reset(t.rdr.csheader[1:])
+       if err := binary.Read(r, order, &t.rdr.msghead); err != nil {
+               return nil, err
+       }
+
+       msg := &Message{
+               Type:   t.rdr.msghead.Type,
+               Flags:  t.rdr.msghead.Flags,
+               serial: t.rdr.msghead.Serial,
+       }
+       // Length of header fields (without alignment).
+       hlen := t.rdr.msghead.HeaderLen
        if hlen%8 != 0 {
                hlen += 8 - (hlen % 8)
        }
+       if hlen+t.rdr.msghead.BodyLen+16 > 1<<27 {
+               return nil, InvalidMessageError("message is too long")
+       }
 
-       // decode headers and look for unix fds
-       headerdata := make([]byte, hlen+4)
-       copy(headerdata, csheader[12:])
-       if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
+       // Decode headers and look for unix fds.
+       b.Reset()
+       if _, err = b.Write(t.rdr.csheader[12:]); err != nil {
                return nil, err
        }
-       dec := newDecoder(bytes.NewBuffer(headerdata), order, make([]int, 0))
+       if _, err = io.CopyN(b, t.rdr, int64(hlen)); err != nil {
+               return nil, err
+       }
+       dec.Reset(b, order, nil)
        dec.pos = 12
        vs, err := dec.Decode(Signature{"a(yv)"})
        if err != nil {
                return nil, err
        }
-       Store(vs, &headers)
-       for _, v := range headers {
+       if err = Store(vs, &t.rdr.headers); err != nil {
+               return nil, err
+       }
+       var unixfds uint32
+       for _, v := range t.rdr.headers {
                if v.Field == byte(FieldUnixFDs) {
                        unixfds, _ = v.Variant.value.(uint32)
                }
        }
-       all := make([]byte, 16+hlen+blen)
-       copy(all, csheader[:])
-       copy(all[16:], headerdata[4:])
-       if _, err := io.ReadFull(t.rdr, all[16+hlen:]); err != nil {
+
+       msg.Headers = make(map[HeaderField]Variant)
+       for _, v := range t.rdr.headers {
+               msg.Headers[HeaderField(v.Field)] = v.Variant
+       }
+
+       dec.align(8)
+       body := make([]byte, t.rdr.BodyLen)
+       if _, err = io.ReadFull(t.rdr, body); err != nil {
                return nil, err
        }
+       r.Reset(body)
+
        if unixfds != 0 {
                if !t.hasUnixFDs {
                        return nil, errors.New("dbus: got unix fds on unsupported transport")
@@ -147,8 +207,8 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
                if err != nil {
                        return nil, err
                }
-               msg, err := DecodeMessageWithFDs(bytes.NewBuffer(all), fds)
-               if err != nil {
+               dec.Reset(r, order, fds)
+               if err = decodeMessageBody(msg, dec); err != nil {
                        return nil, err
                }
                // substitute the values in the message body (which are indices for the
@@ -173,7 +233,27 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
                }
                return msg, nil
        }
-       return DecodeMessage(bytes.NewBuffer(all))
+
+       dec.Reset(r, order, nil)
+       if err = decodeMessageBody(msg, dec); err != nil {
+               return nil, err
+       }
+       return msg, nil
+}
+
+func decodeMessageBody(msg *Message, dec *decoder) error {
+       if err := msg.validateHeader(); err != nil {
+               return err
+       }
+
+       sig, _ := msg.Headers[FieldSignature].value.(Signature)
+       if sig.str == "" {
+               return nil
+       }
+
+       var err error
+       msg.Body, err = dec.Decode(sig)
+       return err
 }
 
 func (t *unixTransport) SendMessage(msg *Message) error {
index 1b5ed2089d0b9507ef0128857b2e4cab658b67cb..ff2284c83829c40b2e6ce728ef3ea1b6f445bf99 100644 (file)
@@ -7,39 +7,41 @@
 
 package dbus
 
-/*
-const int sizeofPtr = sizeof(void*);
-#define _WANT_UCRED
-#include <sys/types.h>
-#include <sys/ucred.h>
-*/
-import "C"
-
 import (
        "io"
        "os"
        "syscall"
        "unsafe"
+
+       "golang.org/x/sys/unix"
 )
 
 // http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go
 // https://golang.org/src/syscall/ztypes_freebsd_amd64.go
+//
+// Note: FreeBSD actually uses a 'struct cmsgcred' which starts with
+// these fields and adds a list of the additional groups for the
+// sender.
 type Ucred struct {
-       Pid int32
-       Uid uint32
-       Gid uint32
+       Pid  int32
+       Uid  uint32
+       Euid uint32
+       Gid  uint32
 }
 
-// http://golang.org/src/pkg/syscall/types_linux.go
-// https://golang.org/src/syscall/types_freebsd.go
-// https://github.com/freebsd/freebsd/blob/master/sys/sys/ucred.h
+// https://github.com/freebsd/freebsd/blob/master/sys/sys/socket.h
+//
+// The cmsgcred structure contains the above four fields, followed by
+// a uint16 count of additional groups, uint16 padding to align and a
+// 16 element array of uint32 for the additional groups. The size is
+// the same across all supported platforms.
 const (
-       SizeofUcred = C.sizeof_struct_ucred
+       SizeofCmsgcred = 84 // 4*4 + 2*2 + 16*4
 )
 
 // http://golang.org/src/pkg/syscall/sockcmsg_unix.go
 func cmsgAlignOf(salen int) int {
-       salign := C.sizeofPtr
+       salign := unix.SizeofPtr
 
        return (salen + salign - 1) & ^(salign - 1)
 }
@@ -54,11 +56,11 @@ func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer {
 // for sending to another process. This can be used for
 // authentication.
 func UnixCredentials(ucred *Ucred) []byte {
-       b := make([]byte, syscall.CmsgSpace(SizeofUcred))
+       b := make([]byte, syscall.CmsgSpace(SizeofCmsgcred))
        h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
        h.Level = syscall.SOL_SOCKET
        h.Type = syscall.SCM_CREDS
-       h.SetLen(syscall.CmsgLen(SizeofUcred))
+       h.SetLen(syscall.CmsgLen(SizeofCmsgcred))
        *((*Ucred)(cmsgData(h))) = *ucred
        return b
 }
index ca3dbe16a44df325f6df0eaa4775e3867f28adc9..bf98ddea7354433c1cd9204aaccd191fc5f9efe9 100644 (file)
@@ -11,17 +11,17 @@ import (
 // Variant represents the D-Bus variant type.
 type Variant struct {
        sig   Signature
-       value interface{}
+       value any
 }
 
 // MakeVariant converts the given value to a Variant. It panics if v cannot be
 // represented as a D-Bus type.
-func MakeVariant(v interface{}) Variant {
+func MakeVariant(v any) Variant {
        return MakeVariantWithSignature(v, SignatureOf(v))
 }
 
 // MakeVariantWithSignature converts the given value to a Variant.
-func MakeVariantWithSignature(v interface{}, s Signature) Variant {
+func MakeVariantWithSignature(v any, s Signature) Variant {
        return Variant{s, v}
 }
 
@@ -73,7 +73,7 @@ func (v Variant) format() (string, bool) {
        }
        rv := reflect.ValueOf(v.value)
        switch rv.Kind() {
-       case reflect.Slice:
+       case reflect.Slice, reflect.Array:
                if rv.Len() == 0 {
                        return "[]", false
                }
@@ -119,6 +119,25 @@ func (v Variant) format() (string, bool) {
                }
                buf.WriteByte('}')
                return buf.String(), unamb
+       case reflect.Struct:
+               if rv.NumField() == 0 {
+                       return "()", false
+               }
+               unamb := true
+               var buf bytes.Buffer
+               buf.WriteByte('(')
+               for i := 0; i < rv.NumField(); i++ {
+                       s, b := MakeVariant(rv.Field(i).Interface()).format()
+                       unamb = unamb && b
+                       buf.WriteString(s)
+                       buf.WriteString(",")
+                       if i != rv.NumField()-1 {
+                               buf.WriteString(" ")
+                       }
+               }
+               buf.WriteByte(')')
+               return buf.String(), unamb
+
        }
        return `"INVALID"`, true
 }
@@ -139,12 +158,12 @@ func (v Variant) String() string {
 }
 
 // Value returns the underlying value of v.
-func (v Variant) Value() interface{} {
+func (v Variant) Value() any {
        return v.value
 }
 
 // Store converts the variant into a native go type using the same
 // mechanism as the "Store" function.
-func (v Variant) Store(value interface{}) error {
+func (v Variant) Store(value any) error {
        return storeInterfaces(v.value, value)
 }
index bf1398c8f057281618649750221c19dbe94c3972..a0649c5ca5162fb512bf5f3d124df15de4628b6d 100644 (file)
@@ -67,7 +67,7 @@ func (l *varLexer) emit(t varTokenType) {
        l.start = l.pos
 }
 
-func (l *varLexer) errorf(format string, v ...interface{}) lexState {
+func (l *varLexer) errorf(format string, v ...any) lexState {
        l.tokens = append(l.tokens, varToken{
                tokError,
                fmt.Sprintf(format, v...),
index d20f5da6dd22d7c2e31b7bfbafbb15bc6bf09901..3f45f0a757caa8de121a8c171679f59b437bcd26 100644 (file)
@@ -33,7 +33,7 @@ type varNode interface {
        Infer() (Signature, error)
        String() string
        Sigs() sigSet
-       Value(Signature) (interface{}, error)
+       Value(Signature) (any, error)
 }
 
 func varMakeNode(p *varParser) (varNode, error) {
@@ -134,7 +134,7 @@ func (s sigSet) ToArray() sigSet {
 type numNode struct {
        sig Signature
        str string
-       val interface{}
+       val any
 }
 
 var numSigSet = sigSet{
@@ -169,7 +169,7 @@ func (n numNode) Sigs() sigSet {
        return numSigSet
 }
 
-func (n numNode) Value(sig Signature) (interface{}, error) {
+func (n numNode) Value(sig Signature) (any, error) {
        if n.sig.str != "" && n.sig != sig {
                return nil, varTypeError{n.str, sig}
        }
@@ -190,7 +190,7 @@ func varMakeNumNode(tok varToken, sig Signature) (varNode, error) {
        return numNode{sig: sig, val: num}, nil
 }
 
-func varNumAs(s string, sig Signature) (interface{}, error) {
+func varNumAs(s string, sig Signature) (any, error) {
        isUnsigned := false
        size := 32
        switch sig.str {
@@ -220,20 +220,20 @@ func varNumAs(s string, sig Signature) (interface{}, error) {
                return nil, varTypeError{s, sig}
        }
        base := 10
-       if strings.HasPrefix(s, "0x") {
+       if after, ok := strings.CutPrefix(s, "0x"); ok {
                base = 16
-               s = s[2:]
+               s = after
        }
-       if strings.HasPrefix(s, "0") && len(s) != 1 {
+       if after, ok := strings.CutPrefix(s, "0"); ok && len(s) != 1 {
                base = 8
-               s = s[1:]
+               s = after
        }
        if isUnsigned {
                i, err := strconv.ParseUint(s, base, size)
                if err != nil {
                        return nil, err
                }
-               var v interface{} = i
+               var v any = i
                switch sig.str {
                case "y":
                        v = byte(i)
@@ -248,7 +248,7 @@ func varNumAs(s string, sig Signature) (interface{}, error) {
        if err != nil {
                return nil, err
        }
-       var v interface{} = i
+       var v any = i
        switch sig.str {
        case "n":
                v = int16(i)
@@ -260,8 +260,8 @@ func varNumAs(s string, sig Signature) (interface{}, error) {
 
 type stringNode struct {
        sig Signature
-       str string      // parsed
-       val interface{} // has correct type
+       str string // parsed
+       val any    // has correct type
 }
 
 var stringSigSet = sigSet{
@@ -285,7 +285,7 @@ func (n stringNode) Sigs() sigSet {
        return stringSigSet
 }
 
-func (n stringNode) Value(sig Signature) (interface{}, error) {
+func (n stringNode) Value(sig Signature) (any, error) {
        if n.sig.str != "" && n.sig != sig {
                return nil, varTypeError{n.str, sig}
        }
@@ -407,7 +407,7 @@ func (boolNode) Sigs() sigSet {
        return boolSigSet
 }
 
-func (b boolNode) Value(sig Signature) (interface{}, error) {
+func (b boolNode) Value(sig Signature) (any, error) {
        if sig.str != "b" {
                return nil, varTypeError{b.String(), sig}
        }
@@ -417,7 +417,6 @@ func (b boolNode) Value(sig Signature) (interface{}, error) {
 type arrayNode struct {
        set      sigSet
        children []varNode
-       val      interface{}
 }
 
 func (n arrayNode) Infer() (Signature, error) {
@@ -446,7 +445,7 @@ func (n arrayNode) Sigs() sigSet {
        return n.set
 }
 
-func (n arrayNode) Value(sig Signature) (interface{}, error) {
+func (n arrayNode) Value(sig Signature) (any, error) {
        if n.set.Empty() {
                // no type information whatsoever, so this must be an empty slice
                return reflect.MakeSlice(typeFor(sig.str), 0, 0).Interface(), nil
@@ -537,7 +536,7 @@ func (variantNode) Sigs() sigSet {
        return variantSet
 }
 
-func (n variantNode) Value(sig Signature) (interface{}, error) {
+func (n variantNode) Value(sig Signature) (any, error) {
        if sig.str != "v" {
                return nil, varTypeError{n.String(), sig}
        }
@@ -574,7 +573,6 @@ type dictEntry struct {
 type dictNode struct {
        kset, vset sigSet
        children   []dictEntry
-       val        interface{}
 }
 
 func (n dictNode) Infer() (Signature, error) {
@@ -614,7 +612,7 @@ func (n dictNode) Sigs() sigSet {
        return r
 }
 
-func (n dictNode) Value(sig Signature) (interface{}, error) {
+func (n dictNode) Value(sig Signature) (any, error) {
        set := n.Sigs()
        if set.Empty() {
                // no type information -> empty dict
@@ -749,7 +747,7 @@ func (b byteStringNode) Sigs() sigSet {
        return byteStringSet
 }
 
-func (b byteStringNode) Value(sig Signature) (interface{}, error) {
+func (b byteStringNode) Value(sig Signature) (any, error) {
        if sig.str != "ay" {
                return nil, varTypeError{b.String(), sig}
        }
index a89d4fe711d9c278b7f6b6f89343e1af9c698909..c9f1c1a8b67dcff28c009e7385aa4e2eb112380f 100644 (file)
@@ -920,8 +920,8 @@ github.com/gobwas/glob/syntax/ast
 github.com/gobwas/glob/syntax/lexer
 github.com/gobwas/glob/util/runes
 github.com/gobwas/glob/util/strings
-# github.com/godbus/dbus/v5 v5.1.0
-## explicit; go 1.12
+# github.com/godbus/dbus/v5 v5.2.0
+## explicit; go 1.20
 github.com/godbus/dbus/v5
 # github.com/gogo/protobuf v1.3.2
 ## explicit; go 1.15