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