github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/core/dst/sendbuffer.go (about)

     1  // Copyright 2014 The DST Authors. All rights reserved.
     2  // Use of this source code is governed by an MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package dst
     6  
     7  import (
     8  	"fmt"
     9  	"runtime/debug"
    10  
    11  	"sync"
    12  
    13  	"github.com/juju/ratelimit"
    14  )
    15  
    16  /*
    17  	                          sendWindow
    18  	                         v
    19  		[S|S|S|S|Q|Q|Q|Q| | | | | | | | | ]
    20  		         ^       ^writeSlot
    21  		          sendSlot
    22  */
    23  type sendBuffer struct {
    24  	mux       *Mux              // we send packets here
    25  	scheduler *ratelimit.Bucket // sets send rate for packets
    26  
    27  	sendWindow int // maximum number of outstanding non-acked packets
    28  	packetRate int // target pps
    29  
    30  	send     packetList // buffered packets
    31  	sendSlot int        // buffer slot from which to send next packet
    32  
    33  	lost     packetList // list of packets reported lost by timeout
    34  	lostSlot int        // next lost packet to resend
    35  
    36  	closed  bool
    37  	closing bool
    38  	mut     sync.Mutex
    39  	cond    *sync.Cond
    40  }
    41  
    42  const (
    43  	schedulerRate     = 1e6
    44  	schedulerCapacity = schedulerRate / 40
    45  )
    46  
    47  // newSendBuffer creates a new send buffer with a zero window.
    48  // SetRateAndWindow() must be called to set an initial packet rate and send
    49  // window before using.
    50  func newSendBuffer(m *Mux) *sendBuffer {
    51  	b := &sendBuffer{
    52  		mux:       m,
    53  		scheduler: ratelimit.NewBucketWithRate(schedulerRate, schedulerCapacity),
    54  	}
    55  	b.cond = sync.NewCond(&b.mut)
    56  	go func() {
    57  		defer func() {
    58  			if e := recover(); e != nil {
    59  				fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
    60  			}
    61  		}()
    62  		b.writerLoop()
    63  	}()
    64  	return b
    65  }
    66  
    67  // Write puts a new packet in send buffer and schedules a send. Blocks when
    68  // the window size is or would be exceeded.
    69  func (b *sendBuffer) Write(pkt packet) error {
    70  	b.mut.Lock()
    71  	defer b.mut.Unlock()
    72  
    73  	for b.send.Full() || b.send.Len() >= b.sendWindow {
    74  		if b.closing {
    75  			return ErrClosedConn
    76  		}
    77  		if debugConnection {
    78  			log.Println(b, "Write blocked")
    79  		}
    80  		b.cond.Wait()
    81  	}
    82  	if !b.send.Append(pkt) {
    83  		panic("bug: append failed")
    84  	}
    85  	b.cond.Broadcast()
    86  	return nil
    87  }
    88  
    89  // Acknowledge removes packets with lower sequence numbers from the loss list
    90  // or send buffer.
    91  func (b *sendBuffer) Acknowledge(seq sequenceNo) {
    92  	b.mut.Lock()
    93  
    94  	if cut := b.lost.CutLessSeq(seq); cut > 0 {
    95  		if debugConnection {
    96  			log.Println(b, "cut", cut, "from loss list")
    97  		}
    98  		// Next resend should always start with the first packet, regardless
    99  		// of what we might already have resent previously.
   100  		b.lostSlot = 0
   101  		b.cond.Broadcast()
   102  	}
   103  
   104  	if cut := b.send.CutLessSeq(seq); cut > 0 {
   105  		if debugConnection {
   106  			log.Println(b, "cut", cut, "from send list")
   107  		}
   108  		b.sendSlot -= cut
   109  		b.cond.Broadcast()
   110  	}
   111  
   112  	b.mut.Unlock()
   113  }
   114  
   115  func (b *sendBuffer) NegativeAck(seq sequenceNo) {
   116  	b.mut.Lock()
   117  
   118  	pkts := b.send.PopSequence(seq)
   119  	if cut := len(pkts); cut > 0 {
   120  		b.lost.AppendAll(pkts)
   121  		if debugConnection {
   122  			log.Println(b, "cut", cut, "from send list, adding to loss list")
   123  			log.Println(seq, pkts)
   124  		}
   125  		b.sendSlot -= cut
   126  		b.lostSlot = 0
   127  		b.cond.Broadcast()
   128  	}
   129  
   130  	b.mut.Unlock()
   131  }
   132  
   133  // ScheduleResend arranges for a resend of all currently unacknowledged
   134  // packets.
   135  func (b *sendBuffer) ScheduleResend() {
   136  	b.mut.Lock()
   137  
   138  	if b.sendSlot > 0 {
   139  		// There are packets that have been sent but not acked. Move them from
   140  		// the send buffer to the loss list for retransmission.
   141  		if debugConnection {
   142  			log.Println(b, "scheduled resend from send list", b.sendSlot)
   143  		}
   144  
   145  		// Append the packets to the loss list and rewind the send buffer
   146  		b.lost.AppendAll(b.send.All()[:b.sendSlot])
   147  		b.send.Cut(b.sendSlot)
   148  		b.sendSlot = 0
   149  		b.cond.Broadcast()
   150  	}
   151  
   152  	if b.lostSlot > 0 {
   153  		// Also resend whatever was already in the loss list
   154  		if debugConnection {
   155  			log.Println(b, "scheduled resend from loss list", b.lostSlot)
   156  		}
   157  		b.lostSlot = 0
   158  		b.cond.Broadcast()
   159  	}
   160  
   161  	b.mut.Unlock()
   162  }
   163  
   164  // SetWindowAndRate sets the window size (in packets) and packet rate (in
   165  // packets per second) to use when sending.
   166  func (b *sendBuffer) SetWindowAndRate(sendWindow, packetRate int) {
   167  	b.mut.Lock()
   168  	if debugConnection {
   169  		log.Println(b, "new window & rate", sendWindow, packetRate)
   170  	}
   171  	b.packetRate = packetRate
   172  	b.sendWindow = sendWindow
   173  	if b.sendWindow > b.send.Cap() {
   174  		b.send.Resize(b.sendWindow)
   175  		b.cond.Broadcast()
   176  	}
   177  	b.mut.Unlock()
   178  }
   179  
   180  // Stop stops the send buffer from any doing further sending, but waits for
   181  // the current buffers to be drained.
   182  func (b *sendBuffer) Stop() {
   183  	b.mut.Lock()
   184  
   185  	if b.closed || b.closing {
   186  		return
   187  	}
   188  
   189  	b.closing = true
   190  	for b.lost.Len() > 0 || b.send.Len() > 0 {
   191  		b.cond.Wait()
   192  	}
   193  
   194  	b.closed = true
   195  	b.cond.Broadcast()
   196  	b.mut.Unlock()
   197  }
   198  
   199  // CrashStop stops the send buffer from any doing further sending, without
   200  // waiting for buffers to drain.
   201  func (b *sendBuffer) CrashStop() {
   202  	b.mut.Lock()
   203  
   204  	if b.closed || b.closing {
   205  		return
   206  	}
   207  
   208  	b.closing = true
   209  	b.closed = true
   210  	b.cond.Broadcast()
   211  	b.mut.Unlock()
   212  }
   213  
   214  func (b *sendBuffer) String() string {
   215  	return fmt.Sprintf("sendBuffer@%p", b)
   216  }
   217  
   218  func (b *sendBuffer) writerLoop() {
   219  	if debugConnection {
   220  		log.Println(b, "writer() starting")
   221  		defer log.Println(b, "writer() exiting")
   222  	}
   223  
   224  	b.scheduler.Take(schedulerCapacity)
   225  	for {
   226  		var pkt packet
   227  		b.mut.Lock()
   228  		for b.lostSlot >= b.sendWindow ||
   229  			(b.sendSlot == b.send.Len() && b.lostSlot == b.lost.Len()) {
   230  			if b.closed {
   231  				b.mut.Unlock()
   232  				return
   233  			}
   234  
   235  			if debugConnection {
   236  				log.Println(b, "writer() paused", b.lostSlot, b.sendSlot, b.sendWindow, b.lost.Len())
   237  			}
   238  			b.cond.Wait()
   239  		}
   240  
   241  		if b.lostSlot < b.lost.Len() {
   242  			pkt = b.lost.All()[b.lostSlot]
   243  			pkt.hdr.timestamp = timestampMicros()
   244  			b.lostSlot++
   245  
   246  			if debugConnection {
   247  				log.Println(b, "resend", b.lostSlot, b.lost.Len(), b.sendWindow, pkt.hdr.connID, pkt.hdr.sequenceNo)
   248  			}
   249  		} else if b.sendSlot < b.send.Len() {
   250  			pkt = b.send.All()[b.sendSlot]
   251  			pkt.hdr.timestamp = timestampMicros()
   252  			b.sendSlot++
   253  
   254  			if debugConnection {
   255  				log.Println(b, "send", b.sendSlot, b.send.Len(), b.sendWindow, pkt.hdr.connID, pkt.hdr.sequenceNo)
   256  			}
   257  		}
   258  
   259  		b.cond.Broadcast()
   260  		packetRate := b.packetRate
   261  		b.mut.Unlock()
   262  
   263  		if pkt.dst != nil {
   264  			b.scheduler.Wait(schedulerRate / int64(packetRate))
   265  			b.mux.write(pkt)
   266  		}
   267  	}
   268  }