github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/internal/wire/connection_close_frame.go (about)

     1  package wire
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/metacubex/quic-go/internal/protocol"
     7  	"github.com/metacubex/quic-go/quicvarint"
     8  )
     9  
    10  // A ConnectionCloseFrame is a CONNECTION_CLOSE frame
    11  type ConnectionCloseFrame struct {
    12  	IsApplicationError bool
    13  	ErrorCode          uint64
    14  	FrameType          uint64
    15  	ReasonPhrase       string
    16  }
    17  
    18  func parseConnectionCloseFrame(b []byte, typ uint64, _ protocol.Version) (*ConnectionCloseFrame, int, error) {
    19  	startLen := len(b)
    20  	f := &ConnectionCloseFrame{IsApplicationError: typ == applicationCloseFrameType}
    21  	ec, l, err := quicvarint.Parse(b)
    22  	if err != nil {
    23  		return nil, 0, replaceUnexpectedEOF(err)
    24  	}
    25  	b = b[l:]
    26  	f.ErrorCode = ec
    27  	// read the Frame Type, if this is not an application error
    28  	if !f.IsApplicationError {
    29  		ft, l, err := quicvarint.Parse(b)
    30  		if err != nil {
    31  			return nil, 0, replaceUnexpectedEOF(err)
    32  		}
    33  		b = b[l:]
    34  		f.FrameType = ft
    35  	}
    36  	var reasonPhraseLen uint64
    37  	reasonPhraseLen, l, err = quicvarint.Parse(b)
    38  	if err != nil {
    39  		return nil, 0, replaceUnexpectedEOF(err)
    40  	}
    41  	b = b[l:]
    42  	if int(reasonPhraseLen) > len(b) {
    43  		return nil, 0, io.EOF
    44  	}
    45  
    46  	reasonPhrase := make([]byte, reasonPhraseLen)
    47  	copy(reasonPhrase, b)
    48  	f.ReasonPhrase = string(reasonPhrase)
    49  	return f, startLen - len(b) + int(reasonPhraseLen), nil
    50  }
    51  
    52  // Length of a written frame
    53  func (f *ConnectionCloseFrame) Length(protocol.Version) protocol.ByteCount {
    54  	length := 1 + protocol.ByteCount(quicvarint.Len(f.ErrorCode)+quicvarint.Len(uint64(len(f.ReasonPhrase)))) + protocol.ByteCount(len(f.ReasonPhrase))
    55  	if !f.IsApplicationError {
    56  		length += protocol.ByteCount(quicvarint.Len(f.FrameType)) // for the frame type
    57  	}
    58  	return length
    59  }
    60  
    61  func (f *ConnectionCloseFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
    62  	if f.IsApplicationError {
    63  		b = append(b, applicationCloseFrameType)
    64  	} else {
    65  		b = append(b, connectionCloseFrameType)
    66  	}
    67  
    68  	b = quicvarint.Append(b, f.ErrorCode)
    69  	if !f.IsApplicationError {
    70  		b = quicvarint.Append(b, f.FrameType)
    71  	}
    72  	b = quicvarint.Append(b, uint64(len(f.ReasonPhrase)))
    73  	b = append(b, []byte(f.ReasonPhrase)...)
    74  	return b, nil
    75  }