1package dbus
2
3import (
4	"bytes"
5	"encoding/binary"
6	"errors"
7	"io"
8	"reflect"
9	"strconv"
10)
11
12const protoVersion byte = 1
13
14// Flags represents the possible flags of a D-Bus message.
15type Flags byte
16
17const (
18	// FlagNoReplyExpected signals that the message is not expected to generate
19	// a reply. If this flag is set on outgoing messages, any possible reply
20	// will be discarded.
21	FlagNoReplyExpected Flags = 1 << iota
22	// FlagNoAutoStart signals that the message bus should not automatically
23	// start an application when handling this message.
24	FlagNoAutoStart
25	// FlagAllowInteractiveAuthorization may be set on a method call
26	// message to inform the receiving side that the caller is prepared
27	// to wait for interactive authorization, which might take a
28	// considerable time to complete. For instance, if this flag is set,
29	// it would be appropriate to query the user for passwords or
30	// confirmation via Polkit or a similar framework.
31	FlagAllowInteractiveAuthorization
32)
33
34// Type represents the possible types of a D-Bus message.
35type Type byte
36
37const (
38	TypeMethodCall Type = 1 + iota
39	TypeMethodReply
40	TypeError
41	TypeSignal
42	typeMax
43)
44
45func (t Type) String() string {
46	switch t {
47	case TypeMethodCall:
48		return "method call"
49	case TypeMethodReply:
50		return "reply"
51	case TypeError:
52		return "error"
53	case TypeSignal:
54		return "signal"
55	}
56	return "invalid"
57}
58
59// HeaderField represents the possible byte codes for the headers
60// of a D-Bus message.
61type HeaderField byte
62
63const (
64	FieldPath HeaderField = 1 + iota
65	FieldInterface
66	FieldMember
67	FieldErrorName
68	FieldReplySerial
69	FieldDestination
70	FieldSender
71	FieldSignature
72	FieldUnixFDs
73	fieldMax
74)
75
76// An InvalidMessageError describes the reason why a D-Bus message is regarded as
77// invalid.
78type InvalidMessageError string
79
80func (e InvalidMessageError) Error() string {
81	return "dbus: invalid message: " + string(e)
82}
83
84// fieldType are the types of the various header fields.
85var fieldTypes = [fieldMax]reflect.Type{
86	FieldPath:        objectPathType,
87	FieldInterface:   stringType,
88	FieldMember:      stringType,
89	FieldErrorName:   stringType,
90	FieldReplySerial: uint32Type,
91	FieldDestination: stringType,
92	FieldSender:      stringType,
93	FieldSignature:   signatureType,
94	FieldUnixFDs:     uint32Type,
95}
96
97// requiredFields lists the header fields that are required by the different
98// message types.
99var requiredFields = [typeMax][]HeaderField{
100	TypeMethodCall:  {FieldPath, FieldMember},
101	TypeMethodReply: {FieldReplySerial},
102	TypeError:       {FieldErrorName, FieldReplySerial},
103	TypeSignal:      {FieldPath, FieldInterface, FieldMember},
104}
105
106// Message represents a single D-Bus message.
107type Message struct {
108	Type
109	Flags
110	Headers map[HeaderField]Variant
111	Body    []interface{}
112
113	serial uint32
114}
115
116type header struct {
117	Field byte
118	Variant
119}
120
121// DecodeMessage tries to decode a single message in the D-Bus wire format
122// from the given reader. The byte order is figured out from the first byte.
123// The possibly returned error can be an error of the underlying reader, an
124// InvalidMessageError or a FormatError.
125func DecodeMessage(rd io.Reader) (msg *Message, err error) {
126	var order binary.ByteOrder
127	var hlength, length uint32
128	var typ, flags, proto byte
129	var headers []header
130
131	b := make([]byte, 1)
132	_, err = rd.Read(b)
133	if err != nil {
134		return
135	}
136	switch b[0] {
137	case 'l':
138		order = binary.LittleEndian
139	case 'B':
140		order = binary.BigEndian
141	default:
142		return nil, InvalidMessageError("invalid byte order")
143	}
144
145	dec := newDecoder(rd, order)
146	dec.pos = 1
147
148	msg = new(Message)
149	vs, err := dec.Decode(Signature{"yyyuu"})
150	if err != nil {
151		return nil, err
152	}
153	if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil {
154		return nil, err
155	}
156	msg.Type = Type(typ)
157	msg.Flags = Flags(flags)
158
159	// get the header length separately because we need it later
160	b = make([]byte, 4)
161	_, err = io.ReadFull(rd, b)
162	if err != nil {
163		return nil, err
164	}
165	binary.Read(bytes.NewBuffer(b), order, &hlength)
166	if hlength+length+16 > 1<<27 {
167		return nil, InvalidMessageError("message is too long")
168	}
169	dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order)
170	dec.pos = 12
171	vs, err = dec.Decode(Signature{"a(yv)"})
172	if err != nil {
173		return nil, err
174	}
175	if err = Store(vs, &headers); err != nil {
176		return nil, err
177	}
178
179	msg.Headers = make(map[HeaderField]Variant)
180	for _, v := range headers {
181		msg.Headers[HeaderField(v.Field)] = v.Variant
182	}
183
184	dec.align(8)
185	body := make([]byte, int(length))
186	if length != 0 {
187		_, err := io.ReadFull(rd, body)
188		if err != nil {
189			return nil, err
190		}
191	}
192
193	if err = msg.IsValid(); err != nil {
194		return nil, err
195	}
196	sig, _ := msg.Headers[FieldSignature].value.(Signature)
197	if sig.str != "" {
198		buf := bytes.NewBuffer(body)
199		dec = newDecoder(buf, order)
200		vs, err := dec.Decode(sig)
201		if err != nil {
202			return nil, err
203		}
204		msg.Body = vs
205	}
206
207	return
208}
209
210// EncodeTo encodes and sends a message to the given writer. The byte order must
211// be either binary.LittleEndian or binary.BigEndian. If the message is not
212// valid or an error occurs when writing, an error is returned.
213func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
214	if err := msg.IsValid(); err != nil {
215		return err
216	}
217	var vs [7]interface{}
218	switch order {
219	case binary.LittleEndian:
220		vs[0] = byte('l')
221	case binary.BigEndian:
222		vs[0] = byte('B')
223	default:
224		return errors.New("dbus: invalid byte order")
225	}
226	body := new(bytes.Buffer)
227	enc := newEncoder(body, order)
228	if len(msg.Body) != 0 {
229		enc.Encode(msg.Body...)
230	}
231	vs[1] = msg.Type
232	vs[2] = msg.Flags
233	vs[3] = protoVersion
234	vs[4] = uint32(len(body.Bytes()))
235	vs[5] = msg.serial
236	headers := make([]header, 0, len(msg.Headers))
237	for k, v := range msg.Headers {
238		headers = append(headers, header{byte(k), v})
239	}
240	vs[6] = headers
241	var buf bytes.Buffer
242	enc = newEncoder(&buf, order)
243	enc.Encode(vs[:]...)
244	enc.align(8)
245	body.WriteTo(&buf)
246	if buf.Len() > 1<<27 {
247		return InvalidMessageError("message is too long")
248	}
249	if _, err := buf.WriteTo(out); err != nil {
250		return err
251	}
252	return nil
253}
254
255// IsValid checks whether msg is a valid message and returns an
256// InvalidMessageError if it is not.
257func (msg *Message) IsValid() error {
258	if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected|FlagAllowInteractiveAuthorization) != 0 {
259		return InvalidMessageError("invalid flags")
260	}
261	if msg.Type == 0 || msg.Type >= typeMax {
262		return InvalidMessageError("invalid message type")
263	}
264	for k, v := range msg.Headers {
265		if k == 0 || k >= fieldMax {
266			return InvalidMessageError("invalid header")
267		}
268		if reflect.TypeOf(v.value) != fieldTypes[k] {
269			return InvalidMessageError("invalid type of header field")
270		}
271	}
272	for _, v := range requiredFields[msg.Type] {
273		if _, ok := msg.Headers[v]; !ok {
274			return InvalidMessageError("missing required header")
275		}
276	}
277	if path, ok := msg.Headers[FieldPath]; ok {
278		if !path.value.(ObjectPath).IsValid() {
279			return InvalidMessageError("invalid path name")
280		}
281	}
282	if iface, ok := msg.Headers[FieldInterface]; ok {
283		if !isValidInterface(iface.value.(string)) {
284			return InvalidMessageError("invalid interface name")
285		}
286	}
287	if member, ok := msg.Headers[FieldMember]; ok {
288		if !isValidMember(member.value.(string)) {
289			return InvalidMessageError("invalid member name")
290		}
291	}
292	if errname, ok := msg.Headers[FieldErrorName]; ok {
293		if !isValidInterface(errname.value.(string)) {
294			return InvalidMessageError("invalid error name")
295		}
296	}
297	if len(msg.Body) != 0 {
298		if _, ok := msg.Headers[FieldSignature]; !ok {
299			return InvalidMessageError("missing signature")
300		}
301	}
302	return nil
303}
304
305// Serial returns the message's serial number. The returned value is only valid
306// for messages received by eavesdropping.
307func (msg *Message) Serial() uint32 {
308	return msg.serial
309}
310
311// String returns a string representation of a message similar to the format of
312// dbus-monitor.
313func (msg *Message) String() string {
314	if err := msg.IsValid(); err != nil {
315		return "<invalid>"
316	}
317	s := msg.Type.String()
318	if v, ok := msg.Headers[FieldSender]; ok {
319		s += " from " + v.value.(string)
320	}
321	if v, ok := msg.Headers[FieldDestination]; ok {
322		s += " to " + v.value.(string)
323	}
324	s += " serial " + strconv.FormatUint(uint64(msg.serial), 10)
325	if v, ok := msg.Headers[FieldReplySerial]; ok {
326		s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
327	}
328	if v, ok := msg.Headers[FieldUnixFDs]; ok {
329		s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
330	}
331	if v, ok := msg.Headers[FieldPath]; ok {
332		s += " path " + string(v.value.(ObjectPath))
333	}
334	if v, ok := msg.Headers[FieldInterface]; ok {
335		s += " interface " + v.value.(string)
336	}
337	if v, ok := msg.Headers[FieldErrorName]; ok {
338		s += " error " + v.value.(string)
339	}
340	if v, ok := msg.Headers[FieldMember]; ok {
341		s += " member " + v.value.(string)
342	}
343	if len(msg.Body) != 0 {
344		s += "\n"
345	}
346	for i, v := range msg.Body {
347		s += "  " + MakeVariant(v).String()
348		if i != len(msg.Body)-1 {
349			s += "\n"
350		}
351	}
352	return s
353}
354