github.com/sagernet/quic-go@v0.43.1-beta.1/internal/wire/connection_close_frame.go (about) 1 package wire 2 3 import ( 4 "bytes" 5 "io" 6 7 "github.com/sagernet/quic-go/internal/protocol" 8 "github.com/sagernet/quic-go/quicvarint" 9 ) 10 11 // A ConnectionCloseFrame is a CONNECTION_CLOSE frame 12 type ConnectionCloseFrame struct { 13 IsApplicationError bool 14 ErrorCode uint64 15 FrameType uint64 16 ReasonPhrase string 17 } 18 19 func parseConnectionCloseFrame(r *bytes.Reader, typ uint64, _ protocol.Version) (*ConnectionCloseFrame, error) { 20 f := &ConnectionCloseFrame{IsApplicationError: typ == applicationCloseFrameType} 21 ec, err := quicvarint.Read(r) 22 if err != nil { 23 return nil, err 24 } 25 f.ErrorCode = ec 26 // read the Frame Type, if this is not an application error 27 if !f.IsApplicationError { 28 ft, err := quicvarint.Read(r) 29 if err != nil { 30 return nil, err 31 } 32 f.FrameType = ft 33 } 34 var reasonPhraseLen uint64 35 reasonPhraseLen, err = quicvarint.Read(r) 36 if err != nil { 37 return nil, err 38 } 39 // shortcut to prevent the unnecessary allocation of dataLen bytes 40 // if the dataLen is larger than the remaining length of the packet 41 // reading the whole reason phrase would result in EOF when attempting to READ 42 if int(reasonPhraseLen) > r.Len() { 43 return nil, io.EOF 44 } 45 46 reasonPhrase := make([]byte, reasonPhraseLen) 47 if _, err := io.ReadFull(r, reasonPhrase); err != nil { 48 // this should never happen, since we already checked the reasonPhraseLen earlier 49 return nil, err 50 } 51 f.ReasonPhrase = string(reasonPhrase) 52 return f, nil 53 } 54 55 // Length of a written frame 56 func (f *ConnectionCloseFrame) Length(protocol.Version) protocol.ByteCount { 57 length := 1 + protocol.ByteCount(quicvarint.Len(f.ErrorCode)+quicvarint.Len(uint64(len(f.ReasonPhrase)))) + protocol.ByteCount(len(f.ReasonPhrase)) 58 if !f.IsApplicationError { 59 length += protocol.ByteCount(quicvarint.Len(f.FrameType)) // for the frame type 60 } 61 return length 62 } 63 64 func (f *ConnectionCloseFrame) Append(b []byte, _ protocol.Version) ([]byte, error) { 65 if f.IsApplicationError { 66 b = append(b, applicationCloseFrameType) 67 } else { 68 b = append(b, connectionCloseFrameType) 69 } 70 71 b = quicvarint.Append(b, f.ErrorCode) 72 if !f.IsApplicationError { 73 b = quicvarint.Append(b, f.FrameType) 74 } 75 b = quicvarint.Append(b, uint64(len(f.ReasonPhrase))) 76 b = append(b, []byte(f.ReasonPhrase)...) 77 return b, nil 78 }