...
1 package xgb
2
3
9
10 import (
11 "errors"
12 "fmt"
13 "io"
14 "net"
15 "os"
16 "strconv"
17 "strings"
18 )
19
20
21
22
23
24
25
26 func (c *Conn) connect(display string) error {
27 err := c.dial(display)
28 if err != nil {
29 return err
30 }
31
32 return c.postConnect()
33 }
34
35
36 func (c *Conn) connectNet(netConn net.Conn) error {
37 c.conn = netConn
38 return c.postConnect()
39 }
40
41
42 func (c *Conn) postConnect() error {
43
44 authName, authData, err := readAuthority(c.host, c.display)
45 noauth := false
46 if err != nil {
47 Logger.Printf("Could not get authority info: %v", err)
48 Logger.Println("Trying connection without authority info...")
49 authName = ""
50 authData = []byte{}
51 noauth = true
52 }
53
54
55 if !noauth && (authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16) {
56 return errors.New("unsupported auth protocol " + authName)
57 }
58
59 buf := make([]byte, 12+Pad(len(authName))+Pad(len(authData)))
60 buf[0] = 0x6c
61 buf[1] = 0
62 Put16(buf[2:], 11)
63 Put16(buf[4:], 0)
64 Put16(buf[6:], uint16(len(authName)))
65 Put16(buf[8:], uint16(len(authData)))
66 Put16(buf[10:], 0)
67 copy(buf[12:], []byte(authName))
68 copy(buf[12+Pad(len(authName)):], authData)
69 if _, err = c.conn.Write(buf); err != nil {
70 return err
71 }
72
73 head := make([]byte, 8)
74 if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
75 return err
76 }
77 code := head[0]
78 reasonLen := head[1]
79 major := Get16(head[2:])
80 minor := Get16(head[4:])
81 dataLen := Get16(head[6:])
82
83 if major != 11 || minor != 0 {
84 return fmt.Errorf("x protocol version mismatch: %d.%d", major, minor)
85 }
86
87 buf = make([]byte, int(dataLen)*4+8, int(dataLen)*4+8)
88 copy(buf, head)
89 if _, err = io.ReadFull(c.conn, buf[8:]); err != nil {
90 return err
91 }
92
93 if code == 0 {
94 reason := buf[8 : 8+reasonLen]
95 return fmt.Errorf("x protocol authentication refused: %s",
96 string(reason))
97 }
98
99
100
101
102 c.SetupBytes = buf
103
104
105 c.setupResourceIdBase = Get32(buf[12:])
106 c.setupResourceIdMask = Get32(buf[16:])
107
108 return nil
109 }
110
111
112 func (c *Conn) dial(display string) error {
113 if len(display) == 0 {
114 display = os.Getenv("DISPLAY")
115 }
116
117 display0 := display
118 if len(display) == 0 {
119 return errors.New("empty display string")
120 }
121
122 colonIdx := strings.LastIndex(display, ":")
123 if colonIdx < 0 {
124 return errors.New("bad display string: " + display0)
125 }
126
127 var protocol, socket string
128
129 if display[0] == '/' {
130 socket = display[0:colonIdx]
131 } else {
132 slashIdx := strings.LastIndex(display, "/")
133 if slashIdx >= 0 {
134 protocol = display[0:slashIdx]
135 c.host = display[slashIdx+1 : colonIdx]
136 } else {
137 c.host = display[0:colonIdx]
138 }
139 }
140
141 display = display[colonIdx+1 : len(display)]
142 if len(display) == 0 {
143 return errors.New("bad display string: " + display0)
144 }
145
146 var scr string
147 dotIdx := strings.LastIndex(display, ".")
148 if dotIdx < 0 {
149 c.display = display[0:]
150 } else {
151 c.display = display[0:dotIdx]
152 scr = display[dotIdx+1:]
153 }
154
155 var err error
156 c.DisplayNumber, err = strconv.Atoi(c.display)
157 if err != nil || c.DisplayNumber < 0 {
158 return errors.New("bad display string: " + display0)
159 }
160
161 if len(scr) != 0 {
162 c.DefaultScreen, err = strconv.Atoi(scr)
163 if err != nil {
164 return errors.New("bad display string: " + display0)
165 }
166 }
167
168
169 if len(socket) != 0 {
170 c.conn, err = net.Dial("unix", socket+":"+c.display)
171 } else if len(c.host) != 0 && c.host != "unix" {
172 if protocol == "" {
173 protocol = "tcp"
174 }
175 c.conn, err = net.Dial(protocol,
176 c.host+":"+strconv.Itoa(6000+c.DisplayNumber))
177 } else {
178 c.host = ""
179 c.conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+c.display)
180 }
181
182 if err != nil {
183 return errors.New("cannot connect to " + display0 + ": " + err.Error())
184 }
185 return nil
186 }
187
View as plain text