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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
package net
import (
"bufio"
"bytes"
"io"
"net"
"strings"
"time"
)
type Conn interface {
ReadMessage() (string, error)
io.Writer
io.Closer
// SetWriteDeadline is optional for transports: sessions that support it
// enforce per-write deadlines so a stalled peer surfaces as a timeout
// instead of a hung writer goroutine. Implementations without deadline
// support return nil (deadlines are best-effort).
SetWriteDeadline(t time.Time) error
SetEcho(bool) error
}
type tcpConn struct {
conn net.Conn
reader *bufio.Reader
echoOff bool
}
func newTCPConn(conn net.Conn) *tcpConn {
return &tcpConn{
conn: conn,
reader: bufio.NewReaderSize(conn, maxLineLength*4),
}
}
// maxLineLength bounds how much of an incoming line is accepted. Longer
// lines are drained from the socket and truncated so a client cannot grow
// the read buffer without limit.
const maxLineLength = 1024
func (t *tcpConn) ReadMessage() (string, error) {
line, err := t.reader.ReadSlice('\n')
if err == bufio.ErrBufferFull {
// Copy the bounded prefix out of the reusable read buffer BEFORE
// draining the rest of the oversized line; further reads overwrite the
// buffer the slice points into.
prefixLen := len(line)
if prefixLen > maxLineLength {
prefixLen = maxLineLength
}
prefix := make([]byte, prefixLen)
copy(prefix, line[:prefixLen])
for {
_, err = t.reader.ReadSlice('\n')
if err == nil {
break
}
if err != bufio.ErrBufferFull {
return "", err
}
}
line = prefix
} else if err != nil {
return "", err
}
text := strings.TrimRight(string(line), "\r\n")
text = stripIAC(text)
if t.echoOff {
t.conn.Write([]byte("\r\n"))
}
return text, nil
}
func (t *tcpConn) Write(b []byte) (int, error) {
return t.conn.Write(b)
}
func (t *tcpConn) SetWriteDeadline(ts time.Time) error {
return t.conn.SetWriteDeadline(ts)
}
func (t *tcpConn) Close() error {
return t.conn.Close()
}
func (t *tcpConn) SetEcho(on bool) error {
t.echoOff = !on
if on {
return t.writeTelnetCmd(wont, echo)
}
return t.writeTelnetCmd(will, echo)
}
const (
iac = 255
will = 251
wont = 252
do = 253
dont = 254
sb = 250
se = 240
echo = 1
)
func (t *tcpConn) writeTelnetCmd(cmd, opt byte) error {
_, err := t.conn.Write([]byte{iac, cmd, opt})
return err
}
func stripIAC(s string) string {
b := []byte(s)
var out []byte
i := 0
iacSE := []byte{iac, se}
for i < len(b) {
if b[i] == iac && i+2 < len(b) {
if b[i+1] == sb {
end := bytes.Index(b[i+2:], iacSE)
if end >= 0 {
i += end + 4
continue
}
}
i += 3
continue
}
if b[i] == iac {
i++
continue
}
out = append(out, b[i])
i++
}
return string(out)
}
|