-
Notifications
You must be signed in to change notification settings - Fork 107
/
Copy pathscanner.go
180 lines (146 loc) · 4.91 KB
/
scanner.go
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package wire
import (
"encoding/binary"
"io"
"io/ioutil"
"strconv"
"github.com/zach-klippenstein/goadb/util"
)
// TODO(zach): All EOF errors returned from networoking calls should use ConnectionResetError.
// StatusCodes are returned by the server. If the code indicates failure, the
// next message will be the error.
const (
StatusSuccess string = "OKAY"
StatusFailure = "FAIL"
StatusSyncData = "DATA"
StatusSyncDone = "DONE"
StatusNone = ""
)
func isFailureStatus(status string) bool {
return status == StatusFailure
}
type StatusReader interface {
// Reads a 4-byte status string and returns it.
// If the status string is StatusFailure, reads the error message from the server
// and returns it as an util.AdbError.
ReadStatus(req string) (string, error)
}
/*
Scanner reads tokens from a server.
See Conn for more details.
*/
type Scanner interface {
io.Closer
StatusReader
ReadMessage() ([]byte, error)
ReadUntilEof() ([]byte, error)
NewSyncScanner() SyncScanner
}
type realScanner struct {
reader io.ReadCloser
}
func NewScanner(r io.ReadCloser) Scanner {
return &realScanner{r}
}
func ReadMessageString(s Scanner) (string, error) {
msg, err := s.ReadMessage()
if err != nil {
return string(msg), err
}
return string(msg), nil
}
func (s *realScanner) ReadStatus(req string) (string, error) {
return readStatusFailureAsError(s.reader, req, readHexLength)
}
func (s *realScanner) ReadMessage() ([]byte, error) {
return readMessage(s.reader, readHexLength)
}
func (s *realScanner) ReadUntilEof() ([]byte, error) {
data, err := ioutil.ReadAll(s.reader)
if err != nil {
return nil, util.WrapErrorf(err, util.NetworkError, "error reading until EOF")
}
return data, nil
}
func (s *realScanner) NewSyncScanner() SyncScanner {
return NewSyncScanner(s.reader)
}
func (s *realScanner) Close() error {
return util.WrapErrorf(s.reader.Close(), util.NetworkError, "error closing scanner")
}
var _ Scanner = &realScanner{}
// lengthReader is a func that readMessage uses to read message length.
// See readHexLength and readInt32.
type lengthReader func(io.Reader) (int, error)
// Reads the status, and if failure, reads the message and returns it as an error.
// If the status is success, doesn't read the message.
// req is just used to populate the AdbError, and can be nil.
// messageLengthReader is the function passed to readMessage if the status is failure.
func readStatusFailureAsError(r io.Reader, req string, messageLengthReader lengthReader) (string, error) {
status, err := readOctetString(req, r)
if err != nil {
return "", util.WrapErrorf(err, util.NetworkError, "error reading status for %s", req)
}
if isFailureStatus(status) {
msg, err := readMessage(r, messageLengthReader)
if err != nil {
return "", util.WrapErrorf(err, util.NetworkError,
"server returned error for %s, but couldn't read the error message", req)
}
return "", adbServerError(req, string(msg))
}
return status, nil
}
func readOctetString(description string, r io.Reader) (string, error) {
octet := make([]byte, 4)
n, err := io.ReadFull(r, octet)
if err == io.ErrUnexpectedEOF {
return "", errIncompleteMessage(description, n, 4)
} else if err != nil {
return "", util.WrapErrorf(err, util.NetworkError, "error reading "+description)
}
return string(octet), nil
}
// readMessage reads a length from r, then reads length bytes and returns them.
// lengthReader is the function used to read the length. Most operations encode
// length as a hex string (readHexLength), but sync operations use little-endian
// binary encoding (readInt32).
func readMessage(r io.Reader, lengthReader lengthReader) ([]byte, error) {
var err error
length, err := lengthReader(r)
if err != nil {
return nil, err
}
data := make([]byte, length)
n, err := io.ReadFull(r, data)
if err != nil && err != io.ErrUnexpectedEOF {
return data, util.WrapErrorf(err, util.NetworkError, "error reading message data")
} else if err == io.ErrUnexpectedEOF {
return data, errIncompleteMessage("message data", n, length)
}
return data, nil
}
// readHexLength reads the next 4 bytes from r as an ASCII hex-encoded length and parses them into an int.
func readHexLength(r io.Reader) (int, error) {
lengthHex := make([]byte, 4)
n, err := io.ReadFull(r, lengthHex)
if err != nil {
return 0, errIncompleteMessage("length", n, 4)
}
length, err := strconv.ParseInt(string(lengthHex), 16, 64)
if err != nil {
return 0, util.WrapErrorf(err, util.NetworkError, "could not parse hex length %v", lengthHex)
}
// Clip the length to 255, as per the Google implementation.
if length > MaxMessageLength {
length = MaxMessageLength
}
return int(length), nil
}
// readInt32 reads the next 4 bytes from r as a little-endian integer.
// Returns an int instead of an int32 to match the lengthReader type.
func readInt32(r io.Reader) (int, error) {
var value int32
err := binary.Read(r, binary.LittleEndian, &value)
return int(value), err
}