| 1256 | } |
| 1257 | |
| 1258 | func (c *Client) routeRx(f *frame.Frame) { |
| 1259 | c.mu.Lock() |
| 1260 | s, ok := c.sessions[f.SessionID] |
| 1261 | c.mu.Unlock() |
| 1262 | if !ok { |
| 1263 | return // unknown session - drop |
| 1264 | } |
| 1265 | if c.debugTiming && len(f.Payload) > 0 { |
| 1266 | // First downstream frame for a session implies time-to-first-byte. |
| 1267 | // LoadAndDelete ensures we log this exactly once per session. |
| 1268 | if start, loaded := c.debugStarts.LoadAndDelete(f.SessionID); loaded { |
| 1269 | ttfb := time.Since(start.(time.Time)) |
| 1270 | log.Printf("[timing] %x ttfb=%dms target=%s", |
| 1271 | f.SessionID[:4], ttfb.Milliseconds(), s.Target) |
| 1272 | } |
| 1273 | } |
| 1274 | if f.HasFlag(frame.FlagRST) { |
| 1275 | // Server has no state for this session (e.g. it restarted). Tear it down |
| 1276 | // immediately so the SOCKS client gets an error and reconnects cleanly. |
| 1277 | log.Printf("[carrier] RST from server for session %x; closing", f.SessionID[:4]) |
| 1278 | s.CloseRx() |
| 1279 | s.RequestClose() |
| 1280 | c.mu.Lock() |
| 1281 | delete(c.sessions, f.SessionID) |
| 1282 | delete(c.txReady, f.SessionID) |
| 1283 | c.mu.Unlock() |
| 1284 | if c.debugTiming { |
| 1285 | c.debugStarts.Delete(f.SessionID) |
| 1286 | } |
| 1287 | s.Stop() |
| 1288 | c.stats.rstFromServer.Add(1) |
| 1289 | c.stats.sessionsClose.Add(1) |
| 1290 | return |
| 1291 | } |
| 1292 | s.ProcessRx(f) |
| 1293 | } |
| 1294 | |
| 1295 | func (c *Client) gcDoneSessions() { |
| 1296 | c.mu.Lock() |