-
Notifications
You must be signed in to change notification settings - Fork 0
/
rlpa_packet.go
176 lines (157 loc) · 3.92 KB
/
rlpa_packet.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
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"log/slog"
"net"
)
const (
TagMessagebox = 0x00
TagManagement = 0x01
TagDownloadProfile = 0x02
TagProcessNotification = 0x03
TagReboot = 0xFB
TagClose = 0xFC
TagApduLock = 0xFD
TagApdu = 0xFE
TagApduUnlock = 0xFF
)
type RLPAPacket struct {
Tag uint8
Value []byte
State int
NextReadLen uint16
Buffer bytes.Buffer
}
func NewRLPAPacket(tag uint8, value []byte) RLPAPacket {
return RLPAPacket{
Tag: tag,
Value: value,
State: 0,
NextReadLen: 1,
Buffer: bytes.Buffer{},
}
}
func (p *RLPAPacket) IsFinished() bool {
return p.State == 3
}
func (p *RLPAPacket) Pack() ([]byte, error) {
buf := new(bytes.Buffer)
// 写入 tag,对应 php 的 pack('C', $this->tag)
err := binary.Write(buf, binary.LittleEndian, p.Tag)
if err != nil {
return nil, err
}
// 写入 value 长度,对应 php 的 pack('v', strlen($this->value));
valLen := uint16(len(p.Value))
err = binary.Write(buf, binary.LittleEndian, valLen)
if err != nil {
return nil, err
}
// 写入value内容
buf.Write(p.Value)
return buf.Bytes(), nil
}
func (p *RLPAPacket) Recv(conn net.Conn) error {
// 如果已经结束,不再处理
if p.IsFinished() {
return nil
}
// 读取至 nextReadLen 长度
readExactly := func(conn net.Conn, nextReadLen int) ([]byte, error) {
buffer := make([]byte, nextReadLen)
totalRead := 0
for totalRead < nextReadLen {
n, err := conn.Read(buffer[totalRead:])
if err != nil {
if err == io.EOF {
// 对面关闭连接,读到 EOF
return buffer[:totalRead], io.ErrUnexpectedEOF
}
return buffer[:totalRead], err
}
totalRead += n
slog.Debug(fmt.Sprint("Socket Read buffer: ", buffer[:totalRead]), "client", conn.RemoteAddr().String())
}
return buffer, nil
}
buf, err := readExactly(conn, int(p.NextReadLen))
if err != nil {
return err
}
// 长度为 0 说明读取失败
if len(buf) == 0 {
return errors.New("read buffer length 0")
}
// 写入
p.NextReadLen -= uint16(len(buf))
p.Buffer.Write(buf)
unpackTag := func(reader io.Reader) (uint8, error) {
// unpack('C', $this->_buffer)[1]
var tag uint8
// 无符号字符不区分大端序小端序
// 读取第一个字节(Tag)
errBinaryRead := binary.Read(reader, binary.LittleEndian, &tag)
if errBinaryRead != nil {
return 0, errBinaryRead
}
return tag, nil
}
unpackNextReadLen := func(reader io.Reader) (uint16, error) {
// unpack('v', $this->_buffer)[1]
// 'v' 为 16 位无符号小端序整数
var nextReadLen uint16
errBinaryRead := binary.Read(reader, binary.LittleEndian, &nextReadLen)
if errBinaryRead != nil {
return 0, errBinaryRead
}
return nextReadLen, nil
}
// State 0 初始阶段,读 tag
// State 1 读长度
// State 2 读数据
// State 3 结束
if p.NextReadLen == 0 {
switch p.State {
case 0:
p.Tag, err = unpackTag(&p.Buffer)
if err != nil {
return err
}
slog.Debug(fmt.Sprint("Unpacked Tag: ", p.Tag), "client", conn.RemoteAddr().String())
p.State = 1
slog.Debug(fmt.Sprint("Switch to STATE: ", p.State), "client", conn.RemoteAddr().String())
p.NextReadLen = 2
p.Buffer.Reset()
break
case 1:
p.State = 2
slog.Debug(fmt.Sprint("Switch to STATE: ", p.State), "client", conn.RemoteAddr().String())
p.NextReadLen, err = unpackNextReadLen(&p.Buffer)
if err != nil {
return err
}
slog.Debug(fmt.Sprint("Unpacked nextReadLen: ", p.NextReadLen), "client", conn.RemoteAddr().String())
// NextReadLen 太长
if p.NextReadLen >= (512 - 3) {
return errors.New("next read len too long (>= 519)")
}
p.Buffer.Reset()
// 剩余读取长度为 0,进入 State 3 结束
if p.NextReadLen == 0 {
p.State = 3
p.Value = []byte{}
}
break
case 2:
p.State = 3
p.Value = p.Buffer.Bytes()
p.Buffer.Reset()
break
}
}
return nil
}