...

Source file src/golang.org/x/net/internal/quic/packet_writer.go

Documentation: golang.org/x/net/internal/quic

     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.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(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(pnum packetNumber) *sentPacket {
   208  	w.b = w.b[:len(w.b)+aeadOverhead]
   209  	w.sent.size = len(w.b) - w.pktOff
   210  	w.sent.num = pnum
   211  	sent := w.sent
   212  	w.sent = nil
   213  	return sent
   214  }
   215  
   216  // avail reports how many more bytes may be written to the current packet.
   217  func (w *packetWriter) avail() int {
   218  	return w.pktLim - len(w.b)
   219  }
   220  
   221  // appendPaddingTo appends PADDING frames until the total datagram size
   222  // (including AEAD overhead of the current packet) is n.
   223  func (w *packetWriter) appendPaddingTo(n int) {
   224  	n -= aeadOverhead
   225  	lim := w.pktLim
   226  	if n < lim {
   227  		lim = n
   228  	}
   229  	if len(w.b) >= lim {
   230  		return
   231  	}
   232  	for len(w.b) < lim {
   233  		w.b = append(w.b, frameTypePadding)
   234  	}
   235  	// Packets are considered in flight when they contain a PADDING frame.
   236  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-2-3.6.1
   237  	w.sent.inFlight = true
   238  }
   239  
   240  func (w *packetWriter) appendPingFrame() (added bool) {
   241  	if len(w.b) >= w.pktLim {
   242  		return false
   243  	}
   244  	w.b = append(w.b, frameTypePing)
   245  	// Mark this packet as ack-eliciting and in-flight,
   246  	// but there's no need to record the presence of a PING frame in it.
   247  	w.sent.ackEliciting = true
   248  	w.sent.inFlight = true
   249  	return true
   250  }
   251  
   252  // appendAckFrame appends an ACK frame to the payload.
   253  // It includes at least the most recent range in the rangeset
   254  // (the range with the largest packet numbers),
   255  // followed by as many additional ranges as fit within the packet.
   256  //
   257  // We always place ACK frames at the start of packets,
   258  // we limit the number of ack ranges retained, and
   259  // we set a minimum packet payload size.
   260  // As a result, appendAckFrame will rarely if ever drop ranges
   261  // in practice.
   262  //
   263  // In the event that ranges are dropped, the impact is limited
   264  // to the peer potentially failing to receive an acknowledgement
   265  // for an older packet during a period of high packet loss or
   266  // reordering. This may result in unnecessary retransmissions.
   267  func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscaledAckDelay) (added bool) {
   268  	if len(seen) == 0 {
   269  		return false
   270  	}
   271  	var (
   272  		largest    = uint64(seen.max())
   273  		firstRange = uint64(seen[len(seen)-1].size() - 1)
   274  	)
   275  	if w.avail() < 1+sizeVarint(largest)+sizeVarint(uint64(delay))+1+sizeVarint(firstRange) {
   276  		return false
   277  	}
   278  	w.b = append(w.b, frameTypeAck)
   279  	w.b = appendVarint(w.b, largest)
   280  	w.b = appendVarint(w.b, uint64(delay))
   281  	// The range count is technically a varint, but we'll reserve a single byte for it
   282  	// and never add more than 62 ranges (the maximum varint that fits in a byte).
   283  	rangeCountOff := len(w.b)
   284  	w.b = append(w.b, 0)
   285  	w.b = appendVarint(w.b, firstRange)
   286  	rangeCount := byte(0)
   287  	for i := len(seen) - 2; i >= 0; i-- {
   288  		gap := uint64(seen[i+1].start - seen[i].end - 1)
   289  		size := uint64(seen[i].size() - 1)
   290  		if w.avail() < sizeVarint(gap)+sizeVarint(size) || rangeCount > 62 {
   291  			break
   292  		}
   293  		w.b = appendVarint(w.b, gap)
   294  		w.b = appendVarint(w.b, size)
   295  		rangeCount++
   296  	}
   297  	w.b[rangeCountOff] = rangeCount
   298  	w.sent.appendNonAckElicitingFrame(frameTypeAck)
   299  	w.sent.appendInt(uint64(seen.max()))
   300  	return true
   301  }
   302  
   303  func (w *packetWriter) appendNewTokenFrame(token []byte) (added bool) {
   304  	if w.avail() < 1+sizeVarint(uint64(len(token)))+len(token) {
   305  		return false
   306  	}
   307  	w.b = append(w.b, frameTypeNewToken)
   308  	w.b = appendVarintBytes(w.b, token)
   309  	return true
   310  }
   311  
   312  func (w *packetWriter) appendResetStreamFrame(id streamID, code uint64, finalSize int64) (added bool) {
   313  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(code)+sizeVarint(uint64(finalSize)) {
   314  		return false
   315  	}
   316  	w.b = append(w.b, frameTypeResetStream)
   317  	w.b = appendVarint(w.b, uint64(id))
   318  	w.b = appendVarint(w.b, code)
   319  	w.b = appendVarint(w.b, uint64(finalSize))
   320  	w.sent.appendAckElicitingFrame(frameTypeResetStream)
   321  	w.sent.appendInt(uint64(id))
   322  	return true
   323  }
   324  
   325  func (w *packetWriter) appendStopSendingFrame(id streamID, code uint64) (added bool) {
   326  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(code) {
   327  		return false
   328  	}
   329  	w.b = append(w.b, frameTypeStopSending)
   330  	w.b = appendVarint(w.b, uint64(id))
   331  	w.b = appendVarint(w.b, code)
   332  	w.sent.appendAckElicitingFrame(frameTypeStopSending)
   333  	w.sent.appendInt(uint64(id))
   334  	return true
   335  }
   336  
   337  // appendCryptoFrame appends a CRYPTO frame.
   338  // It returns a []byte into which the data should be written and whether a frame was added.
   339  // The returned []byte may be smaller than size if the packet cannot hold all the data.
   340  func (w *packetWriter) appendCryptoFrame(off int64, size int) (_ []byte, added bool) {
   341  	max := w.avail()
   342  	max -= 1                        // frame type
   343  	max -= sizeVarint(uint64(off))  // offset
   344  	max -= sizeVarint(uint64(size)) // maximum length
   345  	if max <= 0 {
   346  		return nil, false
   347  	}
   348  	if max < size {
   349  		size = max
   350  	}
   351  	w.b = append(w.b, frameTypeCrypto)
   352  	w.b = appendVarint(w.b, uint64(off))
   353  	w.b = appendVarint(w.b, uint64(size))
   354  	start := len(w.b)
   355  	w.b = w.b[:start+size]
   356  	w.sent.appendAckElicitingFrame(frameTypeCrypto)
   357  	w.sent.appendOffAndSize(off, size)
   358  	return w.b[start:][:size], true
   359  }
   360  
   361  // appendStreamFrame appends a STREAM frame.
   362  // It returns a []byte into which the data should be written and whether a frame was added.
   363  // The returned []byte may be smaller than size if the packet cannot hold all the data.
   364  func (w *packetWriter) appendStreamFrame(id streamID, off int64, size int, fin bool) (_ []byte, added bool) {
   365  	typ := uint8(frameTypeStreamBase | streamLenBit)
   366  	max := w.avail()
   367  	max -= 1 // frame type
   368  	max -= sizeVarint(uint64(id))
   369  	if off != 0 {
   370  		max -= sizeVarint(uint64(off))
   371  		typ |= streamOffBit
   372  	}
   373  	max -= sizeVarint(uint64(size)) // maximum length
   374  	if max < 0 || (max == 0 && size > 0) {
   375  		return nil, false
   376  	}
   377  	if max < size {
   378  		size = max
   379  	} else if fin {
   380  		typ |= streamFinBit
   381  	}
   382  	w.b = append(w.b, typ)
   383  	w.b = appendVarint(w.b, uint64(id))
   384  	if off != 0 {
   385  		w.b = appendVarint(w.b, uint64(off))
   386  	}
   387  	w.b = appendVarint(w.b, uint64(size))
   388  	start := len(w.b)
   389  	w.b = w.b[:start+size]
   390  	if fin {
   391  		w.sent.appendAckElicitingFrame(frameTypeStreamBase | streamFinBit)
   392  	} else {
   393  		w.sent.appendAckElicitingFrame(frameTypeStreamBase)
   394  	}
   395  	w.sent.appendInt(uint64(id))
   396  	w.sent.appendOffAndSize(off, size)
   397  	return w.b[start:][:size], true
   398  }
   399  
   400  func (w *packetWriter) appendMaxDataFrame(max int64) (added bool) {
   401  	if w.avail() < 1+sizeVarint(uint64(max)) {
   402  		return false
   403  	}
   404  	w.b = append(w.b, frameTypeMaxData)
   405  	w.b = appendVarint(w.b, uint64(max))
   406  	w.sent.appendAckElicitingFrame(frameTypeMaxData)
   407  	return true
   408  }
   409  
   410  func (w *packetWriter) appendMaxStreamDataFrame(id streamID, max int64) (added bool) {
   411  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(uint64(max)) {
   412  		return false
   413  	}
   414  	w.b = append(w.b, frameTypeMaxStreamData)
   415  	w.b = appendVarint(w.b, uint64(id))
   416  	w.b = appendVarint(w.b, uint64(max))
   417  	w.sent.appendAckElicitingFrame(frameTypeMaxStreamData)
   418  	w.sent.appendInt(uint64(id))
   419  	return true
   420  }
   421  
   422  func (w *packetWriter) appendMaxStreamsFrame(streamType streamType, max int64) (added bool) {
   423  	if w.avail() < 1+sizeVarint(uint64(max)) {
   424  		return false
   425  	}
   426  	var typ byte
   427  	if streamType == bidiStream {
   428  		typ = frameTypeMaxStreamsBidi
   429  	} else {
   430  		typ = frameTypeMaxStreamsUni
   431  	}
   432  	w.b = append(w.b, typ)
   433  	w.b = appendVarint(w.b, uint64(max))
   434  	w.sent.appendAckElicitingFrame(typ)
   435  	return true
   436  }
   437  
   438  func (w *packetWriter) appendDataBlockedFrame(max int64) (added bool) {
   439  	if w.avail() < 1+sizeVarint(uint64(max)) {
   440  		return false
   441  	}
   442  	w.b = append(w.b, frameTypeDataBlocked)
   443  	w.b = appendVarint(w.b, uint64(max))
   444  	w.sent.appendAckElicitingFrame(frameTypeDataBlocked)
   445  	return true
   446  }
   447  
   448  func (w *packetWriter) appendStreamDataBlockedFrame(id streamID, max int64) (added bool) {
   449  	if w.avail() < 1+sizeVarint(uint64(id))+sizeVarint(uint64(max)) {
   450  		return false
   451  	}
   452  	w.b = append(w.b, frameTypeStreamDataBlocked)
   453  	w.b = appendVarint(w.b, uint64(id))
   454  	w.b = appendVarint(w.b, uint64(max))
   455  	w.sent.appendAckElicitingFrame(frameTypeStreamDataBlocked)
   456  	w.sent.appendInt(uint64(id))
   457  	return true
   458  }
   459  
   460  func (w *packetWriter) appendStreamsBlockedFrame(typ streamType, max int64) (added bool) {
   461  	if w.avail() < 1+sizeVarint(uint64(max)) {
   462  		return false
   463  	}
   464  	var ftype byte
   465  	if typ == bidiStream {
   466  		ftype = frameTypeStreamsBlockedBidi
   467  	} else {
   468  		ftype = frameTypeStreamsBlockedUni
   469  	}
   470  	w.b = append(w.b, ftype)
   471  	w.b = appendVarint(w.b, uint64(max))
   472  	w.sent.appendAckElicitingFrame(ftype)
   473  	return true
   474  }
   475  
   476  func (w *packetWriter) appendNewConnectionIDFrame(seq, retirePriorTo int64, connID []byte, token [16]byte) (added bool) {
   477  	if w.avail() < 1+sizeVarint(uint64(seq))+sizeVarint(uint64(retirePriorTo))+1+len(connID)+len(token) {
   478  		return false
   479  	}
   480  	w.b = append(w.b, frameTypeNewConnectionID)
   481  	w.b = appendVarint(w.b, uint64(seq))
   482  	w.b = appendVarint(w.b, uint64(retirePriorTo))
   483  	w.b = appendUint8Bytes(w.b, connID)
   484  	w.b = append(w.b, token[:]...)
   485  	w.sent.appendAckElicitingFrame(frameTypeNewConnectionID)
   486  	w.sent.appendInt(uint64(seq))
   487  	return true
   488  }
   489  
   490  func (w *packetWriter) appendRetireConnectionIDFrame(seq int64) (added bool) {
   491  	if w.avail() < 1+sizeVarint(uint64(seq)) {
   492  		return false
   493  	}
   494  	w.b = append(w.b, frameTypeRetireConnectionID)
   495  	w.b = appendVarint(w.b, uint64(seq))
   496  	w.sent.appendAckElicitingFrame(frameTypeRetireConnectionID)
   497  	w.sent.appendInt(uint64(seq))
   498  	return true
   499  }
   500  
   501  func (w *packetWriter) appendPathChallengeFrame(data uint64) (added bool) {
   502  	if w.avail() < 1+8 {
   503  		return false
   504  	}
   505  	w.b = append(w.b, frameTypePathChallenge)
   506  	w.b = binary.BigEndian.AppendUint64(w.b, data)
   507  	w.sent.appendAckElicitingFrame(frameTypePathChallenge)
   508  	return true
   509  }
   510  
   511  func (w *packetWriter) appendPathResponseFrame(data uint64) (added bool) {
   512  	if w.avail() < 1+8 {
   513  		return false
   514  	}
   515  	w.b = append(w.b, frameTypePathResponse)
   516  	w.b = binary.BigEndian.AppendUint64(w.b, data)
   517  	w.sent.appendAckElicitingFrame(frameTypePathResponse)
   518  	return true
   519  }
   520  
   521  // appendConnectionCloseTransportFrame appends a CONNECTION_CLOSE frame
   522  // carrying a transport error code.
   523  func (w *packetWriter) appendConnectionCloseTransportFrame(code transportError, frameType uint64, reason string) (added bool) {
   524  	if w.avail() < 1+sizeVarint(uint64(code))+sizeVarint(frameType)+sizeVarint(uint64(len(reason)))+len(reason) {
   525  		return false
   526  	}
   527  	w.b = append(w.b, frameTypeConnectionCloseTransport)
   528  	w.b = appendVarint(w.b, uint64(code))
   529  	w.b = appendVarint(w.b, frameType)
   530  	w.b = appendVarintBytes(w.b, []byte(reason))
   531  	// We don't record CONNECTION_CLOSE frames in w.sent, since they are never acked or
   532  	// detected as lost.
   533  	return true
   534  }
   535  
   536  // appendConnectionCloseTransportFrame appends a CONNECTION_CLOSE frame
   537  // carrying an application protocol error code.
   538  func (w *packetWriter) appendConnectionCloseApplicationFrame(code uint64, reason string) (added bool) {
   539  	if w.avail() < 1+sizeVarint(code)+sizeVarint(uint64(len(reason)))+len(reason) {
   540  		return false
   541  	}
   542  	w.b = append(w.b, frameTypeConnectionCloseApplication)
   543  	w.b = appendVarint(w.b, code)
   544  	w.b = appendVarintBytes(w.b, []byte(reason))
   545  	// We don't record CONNECTION_CLOSE frames in w.sent, since they are never acked or
   546  	// detected as lost.
   547  	return true
   548  }
   549  
   550  func (w *packetWriter) appendHandshakeDoneFrame() (added bool) {
   551  	if w.avail() < 1 {
   552  		return false
   553  	}
   554  	w.b = append(w.b, frameTypeHandshakeDone)
   555  	w.sent.appendAckElicitingFrame(frameTypeHandshakeDone)
   556  	return true
   557  }
   558  

View as plain text