NewSession creates a tunneled session for target ("host:port") and registers it with the long-poll loop. Returns the session for the caller (typically the SOCKS adapter) to wrap in a VirtualConn.
(target string)
| 452 | // it with the long-poll loop. Returns the session for the caller (typically |
| 453 | // the SOCKS adapter) to wrap in a VirtualConn. |
| 454 | func (c *Client) NewSession(target string) *session.Session { |
| 455 | var id [frame.SessionIDLen]byte |
| 456 | if _, err := rand.Read(id[:]); err != nil { |
| 457 | // crypto/rand failure is unrecoverable; panic so the process exits |
| 458 | // rather than emitting an all-zero ID. |
| 459 | panic(fmt.Errorf("crypto/rand: %w", err)) |
| 460 | } |
| 461 | s := session.New(id, target, true) |
| 462 | s.OnTx = func() { |
| 463 | c.mu.Lock() |
| 464 | c.txReady[id] = struct{}{} |
| 465 | c.mu.Unlock() |
| 466 | c.kick() |
| 467 | } |
| 468 | c.mu.Lock() |
| 469 | c.sessions[id] = s |
| 470 | c.txReady[id] = struct{}{} // SYN is pending immediately on creation |
| 471 | c.mu.Unlock() |
| 472 | c.stats.sessionsOpen.Add(1) |
| 473 | if c.debugTiming { |
| 474 | c.debugStarts.Store(id, time.Now()) |
| 475 | } |
| 476 | c.kick() |
| 477 | return s |
| 478 | } |
| 479 | |
| 480 | // Shutdown sends an RST frame for every active session so the server can |
| 481 | // release the corresponding upstream connections immediately rather than |