mirror of https://github.com/v2ray/v2ray-core
implement WriteMultiBuffer
parent
be714f76f1
commit
b3e6994e52
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"v2ray.com/core/app/log"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/predicate"
|
||||
)
|
||||
|
@ -343,10 +344,15 @@ func (v *Connection) Write(b []byte) (int, error) {
|
|||
return totalWritten, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
nBytes := v.sendingWorker.Push(b[totalWritten:])
|
||||
v.dataUpdater.WakeUp()
|
||||
if nBytes > 0 {
|
||||
totalWritten += nBytes
|
||||
for {
|
||||
rb := v.sendingWorker.Push()
|
||||
if rb == nil {
|
||||
break
|
||||
}
|
||||
common.Must(rb.Reset(func(bb []byte) (int, error) {
|
||||
return copy(bb[:v.mss], b[totalWritten:]), nil
|
||||
}))
|
||||
totalWritten += rb.Len()
|
||||
if totalWritten == len(b) {
|
||||
return totalWritten, nil
|
||||
}
|
||||
|
@ -370,6 +376,45 @@ func (v *Connection) Write(b []byte) (int, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (v *Connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
defer mb.Release()
|
||||
|
||||
for {
|
||||
if v == nil || v.State() != StateActive {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
|
||||
for {
|
||||
rb := v.sendingWorker.Push()
|
||||
if rb == nil {
|
||||
break
|
||||
}
|
||||
common.Must(rb.Reset(func(bb []byte) (int, error) {
|
||||
return mb.Read(bb[:v.mss])
|
||||
}))
|
||||
if mb.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
duration := time.Minute
|
||||
if !v.wd.IsZero() {
|
||||
duration = time.Until(v.wd)
|
||||
if duration < 0 {
|
||||
return ErrIOTimeout
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-v.dataOutput:
|
||||
case <-time.After(duration):
|
||||
if !v.wd.IsZero() && v.wd.Before(time.Now()) {
|
||||
return ErrIOTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Connection) SetState(state State) {
|
||||
current := v.Elapsed()
|
||||
atomic.StoreInt32((*int32)(&v.state), int32(state))
|
||||
|
|
|
@ -214,8 +214,7 @@ func (w *ReceivingWorker) ReadMultiBuffer() buf.MultiBuffer {
|
|||
}
|
||||
w.window.Advance()
|
||||
w.nextNumber++
|
||||
mb.Append(seg.Data)
|
||||
seg.Data = nil
|
||||
mb.Append(seg.Detach())
|
||||
seg.Release()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package kcp
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/serial"
|
||||
)
|
||||
|
@ -44,8 +43,8 @@ type DataSegment struct {
|
|||
Timestamp uint32
|
||||
Number uint32
|
||||
SendingNext uint32
|
||||
Data *buf.Buffer
|
||||
|
||||
payload *buf.Buffer
|
||||
timeout uint32
|
||||
transmit uint32
|
||||
}
|
||||
|
@ -62,13 +61,17 @@ func (v *DataSegment) Command() Command {
|
|||
return CommandData
|
||||
}
|
||||
|
||||
func (v *DataSegment) SetData(data []byte) {
|
||||
if v.Data == nil {
|
||||
v.Data = buf.New()
|
||||
func (v *DataSegment) Detach() *buf.Buffer {
|
||||
r := v.payload
|
||||
v.payload = nil
|
||||
return r
|
||||
}
|
||||
|
||||
func (v *DataSegment) Data() *buf.Buffer {
|
||||
if v.payload == nil {
|
||||
v.payload = buf.New()
|
||||
}
|
||||
common.Must(v.Data.Reset(func(b []byte) (int, error) {
|
||||
return copy(b, data), nil
|
||||
}))
|
||||
return v.payload
|
||||
}
|
||||
|
||||
func (v *DataSegment) Bytes() buf.Supplier {
|
||||
|
@ -78,19 +81,19 @@ func (v *DataSegment) Bytes() buf.Supplier {
|
|||
b = serial.Uint32ToBytes(v.Timestamp, b)
|
||||
b = serial.Uint32ToBytes(v.Number, b)
|
||||
b = serial.Uint32ToBytes(v.SendingNext, b)
|
||||
b = serial.Uint16ToBytes(uint16(v.Data.Len()), b)
|
||||
b = append(b, v.Data.Bytes()...)
|
||||
b = serial.Uint16ToBytes(uint16(v.payload.Len()), b)
|
||||
b = append(b, v.payload.Bytes()...)
|
||||
return len(b), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (v *DataSegment) ByteSize() int {
|
||||
return 2 + 1 + 1 + 4 + 4 + 4 + 2 + v.Data.Len()
|
||||
return 2 + 1 + 1 + 4 + 4 + 4 + 2 + v.payload.Len()
|
||||
}
|
||||
|
||||
func (v *DataSegment) Release() {
|
||||
v.Data.Release()
|
||||
v.Data = nil
|
||||
v.payload.Release()
|
||||
v.payload = nil
|
||||
}
|
||||
|
||||
type AckSegment struct {
|
||||
|
@ -233,7 +236,8 @@ func ReadSegment(buf []byte) (Segment, []byte) {
|
|||
if len(buf) < dataLen {
|
||||
return nil, nil
|
||||
}
|
||||
seg.SetData(buf[:dataLen])
|
||||
seg.Data().Clear()
|
||||
seg.Data().Append(buf[:dataLen])
|
||||
buf = buf[dataLen:]
|
||||
|
||||
return seg, buf
|
||||
|
|
|
@ -3,7 +3,6 @@ package kcp_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"v2ray.com/core/common/buf"
|
||||
. "v2ray.com/core/transport/internet/kcp"
|
||||
. "v2ray.com/ext/assert"
|
||||
)
|
||||
|
@ -19,15 +18,13 @@ func TestBadSegment(t *testing.T) {
|
|||
func TestDataSegment(t *testing.T) {
|
||||
assert := With(t)
|
||||
|
||||
b := buf.NewLocal(512)
|
||||
b.Append([]byte{'a', 'b', 'c', 'd'})
|
||||
seg := &DataSegment{
|
||||
Conv: 1,
|
||||
Timestamp: 3,
|
||||
Number: 4,
|
||||
SendingNext: 5,
|
||||
Data: b,
|
||||
}
|
||||
seg.Data().Append([]byte{'a', 'b', 'c', 'd'})
|
||||
|
||||
nBytes := seg.ByteSize()
|
||||
bytes := make([]byte, nBytes)
|
||||
|
@ -41,21 +38,19 @@ func TestDataSegment(t *testing.T) {
|
|||
assert(seg2.Timestamp, Equals, seg.Timestamp)
|
||||
assert(seg2.SendingNext, Equals, seg.SendingNext)
|
||||
assert(seg2.Number, Equals, seg.Number)
|
||||
assert(seg2.Data.Bytes(), Equals, seg.Data.Bytes())
|
||||
assert(seg2.Data().Bytes(), Equals, seg.Data().Bytes())
|
||||
}
|
||||
|
||||
func Test1ByteDataSegment(t *testing.T) {
|
||||
assert := With(t)
|
||||
|
||||
b := buf.NewLocal(512)
|
||||
b.AppendBytes('a')
|
||||
seg := &DataSegment{
|
||||
Conv: 1,
|
||||
Timestamp: 3,
|
||||
Number: 4,
|
||||
SendingNext: 5,
|
||||
Data: b,
|
||||
}
|
||||
seg.Data().AppendBytes('a')
|
||||
|
||||
nBytes := seg.ByteSize()
|
||||
bytes := make([]byte, nBytes)
|
||||
|
@ -69,7 +64,7 @@ func Test1ByteDataSegment(t *testing.T) {
|
|||
assert(seg2.Timestamp, Equals, seg.Timestamp)
|
||||
assert(seg2.SendingNext, Equals, seg.SendingNext)
|
||||
assert(seg2.Number, Equals, seg.Number)
|
||||
assert(seg2.Data.Bytes(), Equals, seg.Data.Bytes())
|
||||
assert(seg2.Data().Bytes(), Equals, seg.Data().Bytes())
|
||||
}
|
||||
|
||||
func TestACKSegment(t *testing.T) {
|
||||
|
|
|
@ -2,6 +2,8 @@ package kcp
|
|||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"v2ray.com/core/common/buf"
|
||||
)
|
||||
|
||||
type SendingWindow struct {
|
||||
|
@ -62,9 +64,8 @@ func (sw *SendingWindow) IsFull() bool {
|
|||
return sw.len == sw.cap
|
||||
}
|
||||
|
||||
func (sw *SendingWindow) Push(number uint32, data []byte) {
|
||||
func (sw *SendingWindow) Push(number uint32) *buf.Buffer {
|
||||
pos := (sw.start + sw.len) % sw.cap
|
||||
sw.data[pos].SetData(data)
|
||||
sw.data[pos].Number = number
|
||||
sw.data[pos].timeout = 0
|
||||
sw.data[pos].transmit = 0
|
||||
|
@ -75,6 +76,7 @@ func (sw *SendingWindow) Push(number uint32, data []byte) {
|
|||
}
|
||||
sw.last = pos
|
||||
sw.len++
|
||||
return sw.data[pos].Data()
|
||||
}
|
||||
|
||||
func (sw *SendingWindow) FirstNumber() uint32 {
|
||||
|
@ -224,7 +226,6 @@ func (v *SendingWorker) ProcessReceivingNextWithoutLock(nextNumber uint32) {
|
|||
v.FindFirstUnacknowledged()
|
||||
}
|
||||
|
||||
// Private: Visible for testing.
|
||||
func (v *SendingWorker) FindFirstUnacknowledged() {
|
||||
first := v.firstUnacknowledged
|
||||
if !v.window.IsEmpty() {
|
||||
|
@ -283,24 +284,16 @@ func (v *SendingWorker) ProcessSegment(current uint32, seg *AckSegment, rto uint
|
|||
}
|
||||
}
|
||||
|
||||
func (v *SendingWorker) Push(b []byte) int {
|
||||
nBytes := 0
|
||||
func (v *SendingWorker) Push() *buf.Buffer {
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
|
||||
for len(b) > 0 && !v.window.IsFull() {
|
||||
var size int
|
||||
if len(b) > int(v.conn.mss) {
|
||||
size = int(v.conn.mss)
|
||||
} else {
|
||||
size = len(b)
|
||||
}
|
||||
v.window.Push(v.nextNumber, b[:size])
|
||||
if !v.window.IsFull() {
|
||||
b := v.window.Push(v.nextNumber)
|
||||
v.nextNumber++
|
||||
b = b[size:]
|
||||
nBytes += size
|
||||
return b
|
||||
}
|
||||
return nBytes
|
||||
return nil
|
||||
}
|
||||
|
||||
// Private: Visible for testing.
|
||||
|
|
|
@ -11,9 +11,9 @@ func TestSendingWindow(t *testing.T) {
|
|||
assert := With(t)
|
||||
|
||||
window := NewSendingWindow(5, nil, nil)
|
||||
window.Push(0, []byte{})
|
||||
window.Push(1, []byte{})
|
||||
window.Push(2, []byte{})
|
||||
window.Push(0)
|
||||
window.Push(1)
|
||||
window.Push(2)
|
||||
assert(window.Len(), Equals, 3)
|
||||
|
||||
window.Remove(1)
|
||||
|
@ -27,11 +27,11 @@ func TestSendingWindow(t *testing.T) {
|
|||
window.Remove(0)
|
||||
assert(window.Len(), Equals, 0)
|
||||
|
||||
window.Push(4, []byte{})
|
||||
window.Push(4)
|
||||
assert(window.Len(), Equals, 1)
|
||||
assert(window.FirstNumber(), Equals, uint32(4))
|
||||
|
||||
window.Push(5, []byte{})
|
||||
window.Push(5)
|
||||
assert(window.Len(), Equals, 2)
|
||||
|
||||
window.Remove(1)
|
||||
|
|
Loading…
Reference in New Issue