-
Notifications
You must be signed in to change notification settings - Fork 38
/
netpackager.go
155 lines (143 loc) · 3.87 KB
/
netpackager.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
package nps_mux
import (
"encoding/binary"
"errors"
"io"
)
type basePackager struct {
buf []byte
// buf contain the mux protocol struct binary data, we copy data to buf firstly.
// replace binary.Read/Write method, it may use reflect shows slowly.
// also reduce conn.Read/Write calls which use syscall.
// due to our test, conn.Write method reduce by two-thirds CPU times,
// conn.Write method has 20% reduction of the CPU times,
// totally provides more than twice of the CPU performance improvement.
length uint16
content []byte
}
func (Self *basePackager) Set(content []byte) (err error) {
Self.reset()
if content != nil {
n := len(content)
if n == 0 {
err = errors.New("mux:packer: newpack content is zero length")
}
if n > maximumSegmentSize {
err = errors.New("mux:packer: newpack content segment too large")
return
}
Self.content = Self.content[:n]
copy(Self.content, content)
} else {
err = errors.New("mux:packer: newpack content is nil")
}
Self.setLength()
return
}
func (Self *basePackager) Pack(writer io.Writer) (err error) {
binary.LittleEndian.PutUint16(Self.buf[5:7], Self.length)
_, err = writer.Write(Self.buf[:7])
if err != nil {
return
}
_, err = writer.Write(Self.content[:Self.length])
return
}
func (Self *basePackager) UnPack(reader io.Reader) (n uint16, err error) {
Self.reset()
l, err := io.ReadFull(reader, Self.buf[5:7])
if err != nil {
return
}
n += uint16(l)
Self.length = binary.LittleEndian.Uint16(Self.buf[5:7])
if int(Self.length) > cap(Self.content) {
err = errors.New("mux:packer: unpack err, content length too large")
return
}
if Self.length > maximumSegmentSize {
err = errors.New("mux:packer: unpack content segment too large")
return
}
Self.content = Self.content[:int(Self.length)]
l, err = io.ReadFull(reader, Self.content)
n += uint16(l)
return
}
func (Self *basePackager) setLength() {
Self.length = uint16(len(Self.content))
return
}
func (Self *basePackager) reset() {
Self.length = 0
Self.content = Self.content[:0] // reset length
}
type muxPackager struct {
flag uint8
id int32
window uint64
basePackager
}
func (Self *muxPackager) Set(flag uint8, id int32, content interface{}) (err error) {
Self.buf = windowBuff.Get()
Self.flag = flag
Self.id = id
switch flag {
case muxPingFlag, muxPingReturn, muxNewMsg, muxNewMsgPart:
Self.content = windowBuff.Get()
err = Self.basePackager.Set(content.([]byte))
case muxMsgSendOk:
// MUX_MSG_SEND_OK contains one data
Self.window = content.(uint64)
}
return
}
func (Self *muxPackager) Pack(writer io.Writer) (err error) {
Self.buf = Self.buf[0:13]
Self.buf[0] = byte(Self.flag)
binary.LittleEndian.PutUint32(Self.buf[1:5], uint32(Self.id))
switch Self.flag {
case muxNewMsg, muxNewMsgPart, muxPingFlag, muxPingReturn:
err = Self.basePackager.Pack(writer)
windowBuff.Put(Self.content)
case muxMsgSendOk:
binary.LittleEndian.PutUint64(Self.buf[5:13], Self.window)
_, err = writer.Write(Self.buf[:13])
default:
_, err = writer.Write(Self.buf[:5])
}
windowBuff.Put(Self.buf)
return
}
func (Self *muxPackager) UnPack(reader io.Reader) (n uint16, err error) {
Self.buf = windowBuff.Get()
Self.buf = Self.buf[0:13]
l, err := io.ReadFull(reader, Self.buf[:5])
if err != nil {
return
}
n += uint16(l)
Self.flag = uint8(Self.buf[0])
Self.id = int32(binary.LittleEndian.Uint32(Self.buf[1:5]))
switch Self.flag {
case muxNewMsg, muxNewMsgPart, muxPingFlag, muxPingReturn:
var m uint16
Self.content = windowBuff.Get() // need Get a window buf from pool
m, err = Self.basePackager.UnPack(reader)
n += m
case muxMsgSendOk:
l, err = io.ReadFull(reader, Self.buf[5:13])
Self.window = binary.LittleEndian.Uint64(Self.buf[5:13])
n += uint16(l) // uint64
}
windowBuff.Put(Self.buf)
return
}
func (Self *muxPackager) reset() {
Self.id = 0
Self.flag = 0
Self.length = 0
Self.content = nil
Self.window = 0
Self.buf = nil
}