github.com/xmplusdev/xray-core@v1.8.10/common/mux/session.go (about)

     1  package mux
     2  
     3  import (
     4  	"io"
     5  	"runtime"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/xmplusdev/xray-core/common"
    10  	"github.com/xmplusdev/xray-core/common/buf"
    11  	"github.com/xmplusdev/xray-core/common/net"
    12  	"github.com/xmplusdev/xray-core/common/protocol"
    13  	"github.com/xmplusdev/xray-core/transport/pipe"
    14  )
    15  
    16  type SessionManager struct {
    17  	sync.RWMutex
    18  	sessions map[uint16]*Session
    19  	count    uint16
    20  	closed   bool
    21  }
    22  
    23  func NewSessionManager() *SessionManager {
    24  	return &SessionManager{
    25  		count:    0,
    26  		sessions: make(map[uint16]*Session, 16),
    27  	}
    28  }
    29  
    30  func (m *SessionManager) Closed() bool {
    31  	m.RLock()
    32  	defer m.RUnlock()
    33  
    34  	return m.closed
    35  }
    36  
    37  func (m *SessionManager) Size() int {
    38  	m.RLock()
    39  	defer m.RUnlock()
    40  
    41  	return len(m.sessions)
    42  }
    43  
    44  func (m *SessionManager) Count() int {
    45  	m.RLock()
    46  	defer m.RUnlock()
    47  
    48  	return int(m.count)
    49  }
    50  
    51  func (m *SessionManager) Allocate() *Session {
    52  	m.Lock()
    53  	defer m.Unlock()
    54  
    55  	if m.closed {
    56  		return nil
    57  	}
    58  
    59  	m.count++
    60  	s := &Session{
    61  		ID:     m.count,
    62  		parent: m,
    63  	}
    64  	m.sessions[s.ID] = s
    65  	return s
    66  }
    67  
    68  func (m *SessionManager) Add(s *Session) bool {
    69  	m.Lock()
    70  	defer m.Unlock()
    71  
    72  	if m.closed {
    73  		return false
    74  	}
    75  
    76  	m.count++
    77  	m.sessions[s.ID] = s
    78  	return true
    79  }
    80  
    81  func (m *SessionManager) Remove(locked bool, id uint16) {
    82  	if !locked {
    83  		m.Lock()
    84  		defer m.Unlock()
    85  	}
    86  	locked = true
    87  
    88  	if m.closed {
    89  		return
    90  	}
    91  
    92  	delete(m.sessions, id)
    93  
    94  	/*
    95  		if len(m.sessions) == 0 {
    96  			m.sessions = make(map[uint16]*Session, 16)
    97  		}
    98  	*/
    99  }
   100  
   101  func (m *SessionManager) Get(id uint16) (*Session, bool) {
   102  	m.RLock()
   103  	defer m.RUnlock()
   104  
   105  	if m.closed {
   106  		return nil, false
   107  	}
   108  
   109  	s, found := m.sessions[id]
   110  	return s, found
   111  }
   112  
   113  func (m *SessionManager) CloseIfNoSession() bool {
   114  	m.Lock()
   115  	defer m.Unlock()
   116  
   117  	if m.closed {
   118  		return true
   119  	}
   120  
   121  	if len(m.sessions) != 0 {
   122  		return false
   123  	}
   124  
   125  	m.closed = true
   126  	return true
   127  }
   128  
   129  func (m *SessionManager) Close() error {
   130  	m.Lock()
   131  	defer m.Unlock()
   132  
   133  	if m.closed {
   134  		return nil
   135  	}
   136  
   137  	m.closed = true
   138  
   139  	for _, s := range m.sessions {
   140  		s.Close(true)
   141  	}
   142  
   143  	m.sessions = nil
   144  	return nil
   145  }
   146  
   147  // Session represents a client connection in a Mux connection.
   148  type Session struct {
   149  	input        buf.Reader
   150  	output       buf.Writer
   151  	parent       *SessionManager
   152  	ID           uint16
   153  	transferType protocol.TransferType
   154  	closed       bool
   155  	XUDP         *XUDP
   156  }
   157  
   158  // Close closes all resources associated with this session.
   159  func (s *Session) Close(locked bool) error {
   160  	if !locked {
   161  		s.parent.Lock()
   162  		defer s.parent.Unlock()
   163  	}
   164  	locked = true
   165  	if s.closed {
   166  		return nil
   167  	}
   168  	s.closed = true
   169  	if s.XUDP == nil {
   170  		common.Interrupt(s.input)
   171  		common.Close(s.output)
   172  	} else {
   173  		// Stop existing handle(), then trigger writer.Close().
   174  		// Note that s.output may be dispatcher.SizeStatWriter.
   175  		s.input.(*pipe.Reader).ReturnAnError(io.EOF)
   176  		runtime.Gosched()
   177  		// If the error set by ReturnAnError still exists, clear it.
   178  		s.input.(*pipe.Reader).Recover()
   179  		XUDPManager.Lock()
   180  		if s.XUDP.Status == Active {
   181  			s.XUDP.Expire = time.Now().Add(time.Minute)
   182  			s.XUDP.Status = Expiring
   183  			newError("XUDP put ", s.XUDP.GlobalID).AtDebug().WriteToLog()
   184  		}
   185  		XUDPManager.Unlock()
   186  	}
   187  	s.parent.Remove(locked, s.ID)
   188  	return nil
   189  }
   190  
   191  // NewReader creates a buf.Reader based on the transfer type of this Session.
   192  func (s *Session) NewReader(reader *buf.BufferedReader, dest *net.Destination) buf.Reader {
   193  	if s.transferType == protocol.TransferTypeStream {
   194  		return NewStreamReader(reader)
   195  	}
   196  	return NewPacketReader(reader, dest)
   197  }
   198  
   199  const (
   200  	Initializing = 0
   201  	Active       = 1
   202  	Expiring     = 2
   203  )
   204  
   205  type XUDP struct {
   206  	GlobalID [8]byte
   207  	Status   uint64
   208  	Expire   time.Time
   209  	Mux      *Session
   210  }
   211  
   212  func (x *XUDP) Interrupt() {
   213  	common.Interrupt(x.Mux.input)
   214  	common.Close(x.Mux.output)
   215  }
   216  
   217  var XUDPManager struct {
   218  	sync.Mutex
   219  	Map map[[8]byte]*XUDP
   220  }
   221  
   222  func init() {
   223  	XUDPManager.Map = make(map[[8]byte]*XUDP)
   224  	go func() {
   225  		for {
   226  			time.Sleep(time.Minute)
   227  			now := time.Now()
   228  			XUDPManager.Lock()
   229  			for id, x := range XUDPManager.Map {
   230  				if x.Status == Expiring && now.After(x.Expire) {
   231  					x.Interrupt()
   232  					delete(XUDPManager.Map, id)
   233  					newError("XUDP del ", id).AtDebug().WriteToLog()
   234  				}
   235  			}
   236  			XUDPManager.Unlock()
   237  		}
   238  	}()
   239  }