dbus

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 9, 2026 License: BSD-3-Clause Imports: 17 Imported by: 0

README

dbus — go-freedesktop

ci Go Reference License Go Coverage

A from-scratch, pure-Go implementation of the D-Bus message protocol — the freedesktop IPC bus every Linux desktop service speaks. CGO-free, zero non-standard dependencies, built directly against the D-Bus specification. It is the go-freedesktop family's own D-Bus layer, a sovereign replacement for github.com/godbus/dbus/v5 whose public surface is kept deliberately close so migrating off the third-party/cgo-adjacent dependency is near-mechanical.

dbus is the open freedesktop protocol name — a spec, like the shared MIME-info database or the notifications interface — not a borrowed project name.

Scope — the whole stack, phased

The library implements the four layers a D-Bus client and service needs:

  • Wire codec — the complete type system (y b n q i u x t d h, the string-likes s o g, arrays a, structs (...), variants v, and dict arrays a{..}), with correct alignment/padding and both byte orders (little l and big B, validated on real s390x/ppc64le hardware models in CI). Messages carry the standard header (a(yv) fields, endian flag, type, flags, protocol version, body length, serial). Go values map naturally, with Variant, ObjectPath, Signature, MakeVariant, and the Marshaler / Unmarshaler escape hatches.
  • Auth & transport — the unix-socket transport (leading \0, line-based SASL: AUTH EXTERNAL <uid> with AUTH ANONYMOUS fallback, optional NEGOTIATE_UNIX_FD, BEGIN, and REJECTED/OK/ERROR handling), plus address parsing for unix:path= / unix:abstract= and the session/system bus environment variables.
  • Connection — a serial counter, method-call→reply matching that is context-cancellable and always bounded by a hard timeout (a silent or misbehaving peer can never hang a caller), the Hello handshake, an incoming dispatch loop, and signal subscription (AddMatch/RemoveMatch + a Signal(chan) fan-out).
  • Server / export — publish a Go value's methods on an object path and interface with reflection dispatch (a trailing *Error return becomes an error reply), RequestName, Emit, and the built-in org.freedesktop.DBus.Introspectable, .Properties, and .Peer interfaces.

Install

go get github.com/go-freedesktop/dbus

Quickstart

package main

import (
	"fmt"

	"github.com/go-freedesktop/dbus"
)

func main() {
	conn, err := dbus.ConnectSessionBus()
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// Call a method: list the names currently on the bus.
	var names []string
	err = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus").
		Call("org.freedesktop.DBus.ListNames", 0).Store(&names)
	if err != nil {
		panic(err)
	}
	fmt.Println(names)
}

Exporting an object is symmetric:

type Greeter struct{}

func (Greeter) Greet(name string) (string, *dbus.Error) {
	return "Hello " + name, nil
}

conn.Export(Greeter{}, "/com/example/Greeter", "com.example.Greeter1")
conn.RequestName("com.example.Greeter", dbus.NameFlagDoNotQueue)

Public API (server/export surface)

Symbol Purpose
ConnectSessionBus() / ConnectSystemBus() dial a bus and perform Hello
Dial(address) / NewConn(net.Conn) connect (with SASL) / wrap an authenticated transport
(*Conn).Object(dest, path) BusObject handle for a remote object
BusObject.Call / CallWithContext(...) *Call invoke a method (hard-timeout bounded)
(*Call).Store(&dst...) decode a reply, or return its error
(*Conn).Export(v, path, iface) publish a Go value's methods (reflection dispatch)
(*Conn).RequestName / ReleaseName(name, flags) own / release a well-known name
(*Conn).Emit(path, "iface.member", args...) emit a signal
(*Conn).Signal(ch) / AddMatch / RemoveMatch subscribe to signals
(*Conn).ExportProperties(path, iface, props) serve org.freedesktop.DBus.Properties
(*Conn).EmitPropertiesChanged(...) emit PropertiesChanged
Variant / MakeVariant / MakeVariantWithSignature self-describing values
ObjectPath / Signature / ParseSignature validated wire identifiers
Error / NewError / MakeFailedError D-Bus error replies (implements error)
Marshal / Unmarshal / Store the low-level codec

The names and shapes (Export, RequestName, Emit, Variant, *Error, MakeVariant, ObjectPath, Signature) mirror godbus/dbus/v5 so a consumer such as go-freedesktop/notifications migrates with near-mechanical edits.

Never hangs

Every method call is bounded twice over: by the caller's context.Context and, when that carries no deadline, by the package-level DefaultCallTimeout. The read loop fails every in-flight call when the connection drops, and socket writes carry their own deadline. A peer that stops responding produces a context.DeadlineExceeded, never a stuck goroutine.

Tests & coverage

CGO_ENABLED=0 go test ./...100% statement coverage, including every error branch. The codec is exercised by table round-trips under both byte orders plus targeted truncation/misalignment/bad-signature cases; the connection, auth, and export layers run over in-process net.Pipe pairs and real unix sockets, every one bounded by a test timeout and context deadline so CI can never hang. CI also runs the suite on the six supported 64-bit targets (amd64/arm64 natively, riscv64/loong64/ppc64le/s390x under qemu-user); the big-endian s390x run validates the B wire order end to end. The -race coverage gate is the only step that enables cgo.

Real-dbus-daemon interoperability

A gated end-to-end test (integration_test.go, //go:build linux) proves interop with the reference dbus-daemon. Run it under a private session bus:

DBUS_GOFD_INTEGRATION=1 dbus-run-session -- go test -run TestIntegrationRealBus -v

It connects, requests a name, exports an object, calls it (and a deliberately-failing method) from a second connection, introspects it, and emits/receives a signal — all against the real daemon.

License

BSD-3-Clause. Copyright (c) the go-freedesktop/dbus authors.


Note: the go-freedesktop org landing page and MkDocs site are deferred to the Wave-2 documentation sweep; this repo ships the README and .github workflow for now.

Documentation

Overview

Package dbus is a pure-Go, CGO-free implementation of the D-Bus wire protocol, authentication, transport, connection and object-export layers, built from scratch against the D-Bus specification with zero non-standard dependencies.

The public surface deliberately mirrors the shape of the widely used github.com/godbus/dbus/v5 API (Conn, Object, Variant, ObjectPath, Signature, Error, Export, RequestName, Emit, MakeVariant) so existing consumers can migrate off cgo/third-party code with near-mechanical edits.

Index

Constants

View Source
const (
	NameFlagAllowReplacement uint32 = 1 << 0
	NameFlagReplaceExisting  uint32 = 1 << 1
	NameFlagDoNotQueue       uint32 = 1 << 2

	NameReplyPrimaryOwner uint32 = 1
	NameReplyInQueue      uint32 = 2
	NameReplyExists       uint32 = 3
	NameReplyAlreadyOwner uint32 = 4
)

RequestName flags and reply codes (subset mirroring the bus API).

Variables

View Source
var DefaultCallTimeout = 30 * time.Second

DefaultCallTimeout is the hard ceiling applied to every method call whose context carries no earlier deadline. It guarantees a misbehaving or silent peer can never make a call block forever.

View Source
var ErrClosed = errors.New("dbus: connection closed")

ErrClosed is returned for operations on a closed connection.

Functions

func Marshal

func Marshal(order ByteOrder, vs ...interface{}) ([]byte, error)

Marshal encodes vs into the D-Bus wire format using byte order, returning the encoded bytes. Alignment is computed as if the encoding begins at an 8-aligned position (as a message body does), so the result may be embedded directly after an 8-padded header.

func Store

func Store(src []interface{}, dsts ...interface{}) error

Store coerces the dynamically-decoded values in src into the pointer targets dsts (as returned by Unmarshal), mirroring github.com/godbus/dbus's Store: a *T receives a T, a *[]X a homogeneous array, a *map a dict, a *struct the fields of a struct, and an interface{} the value verbatim.

func Unmarshal

func Unmarshal(data []byte, order ByteOrder, sig Signature) ([]interface{}, int, error)

Unmarshal decodes every top-level type in sig from data (interpreted with byte order) into natural Go values, returning them and the number of bytes consumed. The decode begins at an 8-aligned offset, matching Marshal.

func WriteMessage

func WriteMessage(w io.Writer, m *Message, order ByteOrder) error

WriteMessage encodes m with order and writes it to w.

Types

type BusObject

type BusObject interface {
	Call(method string, flags Flags, args ...interface{}) *Call
	CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
	GetProperty(name string) (Variant, error)
	SetProperty(name string, value interface{}) error
	Path() ObjectPath
	Destination() string
}

BusObject is a handle to a remote object at a destination and path, on which methods can be called.

type ByteOrder

type ByteOrder = binary.ByteOrder

ByteOrder selects the wire byte order. D-Bus messages are either little-endian ('l') or big-endian ('B'); both are supported and negotiated per message via the header's first byte.

type Call

type Call struct {
	Destination string
	Path        ObjectPath
	Method      string // "interface.member"
	Args        []interface{}
	Body        []interface{}
	Err         error
}

Call is a completed (or failed) method call: Body holds the reply arguments, Err any error (including a remote *Error).

func (*Call) Store

func (c *Call) Store(dsts ...interface{}) error

Store decodes the reply body into the provided pointers, mirroring (*Conn).Store semantics. It returns the call's error if it failed.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a connection to a D-Bus message bus.

func ConnectSessionBus

func ConnectSessionBus() (*Conn, error)

ConnectSessionBus dials the session bus (DBUS_SESSION_BUS_ADDRESS) and sends Hello, returning a connection with an assigned unique name.

func ConnectSystemBus

func ConnectSystemBus() (*Conn, error)

ConnectSystemBus dials the system bus and sends Hello.

func Dial

func Dial(address string) (*Conn, error)

Dial connects to the bus at address, authenticates (EXTERNAL, then ANONYMOUS) and returns a ready connection. It does not send Hello; callers wanting a unique name should use ConnectSessionBus/ConnectSystemBus or call Hello themselves.

func NewConn

func NewConn(transport net.Conn) *Conn

NewConn wraps an already-connected, already-authenticated transport (for example one half of a net.Pipe in tests) and starts serving it.

func (*Conn) AddMatch

func (c *Conn) AddMatch(rule string) error

AddMatch installs a match rule on the bus so matching signals are routed to this connection.

func (*Conn) Close

func (c *Conn) Close() error

Close shuts the connection down, failing every pending call.

func (*Conn) Emit

func (c *Conn) Emit(path ObjectPath, name string, args ...interface{}) error

Emit sends a signal from the local object at path. name is "interface.member".

func (*Conn) EmitPropertiesChanged

func (c *Conn) EmitPropertiesChanged(path ObjectPath, iface string, changed map[string]interface{}) error

EmitPropertiesChanged emits org.freedesktop.DBus.Properties.PropertiesChanged for the named interface, carrying the changed name/value pairs.

func (*Conn) Export

func (c *Conn) Export(v interface{}, path ObjectPath, iface string) error

Export publishes the exported methods of v under the given object path and interface name. Incoming method calls addressed to that path and interface are dispatched to the matching method by reflection. A method may return any number of D-Bus-representable values optionally followed by a *Error, which (when non-nil) is sent back as an error reply.

func (*Conn) ExportProperties

func (c *Conn) ExportProperties(path ObjectPath, iface string, props map[string]*Prop) error

ExportProperties publishes a set of properties for one interface on one object path, served through org.freedesktop.DBus.Properties. props maps property name to its definition.

func (*Conn) Hello

func (c *Conn) Hello() (string, error)

Hello performs the org.freedesktop.DBus.Hello handshake and records the unique name the bus assigns.

func (*Conn) Names

func (c *Conn) Names() []string

Names returns the unique name followed by any acquired well-known names.

func (*Conn) Object

func (c *Conn) Object(dest string, path ObjectPath) BusObject

Object returns a handle to the object at path on the peer named dest.

func (*Conn) ReleaseName

func (c *Conn) ReleaseName(name string) (uint32, error)

ReleaseName asks the bus to release a previously requested well-known name.

func (*Conn) RemoveMatch

func (c *Conn) RemoveMatch(rule string) error

RemoveMatch removes a previously installed match rule.

func (*Conn) RemoveSignal

func (c *Conn) RemoveSignal(ch chan<- *Signal)

RemoveSignal removes a previously registered signal channel.

func (*Conn) RequestName

func (c *Conn) RequestName(name string, flags uint32) (uint32, error)

RequestName asks the bus to assign the well-known name to this connection. On success (primary owner or already owner) the name is recorded.

func (*Conn) Signal

func (c *Conn) Signal(ch chan<- *Signal)

Signal registers ch to receive every signal the connection observes. Combine with AddMatch to have the bus actually route signals to this connection.

type Error

type Error struct {
	Name string
	Body []interface{}
}

Error is a D-Bus error reply. It carries the error name (a valid interface name such as "org.freedesktop.DBus.Error.Failed") and an optional body, whose first element is conventionally a human-readable message string.

func MakeFailedError

func MakeFailedError(err error) *Error

MakeFailedError wraps an arbitrary Go error as a generic org.freedesktop.DBus.Error.Failed reply.

func NewError

func NewError(name string, body []interface{}) *Error

NewError builds an *Error with name and an optional body.

func (Error) Error

func (e Error) Error() string

Error implements the error interface.

type Flags

type Flags byte

Flags is the message flags bitfield.

const (
	// FlagNoReplyExpected suppresses the method_return/error reply.
	FlagNoReplyExpected Flags = 1 << iota
	// FlagNoAutoStart asks the bus not to auto-start a service.
	FlagNoAutoStart
	// FlagAllowInteractiveAuthorization permits interactive authorization.
	FlagAllowInteractiveAuthorization
)

Message flags.

type HeaderField

type HeaderField byte

HeaderField is a message header field code.

const (
	FieldPath HeaderField = iota + 1
	FieldInterface
	FieldMember
	FieldErrorName
	FieldReplySerial
	FieldDestination
	FieldSender
	FieldSignature
	FieldUnixFDs
)

Header field codes.

type Marshaler

type Marshaler interface {
	MarshalDBus(dst []byte, order ByteOrder, pos int) ([]byte, Signature, error)
}

Marshaler is implemented by types that encode themselves to the D-Bus wire format. MarshalDBus must append to and return dst, honouring the alignment implied by having already written pos bytes since the message start, and report the single complete signature it produced.

type Message

type Message struct {
	Type  MessageType
	Flags Flags

	Headers map[HeaderField]Variant
	Body    []interface{}
	// contains filtered or unexported fields
}

Message is a decoded D-Bus message: its type, flags, serial, header fields and body values.

func DecodeMessage

func DecodeMessage(data []byte) (*Message, int, error)

DecodeMessage decodes exactly one message from the front of data, returning the message and the total number of bytes it occupied.

func ReadMessage

func ReadMessage(r io.Reader) (*Message, error)

ReadMessage reads exactly one message from r. It first reads the 16-byte fixed prefix (through the header-array length), then the remaining header, padding and body.

func (*Message) Marshal

func (m *Message) Marshal(order ByteOrder) ([]byte, error)

Marshal encodes the message into wire bytes using the given byte order. It derives and installs the SIGNATURE header from Body when the body is non-empty, then validates the required header fields.

func (*Message) Serial

func (m *Message) Serial() uint32

Serial returns the message serial (0 until assigned by a connection).

func (*Message) SetSerial

func (m *Message) SetSerial(s uint32)

SetSerial sets the message serial.

type MessageType

type MessageType byte

MessageType identifies the kind of a D-Bus message.

const (
	TypeInvalid MessageType = iota
	TypeMethodCall
	TypeMethodReturn
	TypeError
	TypeSignal
)

Message types.

type ObjectPath

type ObjectPath string

ObjectPath is a D-Bus object path such as "/org/freedesktop/DBus". It marshals with the 'o' type code.

func (ObjectPath) IsValid

func (p ObjectPath) IsValid() bool

IsValid reports whether p is a syntactically valid object path: a non-empty sequence of "/"-separated elements of [A-Za-z0-9_], with a single leading slash, no trailing slash (except the root "/") and no empty elements.

type Prop

type Prop struct {
	Value    interface{}
	Writable bool
}

Prop is a single exported property: its current value and whether remote peers may write it via org.freedesktop.DBus.Properties.Set.

type Signal

type Signal struct {
	Sender string
	Path   ObjectPath
	Name   string // "interface.member"
	Body   []interface{}
}

Signal is a received D-Bus signal, delivered to channels registered with (*Conn).Signal.

type Signature

type Signature struct {
	// contains filtered or unexported fields
}

Signature is a validated D-Bus type signature: a possibly-empty concatenation of complete single types (e.g. "a{sv}", "(ii)", "s"). It marshals with the 'g' type code.

func ParseSignature

func ParseSignature(s string) (Signature, error)

ParseSignature validates s and returns it as a Signature. It reports an error for over-length input, unknown type codes, or malformed containers.

func ParseSignatureMust

func ParseSignatureMust(s string) Signature

ParseSignatureMust is ParseSignature for signatures known to be valid at author time (typically string literals): it returns the Signature and panics if s is malformed. It mirrors the like-named convenience in github.com/godbus/dbus/v5 so consumers can migrate with unchanged call sites.

func SignatureOf

func SignatureOf(vs ...interface{}) Signature

SignatureOf returns the concatenated signature of the Go values vs, inferring each type. It panics if any value has no D-Bus representation; callers that cannot guarantee representable inputs should use SignatureOfType.

func SignatureOfType

func SignatureOfType(t reflect.Type) (Signature, error)

SignatureOfType returns the signature for a single Go type, or an error if the type cannot be represented on the wire.

func (Signature) Empty

func (s Signature) Empty() bool

Empty reports whether the signature carries no types.

func (Signature) String

func (s Signature) String() string

String returns the textual signature.

type UnixFD

type UnixFD int32

UnixFD is the Go representation of the 'h' (UNIX file descriptor) type. This implementation encodes and decodes the wire index; out-of-band descriptor passing over the socket is not performed.

type UnixFDIndex

type UnixFDIndex uint32

UnixFDIndex is the on-wire index form of a UNIX file descriptor.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalDBus(src []byte, order ByteOrder, pos int) (int, error)
}

Unmarshaler is implemented by types that decode themselves from the D-Bus wire format, returning the number of bytes consumed from src.

type Variant

type Variant struct {
	// contains filtered or unexported fields
}

Variant is a D-Bus variant: a value carrying its own single complete type signature. It marshals with the 'v' type code.

func MakeVariant

func MakeVariant(value interface{}) Variant

MakeVariant wraps value in a Variant, inferring its signature from the Go type of value.

func MakeVariantWithSignature

func MakeVariantWithSignature(value interface{}, sig Signature) Variant

MakeVariantWithSignature wraps value in a Variant with the explicit signature sig (which must be a single complete type).

func (Variant) Signature

func (v Variant) Signature() Signature

Signature returns the variant's value signature.

func (Variant) String

func (v Variant) String() string

String renders the variant as an annotated literal, e.g. `@i 42` style is avoided in favour of a compact "<sig> value" form useful in diagnostics.

func (Variant) Value

func (v Variant) Value() interface{}

Value returns the Go value carried by the variant.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL