github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/common/mux/session.go (about) 1 package mux 2 3 import ( 4 "io" 5 "runtime" 6 "sync" 7 "time" 8 9 "github.com/xtls/xray-core/common" 10 "github.com/xtls/xray-core/common/buf" 11 "github.com/xtls/xray-core/common/net" 12 "github.com/xtls/xray-core/common/protocol" 13 "github.com/xtls/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 }