go-tg-screenshot-bot

Форк
0
186 строк · 4.5 Кб
1
package xgb
2

3
/*
4
conn.go contains a couple of functions that do some real dirty work related
5
to the initial connection handshake with X.
6

7
This code is largely unmodified from the original XGB package that I forked.
8
*/
9

10
import (
11
	"errors"
12
	"fmt"
13
	"io"
14
	"net"
15
	"os"
16
	"strconv"
17
	"strings"
18
)
19

20
// connect connects to the X server given in the 'display' string,
21
// and does all the necessary setup handshaking.
22
// If 'display' is empty it will be taken from os.Getenv("DISPLAY").
23
// Note that you should read and understand the "Connection Setup" of the
24
// X Protocol Reference Manual before changing this function:
25
// http://goo.gl/4zGQg
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
// connect init from to the net.Conn,
36
func (c *Conn) connectNet(netConn net.Conn) error {
37
	c.conn = netConn
38
	return c.postConnect()
39
}
40

41
// do the postConnect action after Conn get it's underly net.Conn
42
func (c *Conn) postConnect() error {
43
	// Get authentication data
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
	// Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
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
	// Unfortunately, it isn't really feasible to read the setup bytes here,
100
	// since the code to do so is in a different package.
101
	// Users must call 'xproto.Setup(X)' to get the setup info.
102
	c.SetupBytes = buf
103

104
	// But also read stuff that we *need* to get started.
105
	c.setupResourceIdBase = Get32(buf[12:])
106
	c.setupResourceIdMask = Get32(buf[16:])
107

108
	return nil
109
}
110

111
// dial initializes the actual net connection with X.
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
	// Connect to server
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.