|
|
@@ -1,9 +1,7 @@
|
|
|
package kcp
|
|
|
|
|
|
import (
|
|
|
- "io"
|
|
|
"sync"
|
|
|
- "time"
|
|
|
|
|
|
"github.com/v2ray/v2ray-core/common/alloc"
|
|
|
)
|
|
|
@@ -58,101 +56,68 @@ func (this *ReceivingWindow) Advance() {
|
|
|
}
|
|
|
|
|
|
type ReceivingQueue struct {
|
|
|
- sync.Mutex
|
|
|
- closed bool
|
|
|
- cache *alloc.Buffer
|
|
|
- queue chan *alloc.Buffer
|
|
|
- timeout time.Time
|
|
|
+ start uint32
|
|
|
+ cap uint32
|
|
|
+ len uint32
|
|
|
+ data []*alloc.Buffer
|
|
|
}
|
|
|
|
|
|
func NewReceivingQueue(size uint32) *ReceivingQueue {
|
|
|
return &ReceivingQueue{
|
|
|
- queue: make(chan *alloc.Buffer, size),
|
|
|
+ cap: size,
|
|
|
+ data: make([]*alloc.Buffer, size),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (this *ReceivingQueue) Read(buf []byte) (int, error) {
|
|
|
- if this.closed {
|
|
|
- return 0, io.EOF
|
|
|
- }
|
|
|
+func (this *ReceivingQueue) IsEmpty() bool {
|
|
|
+ return this.len == 0
|
|
|
+}
|
|
|
|
|
|
- if this.cache.Len() > 0 {
|
|
|
- nBytes, err := this.cache.Read(buf)
|
|
|
- if this.cache.IsEmpty() {
|
|
|
- this.cache.Release()
|
|
|
- this.cache = nil
|
|
|
- }
|
|
|
- return nBytes, err
|
|
|
- }
|
|
|
+func (this *ReceivingQueue) IsFull() bool {
|
|
|
+ return this.len == this.cap
|
|
|
+}
|
|
|
|
|
|
- var totalBytes int
|
|
|
+func (this *ReceivingQueue) Read(buf []byte) int {
|
|
|
+ if this.IsEmpty() {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
|
|
|
-L:
|
|
|
- for totalBytes < len(buf) {
|
|
|
- timeToSleep := time.Millisecond
|
|
|
- select {
|
|
|
- case payload, open := <-this.queue:
|
|
|
- if !open {
|
|
|
- return totalBytes, io.EOF
|
|
|
- }
|
|
|
- nBytes, err := payload.Read(buf)
|
|
|
- totalBytes += nBytes
|
|
|
- if err != nil {
|
|
|
- return totalBytes, err
|
|
|
- }
|
|
|
- if !payload.IsEmpty() {
|
|
|
- this.cache = payload
|
|
|
- }
|
|
|
- buf = buf[nBytes:]
|
|
|
- case <-time.After(timeToSleep):
|
|
|
- if totalBytes > 0 {
|
|
|
- break L
|
|
|
+ totalBytes := 0
|
|
|
+ lenBuf := len(buf)
|
|
|
+ for !this.IsEmpty() && totalBytes < lenBuf {
|
|
|
+ payload := this.data[this.start]
|
|
|
+ nBytes, _ := payload.Read(buf)
|
|
|
+ buf = buf[nBytes:]
|
|
|
+ totalBytes += nBytes
|
|
|
+ if payload.IsEmpty() {
|
|
|
+ payload.Release()
|
|
|
+ this.data[this.start] = nil
|
|
|
+ this.start++
|
|
|
+ if this.start == this.cap {
|
|
|
+ this.start = 0
|
|
|
}
|
|
|
- if !this.timeout.IsZero() && this.timeout.Before(time.Now()) {
|
|
|
- return totalBytes, errTimeout
|
|
|
- }
|
|
|
- timeToSleep += 500 * time.Millisecond
|
|
|
- if timeToSleep > 5*time.Second {
|
|
|
- timeToSleep = 5 * time.Second
|
|
|
+ this.len--
|
|
|
+ if this.len == 0 {
|
|
|
+ this.start = 0
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return totalBytes, nil
|
|
|
+ return totalBytes
|
|
|
}
|
|
|
|
|
|
-func (this *ReceivingQueue) Put(payload *alloc.Buffer) bool {
|
|
|
- if this.closed {
|
|
|
- payload.Release()
|
|
|
- return false
|
|
|
- }
|
|
|
-
|
|
|
- select {
|
|
|
- case this.queue <- payload:
|
|
|
- return true
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func (this *ReceivingQueue) SetReadDeadline(t time.Time) error {
|
|
|
- this.timeout = t
|
|
|
- return nil
|
|
|
+func (this *ReceivingQueue) Put(payload *alloc.Buffer) {
|
|
|
+ this.data[(this.start+this.len)%this.cap] = payload
|
|
|
+ this.len++
|
|
|
}
|
|
|
|
|
|
func (this *ReceivingQueue) Close() {
|
|
|
- this.Lock()
|
|
|
- defer this.Unlock()
|
|
|
-
|
|
|
- if this.closed {
|
|
|
- return
|
|
|
+ for i := uint32(0); i < this.len; i++ {
|
|
|
+ this.data[(this.start+i)%this.cap].Release()
|
|
|
+ this.data[(this.start+i)%this.cap] = nil
|
|
|
}
|
|
|
- this.closed = true
|
|
|
- close(this.queue)
|
|
|
}
|
|
|
|
|
|
type AckList struct {
|
|
|
- sync.Mutex
|
|
|
writer SegmentWriter
|
|
|
timestamps []uint32
|
|
|
numbers []uint32
|
|
|
@@ -169,18 +134,12 @@ func NewAckList(writer SegmentWriter) *AckList {
|
|
|
}
|
|
|
|
|
|
func (this *AckList) Add(number uint32, timestamp uint32) {
|
|
|
- this.Lock()
|
|
|
- defer this.Unlock()
|
|
|
-
|
|
|
this.timestamps = append(this.timestamps, timestamp)
|
|
|
this.numbers = append(this.numbers, number)
|
|
|
this.nextFlush = append(this.nextFlush, 0)
|
|
|
}
|
|
|
|
|
|
func (this *AckList) Clear(una uint32) {
|
|
|
- this.Lock()
|
|
|
- defer this.Unlock()
|
|
|
-
|
|
|
count := 0
|
|
|
for i := 0; i < len(this.numbers); i++ {
|
|
|
if this.numbers[i] >= una {
|
|
|
@@ -201,14 +160,12 @@ func (this *AckList) Clear(una uint32) {
|
|
|
|
|
|
func (this *AckList) Flush(current uint32, rto uint32) {
|
|
|
seg := NewAckSegment()
|
|
|
- this.Lock()
|
|
|
for i := 0; i < len(this.numbers) && !seg.IsFull(); i++ {
|
|
|
if this.nextFlush[i] <= current {
|
|
|
seg.PutNumber(this.numbers[i], this.timestamps[i])
|
|
|
this.nextFlush[i] = current + rto/2
|
|
|
}
|
|
|
}
|
|
|
- this.Unlock()
|
|
|
if seg.Count > 0 {
|
|
|
this.writer.Write(seg)
|
|
|
seg.Release()
|
|
|
@@ -216,14 +173,14 @@ func (this *AckList) Flush(current uint32, rto uint32) {
|
|
|
}
|
|
|
|
|
|
type ReceivingWorker struct {
|
|
|
- conn *Connection
|
|
|
- queue *ReceivingQueue
|
|
|
- window *ReceivingWindow
|
|
|
- windowMutex sync.Mutex
|
|
|
- acklist *AckList
|
|
|
- updated bool
|
|
|
- nextNumber uint32
|
|
|
- windowSize uint32
|
|
|
+ sync.Mutex
|
|
|
+ conn *Connection
|
|
|
+ queue *ReceivingQueue
|
|
|
+ window *ReceivingWindow
|
|
|
+ acklist *AckList
|
|
|
+ updated bool
|
|
|
+ nextNumber uint32
|
|
|
+ windowSize uint32
|
|
|
}
|
|
|
|
|
|
func NewReceivingWorker(kcp *Connection) *ReceivingWorker {
|
|
|
@@ -239,35 +196,35 @@ func NewReceivingWorker(kcp *Connection) *ReceivingWorker {
|
|
|
}
|
|
|
|
|
|
func (this *ReceivingWorker) ProcessSendingNext(number uint32) {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
+
|
|
|
this.acklist.Clear(number)
|
|
|
}
|
|
|
|
|
|
func (this *ReceivingWorker) ProcessSegment(seg *DataSegment) {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
+
|
|
|
number := seg.Number
|
|
|
idx := number - this.nextNumber
|
|
|
if idx >= this.windowSize {
|
|
|
return
|
|
|
}
|
|
|
- this.ProcessSendingNext(seg.SendingNext)
|
|
|
+ this.acklist.Clear(seg.SendingNext)
|
|
|
this.acklist.Add(number, seg.Timestamp)
|
|
|
- this.windowMutex.Lock()
|
|
|
- defer this.windowMutex.Unlock()
|
|
|
|
|
|
if !this.window.Set(idx, seg) {
|
|
|
seg.Release()
|
|
|
}
|
|
|
|
|
|
- for {
|
|
|
+ for !this.queue.IsFull() {
|
|
|
seg := this.window.RemoveFirst()
|
|
|
if seg == nil {
|
|
|
break
|
|
|
}
|
|
|
|
|
|
- if !this.queue.Put(seg.Data) {
|
|
|
- this.window.Set(0, seg)
|
|
|
- break
|
|
|
- }
|
|
|
-
|
|
|
+ this.queue.Put(seg.Data)
|
|
|
seg.Data = nil
|
|
|
seg.Release()
|
|
|
this.window.Advance()
|
|
|
@@ -276,15 +233,17 @@ func (this *ReceivingWorker) ProcessSegment(seg *DataSegment) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (this *ReceivingWorker) Read(b []byte) (int, error) {
|
|
|
- return this.queue.Read(b)
|
|
|
-}
|
|
|
+func (this *ReceivingWorker) Read(b []byte) int {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
|
|
|
-func (this *ReceivingWorker) SetReadDeadline(t time.Time) {
|
|
|
- this.queue.SetReadDeadline(t)
|
|
|
+ return this.queue.Read(b)
|
|
|
}
|
|
|
|
|
|
func (this *ReceivingWorker) Flush(current uint32) {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
+
|
|
|
this.acklist.Flush(current, this.conn.roundTrip.Timeout())
|
|
|
}
|
|
|
|
|
|
@@ -301,6 +260,9 @@ func (this *ReceivingWorker) Write(seg Segment) {
|
|
|
}
|
|
|
|
|
|
func (this *ReceivingWorker) CloseRead() {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
+
|
|
|
this.queue.Close()
|
|
|
}
|
|
|
|