|  | @@ -3,15 +3,12 @@ package ray
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  |  	"context"
 | 
	
		
			
				|  |  |  	"io"
 | 
	
		
			
				|  |  | +	"sync"
 | 
	
		
			
				|  |  |  	"time"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/buf"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const (
 | 
	
		
			
				|  |  | -	bufferSize = 512
 | 
	
		
			
				|  |  | -)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  // NewRay creates a new Ray for direct traffic transport.
 | 
	
		
			
				|  |  |  func NewRay(ctx context.Context) Ray {
 | 
	
		
			
				|  |  |  	return &directRay{
 | 
	
	
		
			
				|  | @@ -42,121 +39,132 @@ func (v *directRay) InboundOutput() InputStream {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type Stream struct {
 | 
	
		
			
				|  |  | -	buffer chan buf.MultiBuffer
 | 
	
		
			
				|  |  | +	access sync.Mutex
 | 
	
		
			
				|  |  | +	data   buf.MultiBuffer
 | 
	
		
			
				|  |  |  	ctx    context.Context
 | 
	
		
			
				|  |  | -	close  chan bool
 | 
	
		
			
				|  |  | -	err    chan bool
 | 
	
		
			
				|  |  | +	wakeup chan bool
 | 
	
		
			
				|  |  | +	close  bool
 | 
	
		
			
				|  |  | +	err    bool
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func NewStream(ctx context.Context) *Stream {
 | 
	
		
			
				|  |  |  	return &Stream{
 | 
	
		
			
				|  |  |  		ctx:    ctx,
 | 
	
		
			
				|  |  | -		buffer: make(chan buf.MultiBuffer, bufferSize),
 | 
	
		
			
				|  |  | -		close:  make(chan bool),
 | 
	
		
			
				|  |  | -		err:    make(chan bool),
 | 
	
		
			
				|  |  | +		wakeup: make(chan bool, 1),
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *Stream) Read() (buf.MultiBuffer, error) {
 | 
	
		
			
				|  |  | -	select {
 | 
	
		
			
				|  |  | -	case <-v.ctx.Done():
 | 
	
		
			
				|  |  | -		return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	case <-v.err:
 | 
	
		
			
				|  |  | +func (s *Stream) getData() (buf.MultiBuffer, error) {
 | 
	
		
			
				|  |  | +	s.access.Lock()
 | 
	
		
			
				|  |  | +	defer s.access.Unlock()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if s.data != nil {
 | 
	
		
			
				|  |  | +		mb := s.data
 | 
	
		
			
				|  |  | +		s.data = nil
 | 
	
		
			
				|  |  | +		return mb, nil
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if s.close {
 | 
	
		
			
				|  |  | +		return nil, io.EOF
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if s.err {
 | 
	
		
			
				|  |  |  		return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	case b := <-v.buffer:
 | 
	
		
			
				|  |  | -		return b, nil
 | 
	
		
			
				|  |  | -	default:
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return nil, nil
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (s *Stream) Read() (buf.MultiBuffer, error) {
 | 
	
		
			
				|  |  | +	for {
 | 
	
		
			
				|  |  | +		mb, err := s.getData()
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			return nil, err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if mb != nil {
 | 
	
		
			
				|  |  | +			return mb, nil
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		select {
 | 
	
		
			
				|  |  | -		case <-v.ctx.Done():
 | 
	
		
			
				|  |  | -			return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | -		case b := <-v.buffer:
 | 
	
		
			
				|  |  | -			return b, nil
 | 
	
		
			
				|  |  | -		case <-v.close:
 | 
	
		
			
				|  |  | -			return nil, io.EOF
 | 
	
		
			
				|  |  | -		case <-v.err:
 | 
	
		
			
				|  |  | +		case <-s.ctx.Done():
 | 
	
		
			
				|  |  |  			return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | +		case <-s.wakeup:
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *Stream) ReadTimeout(timeout time.Duration) (buf.MultiBuffer, error) {
 | 
	
		
			
				|  |  | -	select {
 | 
	
		
			
				|  |  | -	case <-v.ctx.Done():
 | 
	
		
			
				|  |  | -		return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	case <-v.err:
 | 
	
		
			
				|  |  | -		return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	case b := <-v.buffer:
 | 
	
		
			
				|  |  | -		return b, nil
 | 
	
		
			
				|  |  | -	default:
 | 
	
		
			
				|  |  | -		if timeout == 0 {
 | 
	
		
			
				|  |  | -			return nil, buf.ErrReadTimeout
 | 
	
		
			
				|  |  | +func (s *Stream) ReadTimeout(timeout time.Duration) (buf.MultiBuffer, error) {
 | 
	
		
			
				|  |  | +	for {
 | 
	
		
			
				|  |  | +		mb, err := s.getData()
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			return nil, err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if mb != nil {
 | 
	
		
			
				|  |  | +			return mb, nil
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		select {
 | 
	
		
			
				|  |  | -		case <-v.ctx.Done():
 | 
	
		
			
				|  |  | -			return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  | -		case b := <-v.buffer:
 | 
	
		
			
				|  |  | -			return b, nil
 | 
	
		
			
				|  |  | -		case <-v.close:
 | 
	
		
			
				|  |  | -			return nil, io.EOF
 | 
	
		
			
				|  |  | -		case <-v.err:
 | 
	
		
			
				|  |  | +		case <-s.ctx.Done():
 | 
	
		
			
				|  |  |  			return nil, io.ErrClosedPipe
 | 
	
		
			
				|  |  |  		case <-time.After(timeout):
 | 
	
		
			
				|  |  |  			return nil, buf.ErrReadTimeout
 | 
	
		
			
				|  |  | +		case <-s.wakeup:
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *Stream) Write(data buf.MultiBuffer) (err error) {
 | 
	
		
			
				|  |  | +func (s *Stream) Write(data buf.MultiBuffer) (err error) {
 | 
	
		
			
				|  |  |  	if data.IsEmpty() {
 | 
	
		
			
				|  |  |  		return
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	select {
 | 
	
		
			
				|  |  | -	case <-v.ctx.Done():
 | 
	
		
			
				|  |  | -		return io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	case <-v.err:
 | 
	
		
			
				|  |  | +	s.access.Lock()
 | 
	
		
			
				|  |  | +	defer s.access.Unlock()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if s.err {
 | 
	
		
			
				|  |  | +		data.Release()
 | 
	
		
			
				|  |  |  		return io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	case <-v.close:
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	if s.close {
 | 
	
		
			
				|  |  | +		data.Release()
 | 
	
		
			
				|  |  |  		return io.ErrClosedPipe
 | 
	
		
			
				|  |  | -	default:
 | 
	
		
			
				|  |  | -		select {
 | 
	
		
			
				|  |  | -		case <-v.ctx.Done():
 | 
	
		
			
				|  |  | -			return io.ErrClosedPipe
 | 
	
		
			
				|  |  | -		case <-v.err:
 | 
	
		
			
				|  |  | -			return io.ErrClosedPipe
 | 
	
		
			
				|  |  | -		case <-v.close:
 | 
	
		
			
				|  |  | -			return io.ErrClosedPipe
 | 
	
		
			
				|  |  | -		case v.buffer <- data:
 | 
	
		
			
				|  |  | -			return nil
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *Stream) Close() {
 | 
	
		
			
				|  |  | -	defer swallowPanic()
 | 
	
		
			
				|  |  | +	if s.data == nil {
 | 
	
		
			
				|  |  | +		s.data = data
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		s.data.AppendMulti(data)
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	s.wakeUp()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	close(v.close)
 | 
	
		
			
				|  |  | +	return nil
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *Stream) CloseError() {
 | 
	
		
			
				|  |  | -	defer swallowPanic()
 | 
	
		
			
				|  |  | +func (s *Stream) wakeUp() {
 | 
	
		
			
				|  |  | +	select {
 | 
	
		
			
				|  |  | +	case s.wakeup <- true:
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	close(v.err)
 | 
	
		
			
				|  |  | +func (s *Stream) Close() {
 | 
	
		
			
				|  |  | +	s.access.Lock()
 | 
	
		
			
				|  |  | +	s.close = true
 | 
	
		
			
				|  |  | +	s.wakeUp()
 | 
	
		
			
				|  |  | +	s.access.Unlock()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	n := len(v.buffer)
 | 
	
		
			
				|  |  | -	for i := 0; i < n; i++ {
 | 
	
		
			
				|  |  | -		select {
 | 
	
		
			
				|  |  | -		case b := <-v.buffer:
 | 
	
		
			
				|  |  | -			b.Release()
 | 
	
		
			
				|  |  | -		default:
 | 
	
		
			
				|  |  | -			return
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | +func (s *Stream) CloseError() {
 | 
	
		
			
				|  |  | +	s.access.Lock()
 | 
	
		
			
				|  |  | +	s.err = true
 | 
	
		
			
				|  |  | +	if s.data != nil {
 | 
	
		
			
				|  |  | +		s.data.Release()
 | 
	
		
			
				|  |  | +		s.data = nil
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	s.wakeUp()
 | 
	
		
			
				|  |  | +	s.access.Unlock()
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (v *Stream) Release() {}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func swallowPanic() {
 | 
	
		
			
				|  |  | -	recover()
 | 
	
		
			
				|  |  | -}
 |