/
protocol.go
148 lines (112 loc) · 2.94 KB
/
protocol.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
// Copyright 2023 FishGoddess. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package pack
import (
"encoding/binary"
"errors"
"io"
)
const (
magicBits = 24
typeBits = 8
dataSizeBits = 32
maxMagic = 1<<magicBits - 1
maxType = 1<<typeBits - 1
maxDataSize = 1<<dataSizeBits - 1
// Ha! Guess what this number means?
magicNumber = 0xC638B
headerSize = (magicBits + typeBits + dataSizeBits) / 8 // Bytes
)
const (
packetTypeStandard PacketType = 0
packetTypeError PacketType = 1
)
var (
Endian = binary.BigEndian
)
var (
ErrWrongMagicNumber = errors.New("vex: wrong magic number")
ErrReadSizeMismatch = errors.New("vex: read size != expected size")
ErrWriteSizeMismatch = errors.New("vex: write size != expected size")
)
// PacketType is the type of packet.
type PacketType = byte
func readPacketHeader(reader io.Reader) (PacketType, int32, error) {
var headerBytes [headerSize]byte
n, err := io.ReadFull(reader, headerBytes[:])
if err != nil {
return 0, 0, err
}
if n != headerSize {
return 0, 0, ErrReadSizeMismatch
}
header := Endian.Uint64(headerBytes[:])
magic := (header >> (typeBits + dataSizeBits)) & maxMagic
if magic != magicNumber {
return 0, 0, ErrWrongMagicNumber
}
packetType := PacketType((header >> dataSizeBits) & maxType)
dataSize := int32(header & maxDataSize)
return packetType, dataSize, nil
}
func readPacketData(reader io.Reader, dataSize int32) ([]byte, error) {
// Memory may exceed if body size is too big.
body := make([]byte, dataSize)
n, err := io.ReadFull(reader, body)
if err == io.ErrUnexpectedEOF {
return nil, ErrReadSizeMismatch
}
if err != nil {
return nil, err
}
if n != int(dataSize) {
return nil, ErrReadSizeMismatch
}
return body, nil
}
func readPacket(reader io.Reader) (PacketType, []byte, error) {
packetType, dataSize, err := readPacketHeader(reader)
if err != nil {
return 0, nil, err
}
var data []byte
if dataSize > 0 {
data, err = readPacketData(reader, dataSize)
}
return packetType, data, err
}
func writePacketHeader(writer io.Writer, packetType PacketType, dataSize int32) error {
var headerBytes [headerSize]byte
var header = magicNumber<<(typeBits+dataSizeBits) | uint64(packetType)<<dataSizeBits | uint64(dataSize)
Endian.PutUint64(headerBytes[:], header)
n, err := writer.Write(headerBytes[:])
if err != nil {
return err
}
if n != headerSize {
return ErrWriteSizeMismatch
}
return nil
}
func writePacketData(writer io.Writer, data []byte) error {
n, err := writer.Write(data)
if err != nil {
return err
}
if n != len(data) {
return ErrWriteSizeMismatch
}
return nil
}
func writePacket(writer io.Writer, packetType PacketType, data []byte) error {
dataSize := int32(len(data))
err := writePacketHeader(writer, packetType, dataSize)
if err != nil {
return err
}
if dataSize > 0 {
err = writePacketData(writer, data)
}
return nil
}