|
|
|
@ -9,6 +9,7 @@ import (
|
|
|
|
|
|
|
|
|
|
"github.com/v2ray/v2ray-core/common/alloc"
|
|
|
|
|
"github.com/v2ray/v2ray-core/common/log"
|
|
|
|
|
"github.com/v2ray/v2ray-core/common/signal"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
@ -63,6 +64,7 @@ type Connection struct {
|
|
|
|
|
chReadEvent chan struct{}
|
|
|
|
|
writer io.WriteCloser
|
|
|
|
|
since int64
|
|
|
|
|
terminateOnce signal.Once
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewConnection create a new KCP connection between local and remote.
|
|
|
|
@ -76,21 +78,7 @@ func NewConnection(conv uint32, writerCloser io.WriteCloser, local *net.UDPAddr,
|
|
|
|
|
conn.since = nowMillisec()
|
|
|
|
|
|
|
|
|
|
mtu := uint32(effectiveConfig.Mtu - block.HeaderSize() - headerSize)
|
|
|
|
|
conn.kcp = NewKCP(conv, mtu, func(buf []byte, size int) {
|
|
|
|
|
if size >= IKCP_OVERHEAD {
|
|
|
|
|
ext := alloc.NewBuffer().Clear().Append(buf[:size])
|
|
|
|
|
cmd := CommandData
|
|
|
|
|
opt := Option(0)
|
|
|
|
|
if conn.state == ConnStateReadyToClose {
|
|
|
|
|
opt = OptionClose
|
|
|
|
|
}
|
|
|
|
|
ext.Prepend([]byte{byte(cmd), byte(opt)})
|
|
|
|
|
go conn.output(ext)
|
|
|
|
|
}
|
|
|
|
|
if conn.state == ConnStateReadyToClose && conn.kcp.WaitSnd() == 0 {
|
|
|
|
|
go conn.NotifyTermination()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
conn.kcp = NewKCP(conv, mtu, conn.output)
|
|
|
|
|
conn.kcp.WndSize(effectiveConfig.Sndwnd, effectiveConfig.Rcvwnd)
|
|
|
|
|
conn.kcp.NoDelay(1, 20, 2, 1)
|
|
|
|
|
conn.kcp.current = conn.Elapsed()
|
|
|
|
@ -199,7 +187,7 @@ func (this *Connection) NotifyTermination() {
|
|
|
|
|
this.RUnlock()
|
|
|
|
|
buffer := alloc.NewSmallBuffer().Clear()
|
|
|
|
|
buffer.AppendBytes(byte(CommandTerminate), byte(OptionClose), byte(0), byte(0), byte(0), byte(0))
|
|
|
|
|
this.output(buffer)
|
|
|
|
|
this.outputBuffer(buffer)
|
|
|
|
|
|
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
|
|
|
|
|
@ -207,6 +195,19 @@ func (this *Connection) NotifyTermination() {
|
|
|
|
|
this.Terminate()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *Connection) ForceTimeout() {
|
|
|
|
|
if this == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < 5; i++ {
|
|
|
|
|
if this.state == ConnStateClosed {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
time.Sleep(time.Minute)
|
|
|
|
|
}
|
|
|
|
|
go this.terminateOnce.Do(this.NotifyTermination)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close closes the connection.
|
|
|
|
|
func (this *Connection) Close() error {
|
|
|
|
|
if this == nil || this.state == ConnStateClosed || this.state == ConnStateReadyToClose {
|
|
|
|
@ -219,7 +220,9 @@ func (this *Connection) Close() error {
|
|
|
|
|
if this.state == ConnStateActive {
|
|
|
|
|
this.state = ConnStateReadyToClose
|
|
|
|
|
if this.kcp.WaitSnd() == 0 {
|
|
|
|
|
go this.NotifyTermination()
|
|
|
|
|
go this.terminateOnce.Do(this.NotifyTermination)
|
|
|
|
|
} else {
|
|
|
|
|
go this.ForceTimeout()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -280,7 +283,7 @@ func (this *Connection) SetWriteDeadline(t time.Time) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *Connection) output(payload *alloc.Buffer) {
|
|
|
|
|
func (this *Connection) outputBuffer(payload *alloc.Buffer) {
|
|
|
|
|
defer payload.Release()
|
|
|
|
|
if this == nil {
|
|
|
|
|
return
|
|
|
|
@ -296,6 +299,29 @@ func (this *Connection) output(payload *alloc.Buffer) {
|
|
|
|
|
this.writer.Write(payload.Value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *Connection) output(payload []byte) {
|
|
|
|
|
if this == nil || this.state == ConnStateClosed {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if this.state == ConnStateReadyToClose && this.kcp.WaitSnd() == 0 {
|
|
|
|
|
go this.terminateOnce.Do(this.NotifyTermination)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(payload) < IKCP_OVERHEAD {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer := alloc.NewBuffer().Clear().Append(payload)
|
|
|
|
|
cmd := CommandData
|
|
|
|
|
opt := Option(0)
|
|
|
|
|
if this.state == ConnStateReadyToClose {
|
|
|
|
|
opt = OptionClose
|
|
|
|
|
}
|
|
|
|
|
buffer.Prepend([]byte{byte(cmd), byte(opt)})
|
|
|
|
|
this.outputBuffer(buffer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// kcp update, input loop
|
|
|
|
|
func (this *Connection) updateTask() {
|
|
|
|
|
for this.state != ConnStateClosed {
|
|
|
|
|