File: transport.go

package info (click to toggle)
golang-go-dbus 1~bzr20150122-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 328 kB
  • sloc: makefile: 13
file content (112 lines) | stat: -rw-r--r-- 2,792 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package dbus

import (
	"errors"
	"io/ioutil"
	"net"
	"net/url"
	"strings"
)

type transport interface {
	Dial() (net.Conn, error)
}

func newTransport(address string) (transport, error) {
	if len(address) == 0 {
		return nil, errors.New("Unknown address type")
	}
	// Split the address into transport type and options.
	transportType := address[:strings.Index(address, ":")]
	options := make(map[string]string)
	for _, option := range strings.Split(address[len(transportType)+1:], ",") {
		pair := strings.SplitN(option, "=", 2)
		key, err := url.QueryUnescape(pair[0])
		if err != nil {
			return nil, err
		}
		value, err := url.QueryUnescape(pair[1])
		if err != nil {
			return nil, err
		}
		options[key] = value
	}

	switch transportType {
	case "unix":
		if abstract, ok := options["abstract"]; ok {
			return &unixTransport{"@" + abstract}, nil
		} else if path, ok := options["path"]; ok {
			return &unixTransport{path}, nil
		} else {
			return nil, errors.New("unix transport requires 'path' or 'abstract' options")
		}
	case "tcp", "nonce-tcp":
		address := options["host"] + ":" + options["port"]
		var family string
		switch options["family"] {
		case "", "ipv4":
			family = "tcp4"
		case "ipv6":
			family = "tcp6"
		default:
			return nil, errors.New("Unknown family for tcp transport: " + options["family"])
		}
		if transportType == "tcp" {
			return &tcpTransport{address, family}, nil
		} else {
			nonceFile := options["noncefile"]
			return &nonceTcpTransport{address, family, nonceFile}, nil
		}
	// These can be implemented later as needed
	case "launchd":
		// Perform newTransport() on contents of
		// options["env"] environment variable
	case "systemd":
		// Only used when systemd is starting the message bus,
		// so probably not needed in a client library.
	case "unixexec":
		// exec a process with a socket hooked to stdin/stdout
	}

	return nil, errors.New("Unhandled transport type " + transportType)
}

type unixTransport struct {
	Address string
}

func (trans *unixTransport) Dial() (net.Conn, error) {
	return net.Dial("unix", trans.Address)
}

type tcpTransport struct {
	Address, Family string
}

func (trans *tcpTransport) Dial() (net.Conn, error) {
	return net.Dial(trans.Family, trans.Address)
}

type nonceTcpTransport struct {
	Address, Family, NonceFile string
}

func (trans *nonceTcpTransport) Dial() (net.Conn, error) {
	data, err := ioutil.ReadFile(trans.NonceFile)
	if err != nil {
		return nil, err
	}
	conn, err := net.Dial(trans.Family, trans.Address)
	if err != nil {
		return nil, err
	}
	// Write the nonce data to the socket
	// writing at this point does not need to be synced as the connection
	// is not shared at this point.
	if _, err := conn.Write(data); err != nil {
		conn.Close()
		return nil, err
	}
	return conn, nil
}