|
|
|
@ -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 {
|
|
|
|
|