github.com/xraypb/Xray-core@v1.8.1/common/mux/session.go (about)

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