2018-11-20 17:51:25 -05:00
|
|
|
package wire
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"io"
|
|
|
|
|
2019-01-17 09:33:18 -05:00
|
|
|
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol"
|
|
|
|
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr"
|
|
|
|
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils"
|
2018-11-20 17:51:25 -05:00
|
|
|
)
|
|
|
|
|
2018-11-23 11:04:53 -05:00
|
|
|
// A ConnectionCloseFrame is a CONNECTION_CLOSE frame
|
2018-11-20 17:51:25 -05:00
|
|
|
type ConnectionCloseFrame struct {
|
2018-11-23 11:04:53 -05:00
|
|
|
IsApplicationError bool
|
|
|
|
ErrorCode qerr.ErrorCode
|
|
|
|
ReasonPhrase string
|
2018-11-20 17:51:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) (*ConnectionCloseFrame, error) {
|
2018-11-23 11:04:53 -05:00
|
|
|
typeByte, err := r.ReadByte()
|
|
|
|
if err != nil {
|
2018-11-20 17:51:25 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-11-23 11:04:53 -05:00
|
|
|
f := &ConnectionCloseFrame{IsApplicationError: typeByte == 0x1d}
|
|
|
|
ec, err := utils.BigEndian.ReadUint16(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
f.ErrorCode = qerr.ErrorCode(ec)
|
|
|
|
// read the Frame Type, if this is not an application error
|
|
|
|
if !f.IsApplicationError {
|
|
|
|
if _, err := utils.ReadVarInt(r); err != nil {
|
2018-11-20 17:51:25 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2018-11-23 11:04:53 -05:00
|
|
|
var reasonPhraseLen uint64
|
|
|
|
reasonPhraseLen, err = utils.ReadVarInt(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-11-20 17:51:25 -05:00
|
|
|
// 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
|
|
|
|
}
|
2018-11-23 11:04:53 -05:00
|
|
|
f.ReasonPhrase = string(reasonPhrase)
|
|
|
|
return f, nil
|
2018-11-20 17:51:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Length of a written frame
|
|
|
|
func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
|
2018-11-23 11:04:53 -05:00
|
|
|
length := 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
|
|
|
|
if !f.IsApplicationError {
|
|
|
|
length++ // for the frame type
|
2018-11-20 17:51:25 -05:00
|
|
|
}
|
2018-11-23 11:04:53 -05:00
|
|
|
return length
|
2018-11-20 17:51:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
2018-11-23 11:04:53 -05:00
|
|
|
if f.IsApplicationError {
|
|
|
|
b.WriteByte(0x1d)
|
|
|
|
} else {
|
|
|
|
b.WriteByte(0x1c)
|
2018-11-20 17:51:25 -05:00
|
|
|
}
|
|
|
|
|
2018-11-23 11:04:53 -05:00
|
|
|
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
|
|
|
|
if !f.IsApplicationError {
|
|
|
|
utils.WriteVarInt(b, 0)
|
2018-11-20 17:51:25 -05:00
|
|
|
}
|
2018-11-23 11:04:53 -05:00
|
|
|
utils.WriteVarInt(b, uint64(len(f.ReasonPhrase)))
|
2018-11-20 17:51:25 -05:00
|
|
|
b.WriteString(f.ReasonPhrase)
|
|
|
|
return nil
|
|
|
|
}
|