|
|
@@ -10,6 +10,7 @@ import (
|
|
|
|
|
|
"v2ray.com/core/common/alloc"
|
|
|
"v2ray.com/core/common/log"
|
|
|
+ "v2ray.com/core/common/predicate"
|
|
|
"v2ray.com/core/transport/internet"
|
|
|
)
|
|
|
|
|
|
@@ -119,6 +120,45 @@ func (this *RoundTripInfo) SmoothedTime() uint32 {
|
|
|
return this.srtt
|
|
|
}
|
|
|
|
|
|
+type Updater struct {
|
|
|
+ interval time.Duration
|
|
|
+ shouldContinue predicate.Predicate
|
|
|
+ shouldTerminate predicate.Predicate
|
|
|
+ updateFunc func()
|
|
|
+ notifier chan bool
|
|
|
+}
|
|
|
+
|
|
|
+func NewUpdater(interval uint32, shouldContinue predicate.Predicate, shouldTerminate predicate.Predicate, updateFunc func()) *Updater {
|
|
|
+ u := &Updater{
|
|
|
+ interval: time.Duration(interval) * time.Millisecond,
|
|
|
+ shouldContinue: shouldContinue,
|
|
|
+ shouldTerminate: shouldTerminate,
|
|
|
+ updateFunc: updateFunc,
|
|
|
+ notifier: make(chan bool, 1),
|
|
|
+ }
|
|
|
+ go u.Run()
|
|
|
+ return u
|
|
|
+}
|
|
|
+
|
|
|
+func (this *Updater) WakeUp() {
|
|
|
+ select {
|
|
|
+ case this.notifier <- true:
|
|
|
+ default:
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (this *Updater) Run() {
|
|
|
+ for <-this.notifier {
|
|
|
+ if this.shouldTerminate() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for this.shouldContinue() {
|
|
|
+ this.updateFunc()
|
|
|
+ time.Sleep(this.interval)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// Connection is a KCP connection over UDP.
|
|
|
type Connection struct {
|
|
|
block internet.Authenticator
|
|
|
@@ -147,6 +187,9 @@ type Connection struct {
|
|
|
fastresend uint32
|
|
|
congestionControl bool
|
|
|
output *BufferedSegmentWriter
|
|
|
+
|
|
|
+ dataUpdater *Updater
|
|
|
+ pingUpdater *Updater
|
|
|
}
|
|
|
|
|
|
// NewConnection create a new KCP connection between local and remote.
|
|
|
@@ -182,7 +225,18 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
|
|
|
conn.congestionControl = config.Congestion
|
|
|
conn.sendingWorker = NewSendingWorker(conn)
|
|
|
|
|
|
- go conn.updateTask()
|
|
|
+ conn.dataUpdater = NewUpdater(
|
|
|
+ conn.interval,
|
|
|
+ predicate.Any(conn.sendingWorker.UpdateNecessary, conn.receivingWorker.UpdateNecessary),
|
|
|
+ func() bool {
|
|
|
+ return conn.State() == StateTerminated
|
|
|
+ },
|
|
|
+ conn.updateTask)
|
|
|
+ conn.pingUpdater = NewUpdater(
|
|
|
+ 3000, // 3 seconds
|
|
|
+ func() bool { return conn.State() != StateTerminated },
|
|
|
+ func() bool { return conn.State() == StateTerminated },
|
|
|
+ conn.updateTask)
|
|
|
|
|
|
return conn
|
|
|
}
|
|
|
@@ -240,6 +294,7 @@ func (this *Connection) Write(b []byte) (int, error) {
|
|
|
}
|
|
|
|
|
|
nBytes := this.sendingWorker.Push(b[totalWritten:])
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
if nBytes > 0 {
|
|
|
totalWritten += nBytes
|
|
|
if totalWritten == len(b) {
|
|
|
@@ -278,16 +333,24 @@ func (this *Connection) SetState(state State) {
|
|
|
switch state {
|
|
|
case StateReadyToClose:
|
|
|
this.receivingWorker.CloseRead()
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
case StatePeerClosed:
|
|
|
this.sendingWorker.CloseWrite()
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
case StateTerminating:
|
|
|
this.receivingWorker.CloseRead()
|
|
|
this.sendingWorker.CloseWrite()
|
|
|
+ this.dataUpdater.interval = time.Second
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
case StatePeerTerminating:
|
|
|
this.sendingWorker.CloseWrite()
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
case StateTerminated:
|
|
|
this.receivingWorker.CloseRead()
|
|
|
this.sendingWorker.CloseWrite()
|
|
|
+ this.dataUpdater.interval = time.Second
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
+ this.Terminate()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -366,16 +429,7 @@ func (this *Connection) SetWriteDeadline(t time.Time) error {
|
|
|
|
|
|
// kcp update, input loop
|
|
|
func (this *Connection) updateTask() {
|
|
|
- for this.State() != StateTerminated {
|
|
|
- this.flush()
|
|
|
-
|
|
|
- interval := time.Duration(this.Config.Tti.GetValue()) * time.Millisecond
|
|
|
- if this.State() == StateTerminating {
|
|
|
- interval = time.Second
|
|
|
- }
|
|
|
- time.Sleep(interval)
|
|
|
- }
|
|
|
- this.Terminate()
|
|
|
+ this.flush()
|
|
|
}
|
|
|
|
|
|
func (this *Connection) FetchInputFrom(conn io.Reader) {
|
|
|
@@ -408,7 +462,7 @@ func (this *Connection) Terminate() {
|
|
|
}
|
|
|
log.Info("KCP|Connection: Terminating connection to ", this.RemoteAddr())
|
|
|
|
|
|
- this.SetState(StateTerminated)
|
|
|
+ //this.SetState(StateTerminated)
|
|
|
this.dataInputCond.Broadcast()
|
|
|
this.dataOutputCond.Broadcast()
|
|
|
this.writer.Close()
|
|
|
@@ -434,6 +488,7 @@ func (this *Connection) OnPeerClosed() {
|
|
|
func (this *Connection) Input(data []byte) int {
|
|
|
current := this.Elapsed()
|
|
|
atomic.StoreUint32(&this.lastIncomingTime, current)
|
|
|
+ this.dataUpdater.WakeUp()
|
|
|
|
|
|
var seg Segment
|
|
|
for {
|