forked from quic-go/quic-go
/
connection_close_frame.go
96 lines (83 loc) · 2.58 KB
/
connection_close_frame.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
package wire
import (
"bytes"
"errors"
"io"
"math"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// A ConnectionCloseFrame in QUIC
type ConnectionCloseFrame struct {
ErrorCode qerr.ErrorCode
ReasonPhrase string
}
// parseConnectionCloseFrame reads a CONNECTION_CLOSE frame
func parseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) (*ConnectionCloseFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
var errorCode qerr.ErrorCode
var reasonPhraseLen uint64
if version.UsesIETFFrameFormat() {
ec, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
errorCode = qerr.ErrorCode(ec)
reasonPhraseLen, err = utils.ReadVarInt(r)
if err != nil {
return nil, err
}
} else {
ec, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
errorCode = qerr.ErrorCode(ec)
length, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
reasonPhraseLen = uint64(length)
}
// shortcut to prevent the unnecessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet
// reading the whole reason phrase would result in EOF when attempting to READ
if int(reasonPhraseLen) > r.Len() {
return nil, io.EOF
}
reasonPhrase := make([]byte, reasonPhraseLen)
if _, err := io.ReadFull(r, reasonPhrase); err != nil {
// this should never happen, since we already checked the reasonPhraseLen earlier
return nil, err
}
return &ConnectionCloseFrame{
ErrorCode: errorCode,
ReasonPhrase: string(reasonPhrase),
}, nil
}
// Length of a written frame
func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if version.UsesIETFFrameFormat() {
return 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
}
return 1 + 4 + 2 + protocol.ByteCount(len(f.ReasonPhrase))
}
// Write writes an CONNECTION_CLOSE frame.
func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
b.WriteByte(0x02)
if len(f.ReasonPhrase) > math.MaxUint16 {
return errors.New("ConnectionFrame: ReasonPhrase too long")
}
if version.UsesIETFFrameFormat() {
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
utils.WriteVarInt(b, uint64(len(f.ReasonPhrase)))
} else {
utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode))
utils.BigEndian.WriteUint16(b, uint16(len(f.ReasonPhrase)))
}
b.WriteString(f.ReasonPhrase)
return nil
}