|  | @@ -2,9 +2,8 @@ package kcp
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  |  	"context"
 | 
	
		
			
				|  |  | -	"crypto/cipher"
 | 
	
		
			
				|  |  |  	"crypto/tls"
 | 
	
		
			
				|  |  | -	"sync"
 | 
	
		
			
				|  |  | +	"io"
 | 
	
		
			
				|  |  |  	"sync/atomic"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	"v2ray.com/core/app/log"
 | 
	
	
		
			
				|  | @@ -20,84 +19,20 @@ var (
 | 
	
		
			
				|  |  |  	globalConv = uint32(dice.RollUint16())
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -type ClientConnection struct {
 | 
	
		
			
				|  |  | -	sync.RWMutex
 | 
	
		
			
				|  |  | -	net.Conn
 | 
	
		
			
				|  |  | -	input  func([]Segment)
 | 
	
		
			
				|  |  | -	reader PacketReader
 | 
	
		
			
				|  |  | -	writer PacketWriter
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (c *ClientConnection) Overhead() int {
 | 
	
		
			
				|  |  | -	c.RLock()
 | 
	
		
			
				|  |  | -	defer c.RUnlock()
 | 
	
		
			
				|  |  | -	if c.writer == nil {
 | 
	
		
			
				|  |  | -		return 0
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return c.writer.Overhead()
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// Write implements io.Writer.
 | 
	
		
			
				|  |  | -func (c *ClientConnection) Write(b []byte) (int, error) {
 | 
	
		
			
				|  |  | -	c.RLock()
 | 
	
		
			
				|  |  | -	defer c.RUnlock()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if c.writer == nil {
 | 
	
		
			
				|  |  | -		return len(b), nil
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	return c.writer.Write(b)
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (*ClientConnection) Read([]byte) (int, error) {
 | 
	
		
			
				|  |  | -	panic("KCP|ClientConnection: Read should not be called.")
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (c *ClientConnection) Close() error {
 | 
	
		
			
				|  |  | -	return c.Conn.Close()
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (c *ClientConnection) Reset(inputCallback func([]Segment)) {
 | 
	
		
			
				|  |  | -	c.Lock()
 | 
	
		
			
				|  |  | -	c.input = inputCallback
 | 
	
		
			
				|  |  | -	c.Unlock()
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (c *ClientConnection) ResetSecurity(header internet.PacketHeader, security cipher.AEAD) {
 | 
	
		
			
				|  |  | -	c.Lock()
 | 
	
		
			
				|  |  | -	if c.reader == nil {
 | 
	
		
			
				|  |  | -		c.reader = new(KCPPacketReader)
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	c.reader.(*KCPPacketReader).Header = header
 | 
	
		
			
				|  |  | -	c.reader.(*KCPPacketReader).Security = security
 | 
	
		
			
				|  |  | -	if c.writer == nil {
 | 
	
		
			
				|  |  | -		c.writer = new(KCPPacketWriter)
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	c.writer.(*KCPPacketWriter).Header = header
 | 
	
		
			
				|  |  | -	c.writer.(*KCPPacketWriter).Security = security
 | 
	
		
			
				|  |  | -	c.writer.(*KCPPacketWriter).Writer = c.Conn
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	c.Unlock()
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (c *ClientConnection) Run() {
 | 
	
		
			
				|  |  | +func fetchInput(ctx context.Context, input io.Reader, reader PacketReader, conn *Connection) {
 | 
	
		
			
				|  |  |  	payload := buf.New()
 | 
	
		
			
				|  |  |  	defer payload.Release()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	for {
 | 
	
		
			
				|  |  | -		err := payload.Reset(buf.ReadFrom(c.Conn))
 | 
	
		
			
				|  |  | +		err := payload.Reset(buf.ReadFrom(input))
 | 
	
		
			
				|  |  |  		if err != nil {
 | 
	
		
			
				|  |  |  			payload.Release()
 | 
	
		
			
				|  |  |  			return
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | -		c.RLock()
 | 
	
		
			
				|  |  | -		if c.input != nil {
 | 
	
		
			
				|  |  | -			segments := c.reader.Read(payload.Bytes())
 | 
	
		
			
				|  |  | -			if len(segments) > 0 {
 | 
	
		
			
				|  |  | -				c.input(segments)
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | +		segments := reader.Read(payload.Bytes())
 | 
	
		
			
				|  |  | +		if len(segments) > 0 {
 | 
	
		
			
				|  |  | +			conn.Input(segments)
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | -		c.RUnlock()
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -110,10 +45,6 @@ func DialKCP(ctx context.Context, dest net.Destination) (internet.Connection, er
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		return nil, newError("failed to dial to dest: ", err).AtWarning().Base(err)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	conn := &ClientConnection{
 | 
	
		
			
				|  |  | -		Conn: rawConn,
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	go conn.Run()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	kcpSettings := internet.TransportSettingsFromContext(ctx).(*Config)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -125,9 +56,23 @@ func DialKCP(ctx context.Context, dest net.Destination) (internet.Connection, er
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		return nil, newError("failed to create security").Base(err)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	conn.ResetSecurity(header, security)
 | 
	
		
			
				|  |  | +	reader := &KCPPacketReader{
 | 
	
		
			
				|  |  | +		Header:   header,
 | 
	
		
			
				|  |  | +		Security: security,
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	writer := &KCPPacketWriter{
 | 
	
		
			
				|  |  | +		Header:   header,
 | 
	
		
			
				|  |  | +		Security: security,
 | 
	
		
			
				|  |  | +		Writer:   rawConn,
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	conv := uint16(atomic.AddUint32(&globalConv, 1))
 | 
	
		
			
				|  |  | -	session := NewConnection(conv, conn, kcpSettings)
 | 
	
		
			
				|  |  | +	session := NewConnection(conv, &ConnMetadata{
 | 
	
		
			
				|  |  | +		LocalAddr:  rawConn.LocalAddr(),
 | 
	
		
			
				|  |  | +		RemoteAddr: rawConn.RemoteAddr(),
 | 
	
		
			
				|  |  | +	}, writer, rawConn, kcpSettings)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	go fetchInput(ctx, rawConn, reader, session)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	var iConn internet.Connection = session
 | 
	
		
			
				|  |  |  
 |