|
|
@@ -42,7 +42,7 @@ func (s *session) closeUplink() {
|
|
|
allDone = s.uplinkClosed && s.downlinkClosed
|
|
|
s.Unlock()
|
|
|
if allDone {
|
|
|
- go s.parent.remove(s.id)
|
|
|
+ s.parent.remove(s.id)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -53,7 +53,7 @@ func (s *session) closeDownlink() {
|
|
|
allDone = s.uplinkClosed && s.downlinkClosed
|
|
|
s.Unlock()
|
|
|
if allDone {
|
|
|
- go s.parent.remove(s.id)
|
|
|
+ s.parent.remove(s.id)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -109,13 +109,14 @@ func (m *ClientManager) onClientFinish() {
|
|
|
}
|
|
|
|
|
|
type Client struct {
|
|
|
- access sync.RWMutex
|
|
|
- count uint16
|
|
|
- sessions map[uint16]*session
|
|
|
- inboundRay ray.InboundRay
|
|
|
- ctx context.Context
|
|
|
- cancel context.CancelFunc
|
|
|
- manager *ClientManager
|
|
|
+ access sync.RWMutex
|
|
|
+ count uint16
|
|
|
+ sessions map[uint16]*session
|
|
|
+ inboundRay ray.InboundRay
|
|
|
+ ctx context.Context
|
|
|
+ cancel context.CancelFunc
|
|
|
+ manager *ClientManager
|
|
|
+ session2Remove chan uint16
|
|
|
}
|
|
|
|
|
|
var muxCoolDestination = net.TCPDestination(net.DomainAddress("v1.mux.cool"), net.Port(9527))
|
|
|
@@ -126,27 +127,24 @@ func NewClient(p proxy.Outbound, dialer proxy.Dialer, m *ClientManager) (*Client
|
|
|
pipe := ray.NewRay(ctx)
|
|
|
go p.Process(ctx, pipe, dialer)
|
|
|
c := &Client{
|
|
|
- sessions: make(map[uint16]*session, 256),
|
|
|
- inboundRay: pipe,
|
|
|
- ctx: ctx,
|
|
|
- cancel: cancel,
|
|
|
- manager: m,
|
|
|
- count: 0,
|
|
|
+ sessions: make(map[uint16]*session, 256),
|
|
|
+ inboundRay: pipe,
|
|
|
+ ctx: ctx,
|
|
|
+ cancel: cancel,
|
|
|
+ manager: m,
|
|
|
+ count: 0,
|
|
|
+ session2Remove: make(chan uint16, 16),
|
|
|
}
|
|
|
go c.fetchOutput()
|
|
|
+ go c.monitor()
|
|
|
return c, nil
|
|
|
}
|
|
|
|
|
|
func (m *Client) remove(id uint16) {
|
|
|
- m.access.Lock()
|
|
|
- defer m.access.Unlock()
|
|
|
-
|
|
|
- delete(m.sessions, id)
|
|
|
-
|
|
|
- if len(m.sessions) == 0 {
|
|
|
- m.cancel()
|
|
|
- m.inboundRay.InboundInput().Close()
|
|
|
- go m.manager.onClientFinish()
|
|
|
+ select {
|
|
|
+ case m.session2Remove <- id:
|
|
|
+ default:
|
|
|
+ // Probably not gonna happen.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -159,6 +157,31 @@ func (m *Client) Closed() bool {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (m *Client) monitor() {
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case <-m.ctx.Done():
|
|
|
+ m.cleanup()
|
|
|
+ return
|
|
|
+ case id := <-m.session2Remove:
|
|
|
+ m.access.Lock()
|
|
|
+ delete(m.sessions, id)
|
|
|
+ m.access.Unlock()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (m *Client) cleanup() {
|
|
|
+ m.access.Lock()
|
|
|
+ defer m.access.Unlock()
|
|
|
+
|
|
|
+ for _, s := range m.sessions {
|
|
|
+ s.closeUplink()
|
|
|
+ s.closeDownlink()
|
|
|
+ s.output.CloseError()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func fetchInput(ctx context.Context, s *session, output buf.Writer) {
|
|
|
dest, _ := proxy.TargetFromContext(ctx)
|
|
|
writer := &Writer{
|
|
|
@@ -242,6 +265,8 @@ func pipe(reader *Reader, writer buf.Writer) error {
|
|
|
}
|
|
|
|
|
|
func (m *Client) fetchOutput() {
|
|
|
+ defer m.cancel()
|
|
|
+
|
|
|
reader := NewReader(m.inboundRay.InboundOutput())
|
|
|
for {
|
|
|
meta, err := reader.ReadMetadata()
|
|
|
@@ -271,15 +296,6 @@ func (m *Client) fetchOutput() {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // Close all downlinks
|
|
|
- m.access.RLock()
|
|
|
- for _, s := range m.sessions {
|
|
|
- s.closeUplink()
|
|
|
- s.closeDownlink()
|
|
|
- s.output.CloseError()
|
|
|
- }
|
|
|
- m.access.RUnlock()
|
|
|
}
|
|
|
|
|
|
type Server struct {
|