github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/commander/outbound.go (about)

     1  // +build !confonly
     2  
     3  package commander
     4  
     5  import (
     6  	"context"
     7  	"sync"
     8  
     9  	"v2ray.com/core/common"
    10  	"v2ray.com/core/common/net"
    11  	"v2ray.com/core/common/signal/done"
    12  	"v2ray.com/core/transport"
    13  )
    14  
    15  // OutboundListener is a net.Listener for listening gRPC connections.
    16  type OutboundListener struct {
    17  	buffer chan net.Conn
    18  	done   *done.Instance
    19  }
    20  
    21  func (l *OutboundListener) add(conn net.Conn) {
    22  	select {
    23  	case l.buffer <- conn:
    24  	case <-l.done.Wait():
    25  		conn.Close() // nolint: errcheck
    26  	default:
    27  		conn.Close() // nolint: errcheck
    28  	}
    29  }
    30  
    31  // Accept implements net.Listener.
    32  func (l *OutboundListener) Accept() (net.Conn, error) {
    33  	select {
    34  	case <-l.done.Wait():
    35  		return nil, newError("listen closed")
    36  	case c := <-l.buffer:
    37  		return c, nil
    38  	}
    39  }
    40  
    41  // Close implement net.Listener.
    42  func (l *OutboundListener) Close() error {
    43  	common.Must(l.done.Close())
    44  L:
    45  	for {
    46  		select {
    47  		case c := <-l.buffer:
    48  			c.Close() // nolint: errcheck
    49  		default:
    50  			break L
    51  		}
    52  	}
    53  	return nil
    54  }
    55  
    56  // Addr implements net.Listener.
    57  func (l *OutboundListener) Addr() net.Addr {
    58  	return &net.TCPAddr{
    59  		IP:   net.IP{0, 0, 0, 0},
    60  		Port: 0,
    61  	}
    62  }
    63  
    64  // Outbound is a outbound.Handler that handles gRPC connections.
    65  type Outbound struct {
    66  	tag      string
    67  	listener *OutboundListener
    68  	access   sync.RWMutex
    69  	closed   bool
    70  }
    71  
    72  // Dispatch implements outbound.Handler.
    73  func (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) {
    74  	co.access.RLock()
    75  
    76  	if co.closed {
    77  		common.Interrupt(link.Reader)
    78  		common.Interrupt(link.Writer)
    79  		co.access.RUnlock()
    80  		return
    81  	}
    82  
    83  	closeSignal := done.New()
    84  	c := net.NewConnection(net.ConnectionInputMulti(link.Writer), net.ConnectionOutputMulti(link.Reader), net.ConnectionOnClose(closeSignal))
    85  	co.listener.add(c)
    86  	co.access.RUnlock()
    87  	<-closeSignal.Wait()
    88  }
    89  
    90  // Tag implements outbound.Handler.
    91  func (co *Outbound) Tag() string {
    92  	return co.tag
    93  }
    94  
    95  // Start implements common.Runnable.
    96  func (co *Outbound) Start() error {
    97  	co.access.Lock()
    98  	co.closed = false
    99  	co.access.Unlock()
   100  	return nil
   101  }
   102  
   103  // Close implements common.Closable.
   104  func (co *Outbound) Close() error {
   105  	co.access.Lock()
   106  	defer co.access.Unlock()
   107  
   108  	co.closed = true
   109  	return co.listener.Close()
   110  }