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 }