|  | @@ -1,6 +1,8 @@
 | 
	
		
			
				|  |  |  package impl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  | +	"time"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	"v2ray.com/core/app"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/app/dispatcher"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/app/proxyman"
 | 
	
	
		
			
				|  | @@ -48,7 +50,6 @@ func (v *DefaultDispatcher) Release() {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay {
 | 
	
		
			
				|  |  | -	direct := ray.NewRay()
 | 
	
		
			
				|  |  |  	dispatcher := v.ohm.GetDefaultHandler()
 | 
	
		
			
				|  |  |  	destination := session.Destination
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -65,26 +66,32 @@ func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.I
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	direct := ray.NewRay()
 | 
	
		
			
				|  |  | +	var waitFunc func() error
 | 
	
		
			
				|  |  |  	if session.Inbound != nil && session.Inbound.AllowPassiveConnection {
 | 
	
		
			
				|  |  | -		go dispatcher.Dispatch(destination, buf.NewLocal(32), direct)
 | 
	
		
			
				|  |  | +		waitFunc = noOpWait()
 | 
	
		
			
				|  |  |  	} else {
 | 
	
		
			
				|  |  | -		go v.FilterPacketAndDispatch(destination, direct, dispatcher)
 | 
	
		
			
				|  |  | +		wdi := &waitDataInspector{
 | 
	
		
			
				|  |  | +			hasData: make(chan bool, 1),
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		direct.AddInspector(wdi)
 | 
	
		
			
				|  |  | +		waitFunc = waitForData(wdi)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	go v.waitAndDispatch(waitFunc, destination, direct, dispatcher)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	return direct
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// FilterPacketAndDispatch waits for a payload from source and starts dispatching.
 | 
	
		
			
				|  |  | -// Private: Visible for testing.
 | 
	
		
			
				|  |  | -func (v *DefaultDispatcher) FilterPacketAndDispatch(destination v2net.Destination, link ray.OutboundRay, dispatcher proxy.OutboundHandler) {
 | 
	
		
			
				|  |  | -	payload, err := link.OutboundInput().Read()
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		log.Info("DefaultDispatcher: No payload towards ", destination, ", stopping now.")
 | 
	
		
			
				|  |  | -		link.OutboundInput().Release()
 | 
	
		
			
				|  |  | -		link.OutboundOutput().Release()
 | 
	
		
			
				|  |  | +func (v *DefaultDispatcher) waitAndDispatch(wait func() error, destination v2net.Destination, link ray.OutboundRay, dispatcher proxy.OutboundHandler) {
 | 
	
		
			
				|  |  | +	if err := wait(); err != nil {
 | 
	
		
			
				|  |  | +		log.Info("DefaultDispatcher: Failed precondition: ", err)
 | 
	
		
			
				|  |  | +		link.OutboundInput().ForceClose()
 | 
	
		
			
				|  |  | +		link.OutboundOutput().Close()
 | 
	
		
			
				|  |  |  		return
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	dispatcher.Dispatch(destination, payload, link)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	dispatcher.Dispatch(destination, link)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type DefaultDispatcherFactory struct{}
 | 
	
	
		
			
				|  | @@ -100,3 +107,38 @@ func (v DefaultDispatcherFactory) AppId() app.ID {
 | 
	
		
			
				|  |  |  func init() {
 | 
	
		
			
				|  |  |  	app.RegisterApplicationFactory(serial.GetMessageType(new(dispatcher.Config)), DefaultDispatcherFactory{})
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type waitDataInspector struct {
 | 
	
		
			
				|  |  | +	hasData chan bool
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (wdi *waitDataInspector) Input(*buf.Buffer) {
 | 
	
		
			
				|  |  | +	select {
 | 
	
		
			
				|  |  | +	case wdi.hasData <- true:
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (wdi *waitDataInspector) WaitForData() bool {
 | 
	
		
			
				|  |  | +	select {
 | 
	
		
			
				|  |  | +	case <-wdi.hasData:
 | 
	
		
			
				|  |  | +		return true
 | 
	
		
			
				|  |  | +	case <-time.After(time.Minute):
 | 
	
		
			
				|  |  | +		return false
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func waitForData(wdi *waitDataInspector) func() error {
 | 
	
		
			
				|  |  | +	return func() error {
 | 
	
		
			
				|  |  | +		if wdi.WaitForData() {
 | 
	
		
			
				|  |  | +			return nil
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		return errors.New("DefaultDispatcher: No data.")
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func noOpWait() func() error {
 | 
	
		
			
				|  |  | +	return func() error {
 | 
	
		
			
				|  |  | +		return nil
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 |