|
|
@@ -6,7 +6,6 @@
|
|
|
package kcp
|
|
|
|
|
|
import (
|
|
|
- "github.com/v2ray/v2ray-core/common/alloc"
|
|
|
"github.com/v2ray/v2ray-core/common/log"
|
|
|
)
|
|
|
|
|
|
@@ -35,14 +34,11 @@ type KCP struct {
|
|
|
lastPingTime uint32
|
|
|
|
|
|
mss uint32
|
|
|
- snd_una, snd_nxt uint32
|
|
|
rx_rttvar, rx_srtt, rx_rto uint32
|
|
|
- snd_wnd, rmt_wnd, cwnd uint32
|
|
|
current, interval uint32
|
|
|
|
|
|
- snd_queue *SendingQueue
|
|
|
- snd_buf *SendingWindow
|
|
|
receivingWorker *ReceivingWorker
|
|
|
+ sendingWorker *SendingWorker
|
|
|
|
|
|
fastresend uint32
|
|
|
congestionControl bool
|
|
|
@@ -55,18 +51,14 @@ func NewKCP(conv uint16, output *AuthenticationWriter) *KCP {
|
|
|
log.Debug("KCP|Core: creating KCP ", conv)
|
|
|
kcp := new(KCP)
|
|
|
kcp.conv = conv
|
|
|
- kcp.snd_wnd = effectiveConfig.GetSendingWindowSize()
|
|
|
- kcp.rmt_wnd = 32
|
|
|
kcp.mss = output.Mtu() - DataSegmentOverhead
|
|
|
kcp.rx_rto = 100
|
|
|
kcp.interval = effectiveConfig.Tti
|
|
|
kcp.output = NewSegmentWriter(output)
|
|
|
- kcp.snd_queue = NewSendingQueue(effectiveConfig.GetSendingQueueSize())
|
|
|
- kcp.snd_buf = NewSendingWindow(kcp, effectiveConfig.GetSendingWindowSize())
|
|
|
- kcp.cwnd = kcp.snd_wnd
|
|
|
kcp.receivingWorker = NewReceivingWorker(kcp)
|
|
|
kcp.fastresend = 2
|
|
|
kcp.congestionControl = effectiveConfig.Congestion
|
|
|
+ kcp.sendingWorker = NewSendingWorker(kcp)
|
|
|
return kcp
|
|
|
}
|
|
|
|
|
|
@@ -78,11 +70,13 @@ func (kcp *KCP) SetState(state State) {
|
|
|
case StateReadyToClose:
|
|
|
kcp.receivingWorker.CloseRead()
|
|
|
case StatePeerClosed:
|
|
|
- kcp.ClearSendQueue()
|
|
|
+ kcp.sendingWorker.CloseWrite()
|
|
|
case StateTerminating:
|
|
|
kcp.receivingWorker.CloseRead()
|
|
|
+ kcp.sendingWorker.CloseWrite()
|
|
|
case StateTerminated:
|
|
|
kcp.receivingWorker.CloseRead()
|
|
|
+ kcp.sendingWorker.CloseWrite()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -110,26 +104,6 @@ func (kcp *KCP) OnClose() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Send is user/upper level send, returns below zero for error
|
|
|
-func (kcp *KCP) Send(buffer []byte) int {
|
|
|
- nBytes := 0
|
|
|
- for len(buffer) > 0 && !kcp.snd_queue.IsFull() {
|
|
|
- var size int
|
|
|
- if len(buffer) > int(kcp.mss) {
|
|
|
- size = int(kcp.mss)
|
|
|
- } else {
|
|
|
- size = len(buffer)
|
|
|
- }
|
|
|
- seg := &DataSegment{
|
|
|
- Data: alloc.NewSmallBuffer().Clear().Append(buffer[:size]),
|
|
|
- }
|
|
|
- kcp.snd_queue.Push(seg)
|
|
|
- buffer = buffer[size:]
|
|
|
- nBytes += size
|
|
|
- }
|
|
|
- return nBytes
|
|
|
-}
|
|
|
-
|
|
|
// https://tools.ietf.org/html/rfc6298
|
|
|
func (kcp *KCP) update_ack(rtt int32) {
|
|
|
if kcp.rx_srtt == 0 {
|
|
|
@@ -159,46 +133,11 @@ func (kcp *KCP) update_ack(rtt int32) {
|
|
|
kcp.rx_rto = rto * 3 / 2
|
|
|
}
|
|
|
|
|
|
-func (kcp *KCP) shrink_buf() {
|
|
|
- prevUna := kcp.snd_una
|
|
|
- if kcp.snd_buf.Len() > 0 {
|
|
|
- seg := kcp.snd_buf.First()
|
|
|
- kcp.snd_una = seg.Number
|
|
|
- } else {
|
|
|
- kcp.snd_una = kcp.snd_nxt
|
|
|
- }
|
|
|
- if kcp.snd_una != prevUna {
|
|
|
- kcp.sendingUpdated = true
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func (kcp *KCP) parse_ack(sn uint32) {
|
|
|
- if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- kcp.snd_buf.Remove(sn - kcp.snd_una)
|
|
|
-}
|
|
|
-
|
|
|
-func (kcp *KCP) parse_fastack(sn uint32) {
|
|
|
- if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- kcp.snd_buf.HandleFastAck(sn)
|
|
|
-}
|
|
|
-
|
|
|
-func (kcp *KCP) HandleReceivingNext(receivingNext uint32) {
|
|
|
- kcp.snd_buf.Clear(receivingNext)
|
|
|
-}
|
|
|
-
|
|
|
// Input when you received a low level packet (eg. UDP packet), call it
|
|
|
func (kcp *KCP) Input(data []byte) int {
|
|
|
kcp.lastIncomingTime = kcp.current
|
|
|
|
|
|
var seg ISegment
|
|
|
- var maxack uint32
|
|
|
- var flag int
|
|
|
for {
|
|
|
seg, data = ReadSegment(data)
|
|
|
if seg == nil {
|
|
|
@@ -212,26 +151,7 @@ func (kcp *KCP) Input(data []byte) int {
|
|
|
kcp.lastPayloadTime = kcp.current
|
|
|
case *AckSegment:
|
|
|
kcp.HandleOption(seg.Opt)
|
|
|
- if kcp.rmt_wnd < seg.ReceivingWindow {
|
|
|
- kcp.rmt_wnd = seg.ReceivingWindow
|
|
|
- }
|
|
|
- kcp.HandleReceivingNext(seg.ReceivingNext)
|
|
|
- kcp.shrink_buf()
|
|
|
- for i := 0; i < int(seg.Count); i++ {
|
|
|
- ts := seg.TimestampList[i]
|
|
|
- sn := seg.NumberList[i]
|
|
|
- if _itimediff(kcp.current, ts) >= 0 {
|
|
|
- kcp.update_ack(_itimediff(kcp.current, ts))
|
|
|
- }
|
|
|
- kcp.parse_ack(sn)
|
|
|
- kcp.shrink_buf()
|
|
|
- if flag == 0 {
|
|
|
- flag = 1
|
|
|
- maxack = sn
|
|
|
- } else if _itimediff(sn, maxack) > 0 {
|
|
|
- maxack = sn
|
|
|
- }
|
|
|
- }
|
|
|
+ kcp.sendingWorker.ProcessAckSegment(seg)
|
|
|
kcp.lastPayloadTime = kcp.current
|
|
|
case *CmdOnlySegment:
|
|
|
kcp.HandleOption(seg.Opt)
|
|
|
@@ -244,17 +164,12 @@ func (kcp *KCP) Input(data []byte) int {
|
|
|
kcp.SetState(StateTerminated)
|
|
|
}
|
|
|
}
|
|
|
- kcp.HandleReceivingNext(seg.ReceivinNext)
|
|
|
+ kcp.sendingWorker.ProcessReceivingNext(seg.ReceivinNext)
|
|
|
kcp.receivingWorker.ProcessSendingNext(seg.SendingNext)
|
|
|
- kcp.shrink_buf()
|
|
|
default:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if flag != 0 {
|
|
|
- kcp.parse_fastack(maxack)
|
|
|
- }
|
|
|
-
|
|
|
return 0
|
|
|
}
|
|
|
|
|
|
@@ -284,42 +199,16 @@ func (kcp *KCP) flush() {
|
|
|
kcp.SetState(StateTerminating)
|
|
|
}
|
|
|
|
|
|
- current := kcp.current
|
|
|
-
|
|
|
// flush acknowledges
|
|
|
kcp.receivingWorker.Flush()
|
|
|
+ kcp.sendingWorker.Flush()
|
|
|
|
|
|
- // calculate window size
|
|
|
- cwnd := kcp.snd_una + kcp.snd_wnd
|
|
|
- if cwnd > kcp.rmt_wnd {
|
|
|
- cwnd = kcp.rmt_wnd
|
|
|
- }
|
|
|
- if kcp.congestionControl && cwnd > kcp.snd_una+kcp.cwnd {
|
|
|
- cwnd = kcp.snd_una + kcp.cwnd
|
|
|
- }
|
|
|
-
|
|
|
- for !kcp.snd_queue.IsEmpty() && _itimediff(kcp.snd_nxt, cwnd) < 0 {
|
|
|
- seg := kcp.snd_queue.Pop()
|
|
|
- seg.Conv = kcp.conv
|
|
|
- seg.Number = kcp.snd_nxt
|
|
|
- seg.timeout = current
|
|
|
- seg.ackSkipped = 0
|
|
|
- seg.transmit = 0
|
|
|
- kcp.snd_buf.Push(seg)
|
|
|
- kcp.snd_nxt++
|
|
|
- }
|
|
|
-
|
|
|
- // flush data segments
|
|
|
- if kcp.snd_buf.Flush() {
|
|
|
- kcp.sendingUpdated = false
|
|
|
- }
|
|
|
-
|
|
|
- if kcp.sendingUpdated || kcp.receivingWorker.PingNecessary() || _itimediff(kcp.current, kcp.lastPingTime) >= 5000 {
|
|
|
+ if kcp.sendingWorker.PingNecessary() || kcp.receivingWorker.PingNecessary() || _itimediff(kcp.current, kcp.lastPingTime) >= 5000 {
|
|
|
seg := &CmdOnlySegment{
|
|
|
Conv: kcp.conv,
|
|
|
Cmd: SegmentCommandPing,
|
|
|
ReceivinNext: kcp.receivingWorker.nextNumber,
|
|
|
- SendingNext: kcp.snd_una,
|
|
|
+ SendingNext: kcp.sendingWorker.firstUnacknowledged,
|
|
|
}
|
|
|
if kcp.state == StateReadyToClose {
|
|
|
seg.Opt = SegmentOptionClose
|
|
|
@@ -334,23 +223,6 @@ func (kcp *KCP) flush() {
|
|
|
|
|
|
}
|
|
|
|
|
|
-func (kcp *KCP) HandleLost(lost bool) {
|
|
|
- if !kcp.congestionControl {
|
|
|
- return
|
|
|
- }
|
|
|
- if lost {
|
|
|
- kcp.cwnd = 3 * kcp.cwnd / 4
|
|
|
- } else {
|
|
|
- kcp.cwnd += kcp.cwnd / 4
|
|
|
- }
|
|
|
- if kcp.cwnd < 4 {
|
|
|
- kcp.cwnd = 4
|
|
|
- }
|
|
|
- if kcp.cwnd > kcp.snd_wnd {
|
|
|
- kcp.cwnd = kcp.snd_wnd
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// Update updates state (call it repeatedly, every 10ms-100ms), or you can ask
|
|
|
// ikcp_check when to call it again (without ikcp_input/_send calling).
|
|
|
// 'current' - current timestamp in millisec.
|
|
|
@@ -358,13 +230,3 @@ func (kcp *KCP) Update(current uint32) {
|
|
|
kcp.current = current
|
|
|
kcp.flush()
|
|
|
}
|
|
|
-
|
|
|
-// WaitSnd gets how many packet is waiting to be sent
|
|
|
-func (kcp *KCP) WaitSnd() uint32 {
|
|
|
- return uint32(kcp.snd_buf.Len()) + kcp.snd_queue.Len()
|
|
|
-}
|
|
|
-
|
|
|
-func (this *KCP) ClearSendQueue() {
|
|
|
- this.snd_queue.Clear()
|
|
|
- this.snd_buf.Clear(0xFFFFFFFF)
|
|
|
-}
|