When bandwidthLimitMode is "server", the work connection is wrapped by
libio.WrapReadWriteCloser with a close callback that captured the
variable being reassigned (local/rwc). At call time the callback
referenced the wrapper itself, whose closed guard was already set, so
Close returned nil without closing the underlying work connection.
For TCP proxies this left libio.Join blocked on the other copy
goroutine after the user disconnected, keeping the work connection and
the backend connection open. HTTP and UDP proxies had the same pattern.
Bind the Close method value before reassignment, and add an e2e test
verifying that the local connection is closed after the user
disconnects.
SUDP payload codec follows transport wireProtocol; same-protocol v1/v1 and v2/v2 keep raw join; only mixed proxy/visitor protocols use message-aware bridge; no new capability/selection field.
- pkg/nathole: add RLock when reading clientCfgs map in PreCheck path
to prevent concurrent map read/write crash
- server/proxy: fix error variable shadowing in GetWorkConnFromPool
that could return a closed connection with nil error
- pkg/util/net: check ListenUDP error before spawning goroutines
and assign readConn to struct field so Close() works correctly
- Replace duplicate parseBasicAuth with existing httppkg.ParseBasicAuth
- Extract buildDomains helper in BaseProxy for HTTP/HTTPS/TCPMux proxies
- Extract toProxyStats helper to deduplicate ProxyStats construction
- Extract startVisitorListener helper in BaseProxy for STCP/SUDP proxies
- Extract acceptLoop helper in BaseVisitor for STCP/XTCP visitors
* support bandwidth_limit set by server plugin
* limiter at proxy level
* bandwidth_limit_mode
* updates tests for bandwidth_limit_mode default
* bandwidth_limit_mode as string
* add checkForSrv for bandwidth_limit_mode
* bandwidth_limit flags for sub cmds
* gci write
token is the current token comparison, and oidc generates oidc token using client-credentials flow. in addition - add ping verification using the same method
The ServerCommonConf is now passed around as an argument instead of
being shared between components as a global variable. This allows for
more natural interaction with server.Session as a library and allows for
multiple servers to co-exist within the same process.
Related: #1387