golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/packet_writer.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"encoding/binary"
    11  )
    12  
    13  // A packetWriter constructs QUIC datagrams.
    14  //
    15  // A datagram consists of one or more packets.
    16  // A packet consists of a header followed by one or more frames.
    17  //
    18  // Packets are written in three steps:
    19  // - startProtectedLongHeaderPacket or start1RTT packet prepare the packet;
    20  // - append*Frame appends frames to the payload; and
    21  // - finishProtectedLongHeaderPacket or finish1RTT finalize the packet.
    22  //
    23  // The start functions are efficient, so we can start speculatively
    24  // writing a packet before we know whether we have any frames to
    25  // put in it. The finish functions will abandon the packet if the
    26  // payload contains no data.
    27  type packetWriter struct {
    28  	dgramLim int // max datagram size
    29  	pktLim   int // max packet size
    30  	pktOff   int // offset of the start of the current packet
    31  	payOff   int // offset of the payload of the current packet
    32  	b        []byte
    33  	sent     *sentPacket
    34  }
    35  
    36  // reset prepares to write a datagram of at most lim bytes.
    37  func (w *packetWriter) reset(lim int) {
    38  	if cap(w.b) < lim {
    39  		w.b = make([]byte, 0, lim)
    40  	}
    41  	w.dgramLim = lim
    42  	w.b = w.b[:0]
    43  }
    44  
    45  // datagram returns the current datagram.
    46  func (w *packetWriter) datagram() []byte {
    47  	return w.b
    48  }
    49  
    50  // packet returns the size of the current packet.
    51  func (w *packetWriter) packetLen() int {
    52  	return len(w.b[w.pktOff:]) + aeadOverhead
    53  }
    54  
    55  // payload returns the payload of the current packet.
    56  func (w *packetWriter) payload() []byte {
    57  	return w.b[w.payOff:]
    58  }
    59  
    60  func (w *packetWriter) abandonPacket() {
    61  	w.b = w.b[:w.payOff]
    62  	w.sent.reset()
    63  }
    64  
    65  // startProtectedLongHeaderPacket starts writing an Initial, 0-RTT, or Handshake packet.
    66  func (w *packetWriter) startProtectedLongHeaderPacket(pnumMaxAcked packetNumber, p longPacket) {
    67  	if w.sent == nil {
    68  		w.sent = newSentPacket()
    69  	}
    70  	w.pktOff = len(w.b)
    71  	hdrSize := 1 // packet type
    72  	hdrSize += 4 // version
    73  	hdrSize += 1 + len(p.dstConnID)
    74  	hdrSize += 1 + len(p.srcConnID)
    75  	switch p.ptype {
    76  	case packetTypeInitial:
    77  		hdrSize += sizeVarint(uint64(len(p.extra))) + len(p.extra)
    78  	}
    79  	hdrSize += 2 // length, hardcoded to a 2-byte varint
    80  	pnumOff := len(w.b) + hdrSize
    81  	hdrSize += packetNumberLength(p.num, pnumMaxAcked)
    82  	payOff := len(w.b) + hdrSize
    83  	// Check if we have enough space to hold the packet, including the header,
    84  	// header protection sample (RFC 9001, section 5.4.2), and encryption overhead.
    85  	if pnumOff+4+headerProtectionSampleSize+aeadOverhead >= w.dgramLim {
    86  		// Set the limit on the packet size to be the current write buffer length,
    87  		// ensuring that any writes to the payload fail.
    88  		w.payOff = len(w.b)
    89  		w.pktLim = len(w.b)
    90  		return
    91  	}
    92  	w.payOff = payOff
    93  	w.pktLim = w.dgramLim - aeadOverhead
    94  	// We hardcode the payload length field to be 2 bytes, which limits the payload
    95  	// (including the packet number) to 16383 bytes (the largest 2-byte QUIC varint).
    96  	//
    97  	// Most networks don't support datagrams over 1472 bytes, and even Ethernet
    98  	// jumbo frames are generally only about 9000 bytes.
    99  	if lim := pnumOff + 16383 - aeadOverhead; lim < w.pktLim {
   100  		w.pktLim = lim
   101  	}
   102  	w.b = w.b[:payOff]
   103  }
   104  
   105  // finishProtectedLongHeaderPacket finishes writing an Initial, 0-RTT, or Handshake packet,
   106  // canceling the packet if it contains no payload.
   107  // It returns a sentPacket describing the packet, or nil if no packet was written.
   108  func (w *packetWriter) finishProtectedLongHeaderPacket(pnumMaxAcked packetNumber, k fixedKeys, p longPacket) *sentPacket {
   109  	if len(w.b) == w.payOff {
   110  		// The payload is empty, so just abandon the packet.
   111  		w.b = w.b[:w.pktOff]
   112  		return nil
   113  	}
   114  	pnumLen := packetNumberLength(p.num, pnumMaxAcked)
   115  	plen := w.padPacketLength(pnumLen)
   116  	hdr := w.b[:w.pktOff]
   117  	var typeBits byte
   118  	switch p.ptype {
   119  	case packetTypeInitial:
   120  		typeBits = longPacketTypeInitial
   121  	case packetType0RTT:
   122  		typeBits = longPacketType0RTT
   123  	case packetTypeHandshake:
   124  		typeBits = longPacketTypeHandshake
   125  	case packetTypeRetry:
   126  		typeBits = longPacketTypeRetry
   127  	}
   128  	hdr = append(hdr, headerFormLong|fixedBit|typeBits|byte(pnumLen-1))
   129  	hdr = binary.BigEndian.AppendUint32(hdr, p.version)
   130  	hdr = appendUint8Bytes(hdr, p.dstConnID)
   131  	hdr = appendUint8Bytes(hdr, p.srcConnID)
   132  	switch p.ptype {
   133  	case packetTypeInitial:
   134  		hdr = appendVarintBytes(hdr, p.extra) // token
   135  	}
   136  
   137  	// Packet length, always encoded as a 2-byte varint.
   138  	hdr = append(hdr, 0x40|byte(plen>>8), byte(plen))
   139  
   140  	pnumOff := len(hdr)
   141  	hdr = appendPacketNumber(hdr, p.num, pnumMaxAcked)
   142  
   143  	k.protect(hdr[w.pktOff:], w.b[len(hdr):], pnumOff-w.pktOff, p.num)
   144  	return w.finish(p.ptype, p.num)
   145  }
   146  
   147  // start1RTTPacket starts writing a 1-RTT (short header) packet.
   148  func (w *packetWriter) start1RTTPacket(pnum, pnumMaxAcked packetNumber, dstConnID []byte) {
   149  	if w.sent == nil {
   150  		w.sent = newSentPacket()
   151  	}
   152  	w.pktOff = len(w.b)
   153  	hdrSize := 1 // packet type
   154  	hdrSize += len(dstConnID)
   155  	// Ensure we have enough space to hold the packet, including the header,
   156  	// header protection sample (RFC 9001, section 5.4.2), and encryption overhead.
   157  	if len(w.b)+hdrSize+4+headerProtectionSampleSize+aeadOverhead >= w.dgramLim {
   158  		w.payOff = len(w.b)
   159  		w.pktLim = len(w.b)
   160  		return
   161  	}
   162  	hdrSize += packetNumberLength(pnum, pnumMaxAcked)
   163  	w.payOff = len(w.b) + hdrSize
   164  	w.pktLim = w.dgramLim - aeadOverhead
   165  	w.b = w.b[:w.payOff]
   166  }
   167  
   168  // finish1RTTPacket finishes writing a 1-RTT packet,
   169  // canceling the packet if it contains no payload.
   170  // It returns a sentPacket describing the packet, or nil if no packet was written.
   171  func (w *packetWriter) finish1RTTPacket(pnum, pnumMaxAcked packetNumber, dstConnID []byte, k *updatingKeyPair) *sentPacket {
   172  	if len(w.b) == w.payOff {
   173  		// The payload is empty, so just abandon the packet.
   174  		w.b = w.b[:w.pktOff]
   175  		return nil
   176  	}
   177  	// TODO: Spin
   178  	pnumLen := packetNumberLength(pnum, pnumMaxAcked)
   179  	hdr := w.b[:w.pktOff]
   180  	hdr = append(hdr, 0x40|byte(pnumLen-1))
   181  	hdr = append(hdr, dstConnID...)
   182  	pnumOff := len(hdr)
   183  	hdr = appendPacketNumber(hdr, pnum, pnumMaxAcked)
   184  	w.padPacketLength(pnumLen)
   185  	k.protect(hdr[w.pktOff:], w.b[len(hdr):], pnumOff-w.pktOff, pnum)
   186  	return w.finish(packetType1RTT, pnum)
   187  }
   188  
   189  // padPacketLength pads out the payload of the current packet to the minimum size,
   190  // and returns the combined length of the packet number and payload (used for the Length
   191  // field of long header packets).
   192  func (w *packetWriter) padPacketLength(pnumLen int) int {
   193  	plen := len(w.b) - w.payOff + pnumLen + aeadOverhead
   194  	// "To ensure that sufficient data is available for sampling, packets are
   195  	// padded so that the combined lengths of the encoded packet number and
   196  	// protected payload is at least 4 bytes longer than the sample required
   197  	// for header protection."
   198  	// https://www.rfc-editor.org/rfc/rfc9001.html#section-5.4.2
   199  	for plen < 4+headerProtectionSampleSize {
   200  		w.b = append(w.b, 0)
   201  		plen++
   202  	}
   203  	return plen
   204  }
   205  
   206  // finish finishes the current packet after protection is applied.
   207  func (w *packetWriter) finish(ptype packetType, pnum packetNumber) *sentPacket {
   208  	w.b = w.b[:len(w.b)+aeadOverhead]
   209  	w.sent.size = len(w.b) - w.pktOff
   210  	w.sent.ptype = ptype
   211  	w.sent.num = pnum
   212  	sent := w.sent
   213  	w.sent = nil
   214  	return sent
   215  }
   216  
   217  // avail reports how many more bytes may be written to the current packet.
   218  func (w *packetWriter) avail() int {
   219  	return w.pktLim - len(w.b)
   220  }
   221  
   222  // appendPaddingTo appends PADDING frames until the total datagram size
   223  // (including AEAD overhead of the current packet) is n.
   224  func (w *packetWriter) appendPaddingTo(n int) {
   225  	n -= aeadOverhead
   226  	lim := w.pktLim
   227  	if n < lim {
   228  		lim = n
   229  	}
   230  	if len(w.b) >= lim {
   231  		return
   232  	}
   233  	for len(w.b) < lim {
   234  		w.b = append(w.b, frameTypePadding)
   235  	}
   236  	// Packets are considered in flight when they contain a PADDING frame.
   237  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-2-3.6.1
   238  	w.sent.inFlight = true
   239  }
   240  
   241  func (w *packetWriter) appendPingFrame() (added bool) {
   242  	if len(w.b) >= w.pktLim {
   243  		return false
   244  	}
   245  	w.b = append(w.b, frameTypePing)
   246  	w.sent.markAckEliciting() // no need to record the frame itself
   247  	return true
   248  }
   249  
   250  // appendAckFrame appends an ACK frame to the payload.
   251  // It includes at least the most recent range in the rangeset
   252  // (the range with the largest packet numbers),
   253  // followed by as many additional ranges as fit within the packet.
   254  //
   255  // We always place ACK frames at the start of packets,
   256  // we limit the number of ack ranges retained, and
   257  // we set a minimum packet payload size.
   258  // As a result, appendAckFrame will rarely if ever drop ranges
   259  // in practice.
   260  //
   261  // In the event that ranges are dropped, the impact is limited
   262  // to the peer potentially failing to receive an acknowledgement
   263  // for an older packet during a period of high packet loss or
   264  // reordering. This may result in unnecessary retransmissions.
   265  func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscaledAckDelay) (added bool) {
   266  	if len(seen) == 0 {
   267  		return false
   268  	}
   269  	var (
   270  		largest    = uint64(seen.max())
   271  		firstRange = uint64(seen[len(seen)-1].size() - 1)
   272  	)
   273  	if w.avail() < 1+sizeVarint(largest)+sizeVarint(uint64(delay))+1+sizeVarint(firstRange) {
   274  		return false
   275  	}
   276  	w.b = append(w.b, frameTypeAck)
   277  	w.b = appendVarint(w.b, largest)
   278  	w.b = appendVarint(w.b, uint64(delay))
   279  	// The range count is technically a varint, but we'll reserve a single byte for it
   280  	// and never add more than 62 ranges (the maximum varint that fits in a byte).
   281  	rangeCountOff := len(w.b)
   282  	w.b = append(w.b, 0)
   283  	w.b = appendVarint(w.b, firstRange)
   284  	rangeCount := byte(0)
   285  	for i := len(seen) - 2; i >= 0; i-- {
   286  		gap := uint64(seen[i+1].start - seen[i].end - 1)
   287  		size := uint64(seen[i].size() - 1)
   288  		if w.avail() < sizeVarint(gap)+sizeVarint(size) || rangeCount > 62 {
   289  			break
   290  		}
   291  		w.b = appendVarint(w.b, gap)
   292  		w.b = appendVarint(w.b, size)
   293  		rangeCount++
   294  	}
   295  	w.b[rangeCountOff] = rangeCount
   296  	w.sent.appendNonAckElicitingFrame(frameTypeAck)
   297  	w.sent.appendInt(uint64(seen.max()))
   298  	return true
   299  }
   300  
   301  func (w *packetWriter) appendNewTokenFrame(token []byte) (added bool) {
   302  	if w.avail() < 1+sizeVarint(uint64(len(token)))+len(token) {
   303  		return false
   304  	}
   305  	w.b = append(w.b, frameTypeNewToken)
   306  	w.b = appendVarintBytes(w.b, token)
   307  	return true
   308  }
   309  
   310  func (w *packetWriter) appendResetStreamFrame(id streamID, code uint64, finalSize int64) (added bool) {
   311  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(code)+sizeVarint(uint64(finalSize)) {
   312  		return false
   313  	}
   314  	w.b = append(w.b, frameTypeResetStream)
   315  	w.b = appendVarint(w.b, uint64(id))
   316  	w.b = appendVarint(w.b, code)
   317  	w.b = appendVarint(w.b, uint64(finalSize))
   318  	w.sent.appendAckElicitingFrame(frameTypeResetStream)
   319  	w.sent.appendInt(uint64(id))
   320  	return true
   321  }
   322  
   323  func (w *packetWriter) appendStopSendingFrame(id streamID, code uint64) (added bool) {
   324  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(code) {
   325  		return false
   326  	}
   327  	w.b = append(w.b, frameTypeStopSending)
   328  	w.b = appendVarint(w.b, uint64(id))
   329  	w.b = appendVarint(w.b, code)
   330  	w.sent.appendAckElicitingFrame(frameTypeStopSending)
   331  	w.sent.appendInt(uint64(id))
   332  	return true
   333  }
   334  
   335  // appendCryptoFrame appends a CRYPTO frame.
   336  // It returns a []byte into which the data should be written and whether a frame was added.
   337  // The returned []byte may be smaller than size if the packet cannot hold all the data.
   338  func (w *packetWriter) appendCryptoFrame(off int64, size int) (_ []byte, added bool) {
   339  	max := w.avail()
   340  	max -= 1                        // frame type
   341  	max -= sizeVarint(uint64(off))  // offset
   342  	max -= sizeVarint(uint64(size)) // maximum length
   343  	if max <= 0 {
   344  		return nil, false
   345  	}
   346  	if max < size {
   347  		size = max
   348  	}
   349  	w.b = append(w.b, frameTypeCrypto)
   350  	w.b = appendVarint(w.b, uint64(off))
   351  	w.b = appendVarint(w.b, uint64(size))
   352  	start := len(w.b)
   353  	w.b = w.b[:start+size]
   354  	w.sent.appendAckElicitingFrame(frameTypeCrypto)
   355  	w.sent.appendOffAndSize(off, size)
   356  	return w.b[start:][:size], true
   357  }
   358  
   359  // appendStreamFrame appends a STREAM frame.
   360  // It returns a []byte into which the data should be written and whether a frame was added.
   361  // The returned []byte may be smaller than size if the packet cannot hold all the data.
   362  func (w *packetWriter) appendStreamFrame(id streamID, off int64, size int, fin bool) (_ []byte, added bool) {
   363  	typ := uint8(frameTypeStreamBase | streamLenBit)
   364  	max := w.avail()
   365  	max -= 1 // frame type
   366  	max -= sizeVarint(uint64(id))
   367  	if off != 0 {
   368  		max -= sizeVarint(uint64(off))
   369  		typ |= streamOffBit
   370  	}
   371  	max -= sizeVarint(uint64(size)) // maximum length
   372  	if max < 0 || (max == 0 && size > 0) {
   373  		return nil, false
   374  	}
   375  	if max < size {
   376  		size = max
   377  	} else if fin {
   378  		typ |= streamFinBit
   379  	}
   380  	w.b = append(w.b, typ)
   381  	w.b = appendVarint(w.b, uint64(id))
   382  	if off != 0 {
   383  		w.b = appendVarint(w.b, uint64(off))
   384  	}
   385  	w.b = appendVarint(w.b, uint64(size))
   386  	start := len(w.b)
   387  	w.b = w.b[:start+size]
   388  	w.sent.appendAckElicitingFrame(typ & (frameTypeStreamBase | streamFinBit))
   389  	w.sent.appendInt(uint64(id))
   390  	w.sent.appendOffAndSize(off, size)
   391  	return w.b[start:][:size], true
   392  }
   393  
   394  func (w *packetWriter) appendMaxDataFrame(max int64) (added bool) {
   395  	if w.avail() < 1+sizeVarint(uint64(max)) {
   396  		return false
   397  	}
   398  	w.b = append(w.b, frameTypeMaxData)
   399  	w.b = appendVarint(w.b, uint64(max))
   400  	w.sent.appendAckElicitingFrame(frameTypeMaxData)
   401  	return true
   402  }
   403  
   404  func (w *packetWriter) appendMaxStreamDataFrame(id streamID, max int64) (added bool) {
   405  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(uint64(max)) {
   406  		return false
   407  	}
   408  	w.b = append(w.b, frameTypeMaxStreamData)
   409  	w.b = appendVarint(w.b, uint64(id))
   410  	w.b = appendVarint(w.b, uint64(max))
   411  	w.sent.appendAckElicitingFrame(frameTypeMaxStreamData)
   412  	w.sent.appendInt(uint64(id))
   413  	return true
   414  }
   415  
   416  func (w *packetWriter) appendMaxStreamsFrame(streamType streamType, max int64) (added bool) {
   417  	if w.avail() < 1+sizeVarint(uint64(max)) {
   418  		return false
   419  	}
   420  	var typ byte
   421  	if streamType == bidiStream {
   422  		typ = frameTypeMaxStreamsBidi
   423  	} else {
   424  		typ = frameTypeMaxStreamsUni
   425  	}
   426  	w.b = append(w.b, typ)
   427  	w.b = appendVarint(w.b, uint64(max))
   428  	w.sent.appendAckElicitingFrame(typ)
   429  	return true
   430  }
   431  
   432  func (w *packetWriter) appendDataBlockedFrame(max int64) (added bool) {
   433  	if w.avail() < 1+sizeVarint(uint64(max)) {
   434  		return false
   435  	}
   436  	w.b = append(w.b, frameTypeDataBlocked)
   437  	w.b = appendVarint(w.b, uint64(max))
   438  	w.sent.appendAckElicitingFrame(frameTypeDataBlocked)
   439  	return true
   440  }
   441  
   442  func (w *packetWriter) appendStreamDataBlockedFrame(id streamID, max int64) (added bool) {
   443  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(uint64(max)) {
   444  		return false
   445  	}
   446  	w.b = append(w.b, frameTypeStreamDataBlocked)
   447  	w.b = appendVarint(w.b, uint64(id))
   448  	w.b = appendVarint(w.b, uint64(max))
   449  	w.sent.appendAckElicitingFrame(frameTypeStreamDataBlocked)
   450  	w.sent.appendInt(uint64(id))
   451  	return true
   452  }
   453  
   454  func (w *packetWriter) appendStreamsBlockedFrame(typ streamType, max int64) (added bool) {
   455  	if w.avail() < 1+sizeVarint(uint64(max)) {
   456  		return false
   457  	}
   458  	var ftype byte
   459  	if typ == bidiStream {
   460  		ftype = frameTypeStreamsBlockedBidi
   461  	} else {
   462  		ftype = frameTypeStreamsBlockedUni
   463  	}
   464  	w.b = append(w.b, ftype)
   465  	w.b = appendVarint(w.b, uint64(max))
   466  	w.sent.appendAckElicitingFrame(ftype)
   467  	return true
   468  }
   469  
   470  func (w *packetWriter) appendNewConnectionIDFrame(seq, retirePriorTo int64, connID []byte, token [16]byte) (added bool) {
   471  	if w.avail() < 1+sizeVarint(uint64(seq))+sizeVarint(uint64(retirePriorTo))+1+len(connID)+len(token) {
   472  		return false
   473  	}
   474  	w.b = append(w.b, frameTypeNewConnectionID)
   475  	w.b = appendVarint(w.b, uint64(seq))
   476  	w.b = appendVarint(w.b, uint64(retirePriorTo))
   477  	w.b = appendUint8Bytes(w.b, connID)
   478  	w.b = append(w.b, token[:]...)
   479  	w.sent.appendAckElicitingFrame(frameTypeNewConnectionID)
   480  	w.sent.appendInt(uint64(seq))
   481  	return true
   482  }
   483  
   484  func (w *packetWriter) appendRetireConnectionIDFrame(seq int64) (added bool) {
   485  	if w.avail() < 1+sizeVarint(uint64(seq)) {
   486  		return false
   487  	}
   488  	w.b = append(w.b, frameTypeRetireConnectionID)
   489  	w.b = appendVarint(w.b, uint64(seq))
   490  	w.sent.appendAckElicitingFrame(frameTypeRetireConnectionID)
   491  	w.sent.appendInt(uint64(seq))
   492  	return true
   493  }
   494  
   495  func (w *packetWriter) appendPathChallengeFrame(data pathChallengeData) (added bool) {
   496  	if w.avail() < 1+8 {
   497  		return false
   498  	}
   499  	w.b = append(w.b, frameTypePathChallenge)
   500  	w.b = append(w.b, data[:]...)
   501  	w.sent.markAckEliciting() // no need to record the frame itself
   502  	return true
   503  }
   504  
   505  func (w *packetWriter) appendPathResponseFrame(data pathChallengeData) (added bool) {
   506  	if w.avail() < 1+8 {
   507  		return false
   508  	}
   509  	w.b = append(w.b, frameTypePathResponse)
   510  	w.b = append(w.b, data[:]...)
   511  	w.sent.markAckEliciting() // no need to record the frame itself
   512  	return true
   513  }
   514  
   515  // appendConnectionCloseTransportFrame appends a CONNECTION_CLOSE frame
   516  // carrying a transport error code.
   517  func (w *packetWriter) appendConnectionCloseTransportFrame(code transportError, frameType uint64, reason string) (added bool) {
   518  	if w.avail() < 1+sizeVarint(uint64(code))+sizeVarint(frameType)+sizeVarint(uint64(len(reason)))+len(reason) {
   519  		return false
   520  	}
   521  	w.b = append(w.b, frameTypeConnectionCloseTransport)
   522  	w.b = appendVarint(w.b, uint64(code))
   523  	w.b = appendVarint(w.b, frameType)
   524  	w.b = appendVarintBytes(w.b, []byte(reason))
   525  	// We don't record CONNECTION_CLOSE frames in w.sent, since they are never acked or
   526  	// detected as lost.
   527  	return true
   528  }
   529  
   530  // appendConnectionCloseTransportFrame appends a CONNECTION_CLOSE frame
   531  // carrying an application protocol error code.
   532  func (w *packetWriter) appendConnectionCloseApplicationFrame(code uint64, reason string) (added bool) {
   533  	if w.avail() < 1+sizeVarint(code)+sizeVarint(uint64(len(reason)))+len(reason) {
   534  		return false
   535  	}
   536  	w.b = append(w.b, frameTypeConnectionCloseApplication)
   537  	w.b = appendVarint(w.b, code)
   538  	w.b = appendVarintBytes(w.b, []byte(reason))
   539  	// We don't record CONNECTION_CLOSE frames in w.sent, since they are never acked or
   540  	// detected as lost.
   541  	return true
   542  }
   543  
   544  func (w *packetWriter) appendHandshakeDoneFrame() (added bool) {
   545  	if w.avail() < 1 {
   546  		return false
   547  	}
   548  	w.b = append(w.b, frameTypeHandshakeDone)
   549  	w.sent.appendAckElicitingFrame(frameTypeHandshakeDone)
   550  	return true
   551  }