Refactor the tcp segment implementation to use refsvfs.

This change also fixes existing refcounting correctness issues.

PiperOrigin-RevId: 437118979
This commit is contained in:
Lucas Manning
2022-03-24 16:55:50 -07:00
committed by gVisor bot
parent 04a94d647d
commit 28cf71cc61
25 changed files with 237 additions and 54 deletions
+2
View File
@@ -78,6 +78,8 @@ func (f *fakeTransportEndpoint) Abort() {
f.Close()
}
func (*fakeTransportEndpoint) Release() {}
func (f *fakeTransportEndpoint) Close() {
// TODO(gvisor.dev/issue/5153): Consider retaining the route.
f.route.Release()
+15
View File
@@ -674,6 +674,9 @@ type Endpoint interface {
// SocketOptions returns the structure which contains all the socket
// level options.
SocketOptions() *SocketOptions
// Release releases all reference counted objects held by the endpoint.
Release()
}
// LinkPacketInfo holds Link layer information for a received packet.
@@ -2490,6 +2493,18 @@ func GetDanglingEndpoints() []Endpoint {
return es
}
// ReleaseDanglingEndpoints clears out all all reference counted objects held by
// dangling endpoints.
func ReleaseDanglingEndpoints() {
// Get the dangling endpoints first to avoid locking around Release(), which
// can cause a lock inversion with endpoint.mu and danglingEndpointsMu.
// Calling Release on a dangling endpoint that has been deleted is a noop.
eps := GetDanglingEndpoints()
for _, ep := range eps {
ep.Release()
}
}
// AddDanglingEndpoint adds a dangling endpoint.
func AddDanglingEndpoint(e Endpoint) {
danglingEndpointsMu.Lock()
+3
View File
@@ -767,6 +767,9 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB
// HandleError implements stack.TransportEndpoint.
func (*endpoint) HandleError(stack.TransportError, *stack.PacketBuffer) {}
// Release implements stack.TransportEndpoint.
func (*endpoint) Release() {}
// State implements tcpip.Endpoint.State. The ICMP endpoint currently doesn't
// expose internal socket state.
func (e *endpoint) State() uint32 {
@@ -151,6 +151,11 @@ func (*endpoint) Wait() {
// No-op.
}
// Release implements stack.TransportEndpoint.Release.
func (*endpoint) Release() {
// No-op.
}
// LastError implements tcpip.Endpoint.LastError.
func (*endpoint) LastError() tcpip.Error {
return nil
+3
View File
@@ -492,6 +492,9 @@ func (ep *endpoint) Stats() tcpip.EndpointStats {
// SetOwner implements tcpip.Endpoint.SetOwner.
func (*endpoint) SetOwner(tcpip.PacketOwner) {}
// Release implements tcpip.Release.
func (*endpoint) Release() {}
// SocketOptions implements tcpip.Endpoint.SocketOptions.
func (ep *endpoint) SocketOptions() *tcpip.SocketOptions {
return &ep.ops
+3
View File
@@ -735,6 +735,9 @@ func (*endpoint) LastError() tcpip.Error {
return nil
}
// Release implements stack.TransportEndpoint.Release.
func (*endpoint) Release() {}
// SocketOptions implements tcpip.Endpoint.SocketOptions.
func (e *endpoint) SocketOptions() *tcpip.SocketOptions {
return &e.ops
+13
View File
@@ -15,6 +15,17 @@ go_template_instance(
},
)
go_template_instance(
name = "tcp_segment_refs",
out = "tcp_segment_refs.go",
package = "tcp",
prefix = "segment",
template = "//pkg/refsvfs2:refs_template",
types = {
"T": "segment",
},
)
go_template_instance(
name = "tcp_endpoint_list",
out = "tcp_endpoint_list.go",
@@ -54,6 +65,7 @@ go_library(
"snd.go",
"tcp_endpoint_list.go",
"tcp_segment_list.go",
"tcp_segment_refs.go",
"timer.go",
],
imports = ["gvisor.dev/gvisor/pkg/tcpip/buffer"],
@@ -61,6 +73,7 @@ go_library(
deps = [
"//pkg/log",
"//pkg/rand",
"//pkg/refsvfs2",
"//pkg/sleep",
"//pkg/sync",
"//pkg/tcpip",
+2 -3
View File
@@ -715,7 +715,6 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) tcpip.Err
// Requeue the segment if the ACK completing the handshake has more info
// to be procesed by the newly established endpoint.
if (s.flags.Contains(header.TCPFlagFin) || s.data.Size() > 0) && n.enqueueSegment(s) {
s.incRef()
n.newSegmentWaker.Assert()
}
@@ -780,7 +779,7 @@ func (e *endpoint) protocolListenLoop(rcvWnd seqnum.Size) {
// TODO(gvisor.dev/issue/4690): Better handle errors instead of
// silently dropping.
_ = e.handleListenSegment(ctx, s)
s.decRef()
s.DecRef()
}
close(e.drainDone)
e.mu.Unlock()
@@ -801,7 +800,7 @@ func (e *endpoint) protocolListenLoop(rcvWnd seqnum.Size) {
// TODO(gvisor.dev/issue/4690): Better handle errors instead of
// silently dropping.
_ = e.handleListenSegment(ctx, s)
s.decRef()
s.DecRef()
}
// If the queue is not empty, make sure we'll wake up
+14 -12
View File
@@ -423,7 +423,6 @@ func (h *handshake) synRcvdState(s *segment) tcpip.Error {
// Requeue the segment if the ACK completing the handshake has more info
// to be procesed by the newly established endpoint.
if (s.flags.Contains(header.TCPFlagFin) || s.data.Size() > 0) && h.ep.enqueueSegment(s) {
s.incRef()
h.ep.newSegmentWaker.Assert()
}
return nil
@@ -459,7 +458,7 @@ func (h *handshake) processSegments() tcpip.Error {
}
err := h.handleSegment(s)
s.decRef()
s.DecRef()
if err != nil {
return err
}
@@ -590,7 +589,7 @@ func (h *handshake) complete() tcpip.Error {
for !h.ep.segmentQueue.empty() {
s := h.ep.segmentQueue.dequeue()
err := h.handleSegment(s)
s.decRef()
s.DecRef()
if err != nil {
return err
}
@@ -969,7 +968,7 @@ func (e *endpoint) sendData(next *segment) {
if next == nil {
return
}
e.snd.writeNext = next
e.snd.updateWriteNext(next)
}
// Push out any new packets.
@@ -1003,6 +1002,10 @@ func (e *endpoint) resetConnectionLocked(err tcpip.Error) {
}
e.sendRaw(buffer.VectorisedView{}, header.TCPFlagAck|header.TCPFlagRst, resetSeqNum, e.rcv.RcvNxt, 0)
}
// Don't purge read queues here. If there's buffered data, it's still allowed
// to be read.
e.purgeWriteQueue()
e.purgePendingRcvQueue()
}
// completeWorkerLocked is called by the worker goroutine when it's about to
@@ -1058,7 +1061,6 @@ func (e *endpoint) tryDeliverSegmentFromClosedEndpoint(s *segment) {
}
if ep == nil {
replyWithReset(e.stack, s, stack.DefaultTOS, tcpip.UseDefaultIPv4TTL, tcpip.UseDefaultIPv6HopLimit)
s.decRef()
return
}
@@ -1082,6 +1084,7 @@ func (e *endpoint) drainClosingSegmentQueue() {
}
e.tryDeliverSegmentFromClosedEndpoint(s)
s.DecRef()
}
}
@@ -1150,7 +1153,7 @@ func (e *endpoint) handleSegmentsLocked(fastPath bool) tcpip.Error {
}
cont, err := e.handleSegmentLocked(s)
s.decRef()
s.DecRef()
if err != nil {
return err
}
@@ -1553,6 +1556,7 @@ func (e *endpoint) protocolMainLoop(handshake bool, wakerInitDone chan<- struct{
e.workerCleanup = true
if err != nil {
e.resetConnectionLocked(err)
e.releaseLocked()
}
}
@@ -1656,15 +1660,13 @@ func (e *endpoint) handleTimeWaitSegments() (extendTimeWait bool, reuseTW func()
if EndpointState(tcpEP.State()) == StateListen {
reuseTW = func() {
if !tcpEP.enqueueSegment(s) {
s.decRef()
return
}
tcpEP.newSegmentWaker.Assert()
s.DecRef()
}
// We explicitly do not decRef
// the segment as it's still
// valid and being reflected to
// a listening endpoint.
// We explicitly do not DecRef the segment as it's still valid and
// being reflected to a listening endpoint.
return false, reuseTW
}
}
@@ -1673,7 +1675,7 @@ func (e *endpoint) handleTimeWaitSegments() (extendTimeWait bool, reuseTW func()
if extTW {
extendTimeWait = true
}
s.decRef()
s.DecRef()
}
if checkRequeue && !e.segmentQueue.empty() {
e.newSegmentWaker.Assert()
+1 -3
View File
@@ -179,17 +179,16 @@ func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.Trans
ep := stackEP.(*endpoint)
s := newIncomingSegment(id, clock, pkt)
defer s.DecRef()
if !s.parse(pkt.RXTransportChecksumValidated) {
ep.stack.Stats().TCP.InvalidSegmentsReceived.Increment()
ep.stats.ReceiveErrors.MalformedPacketsReceived.Increment()
s.decRef()
return
}
if !s.csumValid {
ep.stack.Stats().TCP.ChecksumErrors.Increment()
ep.stats.ReceiveErrors.ChecksumErrors.Increment()
s.decRef()
return
}
@@ -200,7 +199,6 @@ func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.Trans
}
if !ep.enqueueSegment(s) {
s.decRef()
return
}
+88 -3
View File
@@ -15,6 +15,7 @@
package tcp
import (
"container/heap"
"encoding/binary"
"fmt"
"io"
@@ -999,6 +1000,71 @@ func (e *endpoint) notifyProtocolGoroutine(n uint32) {
}
}
func (e *endpoint) Release() {
e.LockUser()
defer e.UnlockUser()
e.releaseLocked()
}
// +checklocks:e.mu
func (e *endpoint) releaseLocked() {
e.purgeReadQueue()
e.purgeWriteQueue()
for {
s := e.segmentQueue.dequeue()
if s == nil {
break
}
s.DecRef()
}
}
// Purging pending rcv segments is only necessary on RST.
func (e *endpoint) purgePendingRcvQueue() {
if e.rcv != nil {
for e.rcv.pendingRcvdSegments.Len() > 0 {
s := heap.Pop(&e.rcv.pendingRcvdSegments).(*segment)
s.DecRef()
}
}
}
// +checklocks:e.mu
func (e *endpoint) purgeReadQueue() {
if e.rcv != nil {
e.rcvQueueInfo.rcvQueueMu.Lock()
defer e.rcvQueueInfo.rcvQueueMu.Unlock()
for {
s := e.rcvQueueInfo.rcvQueue.Front()
if s == nil {
break
}
e.rcvQueueInfo.rcvQueue.Remove(s)
s.DecRef()
}
e.rcvQueueInfo.RcvBufUsed = 0
}
}
// +checklocks:e.mu
func (e *endpoint) purgeWriteQueue() {
if e.snd != nil {
e.sndQueueInfo.sndQueueMu.Lock()
defer e.sndQueueInfo.sndQueueMu.Unlock()
e.snd.updateWriteNext(nil)
for {
s := e.snd.writeList.Front()
if s == nil {
break
}
e.snd.writeList.Remove(s)
s.DecRef()
}
e.sndQueueInfo.SndBufUsed = 0
e.sndQueueInfo.SndClosed = true
}
}
// Abort implements stack.TransportEndpoint.Abort.
func (e *endpoint) Abort() {
// The abort notification is not processed synchronously, so no
@@ -1041,6 +1107,9 @@ func (e *endpoint) Close() {
return
}
// We always want to purge the read queue, but do so after the checks in
// shutdownLocked.
defer e.purgeReadQueue()
linger := e.SocketOptions().GetLinger()
if linger.Enabled && linger.Timeout == 0 {
s := e.EndpointState()
@@ -1066,6 +1135,10 @@ func (e *endpoint) Close() {
// if we're connected, or stop accepting if we're listening.
e.shutdownLocked(tcpip.ShutdownWrite | tcpip.ShutdownRead)
e.closeNoShutdownLocked()
switch e.EndpointState() {
case StateClose, StateError:
e.releaseLocked()
}
}
// closeNoShutdown closes the endpoint without doing a full shutdown.
@@ -1187,6 +1260,8 @@ func (e *endpoint) cleanupLocked() {
e.route = nil
}
// It's not safe to purge the read queues yet, there could be unread data.
e.purgeWriteQueue()
e.stack.CompleteTransportEndpointCleanup(e)
tcpip.DeleteDanglingEndpoint(e)
}
@@ -1470,10 +1545,16 @@ func (e *endpoint) commitRead(done int) *segment {
// Memory is only considered released when the whole segment has been
// read.
memDelta += s.segMemSize()
s.decRef()
s.DecRef()
s = e.rcvQueueInfo.rcvQueue.Front()
}
e.rcvQueueInfo.RcvBufUsed -= done
// Concurrent calls to Close() and Read() could cause RcvBufUsed to be
// negative because Read() unlocks between startRead() and commitRead(). In
// this case the read is allowed, but we refrain from subtracting from
// RcvBufUsed since it should already be zero.
if e.rcvQueueInfo.RcvBufUsed != 0 {
e.rcvQueueInfo.RcvBufUsed -= done
}
if memDelta > 0 {
// If the window was small before this read and if the read freed up
@@ -1599,6 +1680,7 @@ func (e *endpoint) queueSegment(p tcpip.Payloader, opts tcpip.WriteOptions) (*se
// Add data to the send queue.
s := newOutgoingSegment(e.TransportEndpointInfo.ID, e.stack.Clock(), v)
e.sndQueueInfo.SndBufUsed += len(v)
s.IncRef()
e.snd.writeList.PushBack(s)
return s, len(v), nil
@@ -1616,6 +1698,9 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp
// Return if either we didn't queue anything or if an error occurred while
// attempting to queue data.
nextSeg, n, err := e.queueSegment(p, opts)
if nextSeg != nil {
defer nextSeg.DecRef()
}
if n == 0 || err != nil {
return 0, err
}
@@ -2892,7 +2977,7 @@ func (e *endpoint) readyToRead(s *segment) {
e.rcvQueueInfo.rcvQueueMu.Lock()
if s != nil {
e.rcvQueueInfo.RcvBufUsed += s.payloadSize()
s.incRef()
s.IncRef()
e.rcvQueueInfo.rcvQueue.PushBack(s)
} else {
e.rcvQueueInfo.RcvClosed = true
+3 -3
View File
@@ -66,7 +66,7 @@ func NewForwarder(s *stack.Stack, rcvWnd, maxInFlight int, handler func(*Forward
// stack.SetTransportProtocolHandler function.
func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
s := newIncomingSegment(id, f.stack.Clock(), pkt)
defer s.decRef()
defer s.DecRef()
// We only care about well-formed SYN packets (not SYN-ACK) packets.
if !s.parse(pkt.RXTransportChecksumValidated) || !s.csumValid || !s.flags.Contains(header.TCPFlagSyn) || s.flags.Contains(header.TCPFlagAck) {
@@ -90,7 +90,7 @@ func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Packet
// Launch a new goroutine to handle the request.
f.inFlight[id] = struct{}{}
s.incRef()
s.IncRef()
go f.handler(&ForwarderRequest{ // S/R-SAFE: not used by Sentry.
forwarder: f,
segment: s,
@@ -136,7 +136,7 @@ func (r *ForwarderRequest) Complete(sendReset bool) {
}
// Release all resources.
r.segment.decRef()
r.segment.DecRef()
r.segment = nil
r.forwarder = nil
}
+1 -1
View File
@@ -158,7 +158,7 @@ func (p *protocol) QueuePacket(ep stack.TransportEndpoint, id stack.TransportEnd
// means."
func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition {
s := newIncomingSegment(id, p.stack.Clock(), pkt)
defer s.decRef()
defer s.DecRef()
if !s.parse(pkt.RXTransportChecksumValidated) || !s.csumValid {
return stack.UnknownDestinationPacketMalformed
+1 -1
View File
@@ -197,7 +197,7 @@ func (s *sender) probeTimerExpired() tcpip.Error {
dataSent = s.maybeSendSegment(s.writeNext, int(s.ep.scoreboard.SMSS()), s.SndUna.Add(s.SndWnd))
if dataSent {
s.Outstanding += s.pCount(s.writeNext, s.MaxPayloadSize)
s.writeNext = s.writeNext.Next()
s.updateWriteNext(s.writeNext.Next())
}
}
+3 -4
View File
@@ -286,8 +286,7 @@ func (r *receiver) consumeSegment(s *segment, segSeq seqnum.Value, segLen seqnum
for i := first; i < len(r.pendingRcvdSegments); i++ {
r.PendingBufUsed -= r.pendingRcvdSegments[i].segMemSize()
r.pendingRcvdSegments[i].decRef()
r.pendingRcvdSegments[i].DecRef()
// Note that slice truncation does not allow garbage collection of
// truncated items, thus truncated items must be set to nil to avoid
// memory leaks.
@@ -490,7 +489,7 @@ func (r *receiver) handleRcvdSegment(s *segment) (drop bool, err tcpip.Error) {
r.ep.rcvQueueInfo.rcvQueueMu.Lock()
r.PendingBufUsed += s.segMemSize()
r.ep.rcvQueueInfo.rcvQueueMu.Unlock()
s.incRef()
s.IncRef()
heap.Push(&r.pendingRcvdSegments, s)
UpdateSACKBlocks(&r.ep.sack, segSeq, segSeq.Add(segLen), r.RcvNxt)
}
@@ -526,7 +525,7 @@ func (r *receiver) handleRcvdSegment(s *segment) (drop bool, err tcpip.Error) {
r.ep.rcvQueueInfo.rcvQueueMu.Lock()
r.PendingBufUsed -= s.segMemSize()
r.ep.rcvQueueInfo.rcvQueueMu.Unlock()
s.decRef()
s.DecRef()
}
return false, nil
}
+1 -1
View File
@@ -69,7 +69,7 @@ func (sr *sackRecovery) handleSACKRecovery(limit int, end seqnum.Value) (dataSen
}
dataSent = true
snd.Outstanding++
snd.writeNext = nextSeg.Next()
snd.updateWriteNext(nextSeg.Next())
continue
}
+9 -13
View File
@@ -16,7 +16,6 @@ package tcp
import (
"fmt"
"sync/atomic"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -41,7 +40,8 @@ const (
// +stateify savable
type segment struct {
segmentEntry
refCnt int32
segmentRefs
ep *endpoint
qFlags queueFlags
id stack.TransportEndpointID `state:"manual"`
@@ -90,13 +90,13 @@ type segment struct {
func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) *segment {
netHdr := pkt.Network()
s := &segment{
refCnt: 1,
id: id,
srcAddr: netHdr.SourceAddress(),
dstAddr: netHdr.DestinationAddress(),
netProto: pkt.NetworkProtocolNumber,
nicID: pkt.NICID,
}
s.InitRefs()
s.data = pkt.Data().ExtractVV().Clone(s.views[:])
s.hdr = header.TCP(pkt.TransportHeader().View())
s.rcvdTime = clock.NowMonotonic()
@@ -106,9 +106,9 @@ func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *st
func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, v buffer.View) *segment {
s := &segment{
refCnt: 1,
id: id,
id: id,
}
s.InitRefs()
s.rcvdTime = clock.NowMonotonic()
if len(v) != 0 {
s.views[0] = v
@@ -120,7 +120,6 @@ func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, v buffe
func (s *segment) clone() *segment {
t := &segment{
refCnt: 1,
id: s.id,
sequenceNumber: s.sequenceNumber,
ackNumber: s.ackNumber,
@@ -135,6 +134,7 @@ func (s *segment) clone() *segment {
qFlags: s.qFlags,
dataMemSize: s.dataMemSize,
}
t.InitRefs()
t.data = s.data.Clone(t.views[:])
return t
}
@@ -164,8 +164,8 @@ func (s *segment) setOwner(ep *endpoint, qFlags queueFlags) {
s.qFlags = qFlags
}
func (s *segment) decRef() {
if atomic.AddInt32(&s.refCnt, -1) == 0 {
func (s *segment) DecRef() {
s.segmentRefs.DecRef(func() {
if s.ep != nil {
switch s.qFlags {
case recvQ:
@@ -176,11 +176,7 @@ func (s *segment) decRef() {
panic(fmt.Sprintf("unexpected queue flag %b set for segment", s.qFlags))
}
}
}
}
func (s *segment) incRef() {
atomic.AddInt32(&s.refCnt, 1)
})
}
// logicalLen is the segment length in the sequence number space. It's defined
+1
View File
@@ -60,6 +60,7 @@ func (q *segmentQueue) enqueue(s *segment) bool {
allow := (used <= int(bufSz) || s.payloadSize() == 0) && !q.frozen
if allow {
s.IncRef()
q.list.PushBack(s)
// Set the owner now that the endpoint owns the segment.
s.setOwner(q.ep, recvQ)
+2 -2
View File
@@ -43,9 +43,9 @@ func TestSegmentMerge(t *testing.T) {
var clock faketime.NullClock
id := stack.TransportEndpointID{}
seg1 := newOutgoingSegment(id, &clock, buffer.NewView(10))
defer seg1.decRef()
defer seg1.DecRef()
seg2 := newOutgoingSegment(id, &clock, buffer.NewView(20))
defer seg2.decRef()
defer seg2.DecRef()
checkSegmentSize(t, "seg1", seg1, segmentSizeWants{
DataSize: 10,
+17 -7
View File
@@ -333,7 +333,7 @@ func (s *sender) updateMaxPayloadSize(mtu, count int) {
// Since we likely reduced the number of outstanding packets, we may be
// ready to send some more.
s.writeNext = nextSeg
s.updateWriteNext(nextSeg)
s.sendData()
}
@@ -545,7 +545,7 @@ func (s *sender) retransmitTimerExpired() bool {
// information as we lack more rigorous checks to validate if the SACK
// information is usable after an RTO.
s.ep.scoreboard.Reset()
s.writeNext = s.writeList.Front()
s.updateWriteNext(s.writeList.Front())
// RFC 1122 4.2.2.17: Start sending zero window probes when we still see a
// zero receive window after retransmission interval and we have data to
@@ -752,7 +752,7 @@ func (s *sender) maybeSendSegment(seg *segment, limit int, end seqnum.Value) (se
}
seg.merge(nSeg)
s.writeList.Remove(nSeg)
nSeg.decRef()
nSeg.DecRef()
}
if !nextTooBig && seg.data.Size() < available {
// Segment is not full.
@@ -972,7 +972,7 @@ func (s *sender) sendData() {
if s.isAssignedSequenceNumber(seg) && s.ep.SACKPermitted && s.ep.scoreboard.IsSACKED(seg.sackBlock()) {
// Move writeNext along so that we don't try and scan data that
// has already been SACKED.
s.writeNext = seg.Next()
s.updateWriteNext(seg.Next())
continue
}
if sent := s.maybeSendSegment(seg, limit, end); !sent {
@@ -980,7 +980,7 @@ func (s *sender) sendData() {
}
dataSent = true
s.Outstanding += s.pCount(seg, s.MaxPayloadSize)
s.writeNext = seg.Next()
s.updateWriteNext(seg.Next())
}
s.postXmit(dataSent, true /* shouldScheduleProbe */)
@@ -1526,7 +1526,7 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) {
}
if s.writeNext == seg {
s.writeNext = seg.Next()
s.updateWriteNext(seg.Next())
}
// Update the RACK fields if SACK is enabled.
@@ -1545,7 +1545,7 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) {
} else {
s.SackedOut -= s.pCount(seg, s.MaxPayloadSize)
}
seg.decRef()
seg.DecRef()
ackLeft -= datalen
}
@@ -1699,3 +1699,13 @@ func (s *sender) maybeSendOutOfWindowAck(seg *segment) {
s.sendAck()
}
}
func (s *sender) updateWriteNext(seg *segment) {
if s.writeNext != nil {
s.writeNext.DecRef()
}
if seg != nil {
seg.IncRef()
}
s.writeNext = seg
}

Some files were not shown because too many files have changed in this diff Show More