6fd25387f7
## Summary Comprehensive fixes for race conditions, concurrency bugs, and a critical session handling bug across the session package and its child packages. ## Changes ### Bug Fix: waitForTCPIPForward fails on non-tcpip-forward global requests - Changed `waitForTCPIPForward()` from a single select to a for loop that drains non-tcpip-forward requests gracefully - Non-tcpip-forward requests now receive a false reply and the function continues waiting for the actual forward request - The 500ms timeout resets after each request to handle slow clients with multiple early requests - Updated and added tests to cover the new behavior: Wrong_Request_Type_Then_Timeout, Multiple_Non-Forward_Requests_Then_Success, Timeout_After_Non-Forward_Requests ### Race Condition Fixes - Added sync.RWMutex to the forwarder struct to protect concurrent field access - Fixed data race in forwarder setters (`SetType()`, `SetForwardedPort()`, `SetListener()`) by adding `Lock()`/`Unlock()` protection - Fixed data race in forwarder getters (`TunnelType()`, `ForwardedPort()`, `Listener()`) by adding `RLock()`/`RUnlock()` protection - Added sync.RWMutex to the slug struct to protect concurrent field access - Fixed data race in `slug.Set()` by adding `Lock()`/`Unlock()` protection - Fixed data race in `slug.String()` by adding `RLock()`/`RUnlock()` protection ### Concurrency Safety Improvements - Changed `OpenForwardedChannel()` to use `f.ForwardedPort()` getter instead of direct field access - Fixed `Close()` in forwarder to use `f.Listener()` getter consistently instead of accessing `f.listener` directly - Fixed data race in `HandleTCPForward()` where the goroutine running `tcpServer.Serve(listener)` wrote to the outer err variable from the enclosing function scope - Changed err = `tcpServer.Serve(listener)` to `if err := tcpServer.Serve(listener)` so the goroutine uses a local variable Reviewed-on: #151 Co-authored-by: Bagas <bagas@fossy.my.id> Co-committed-by: Bagas <bagas@fossy.my.id>
32 lines
366 B
Go
32 lines
366 B
Go
package slug
|
|
|
|
import "sync"
|
|
|
|
type Slug interface {
|
|
String() string
|
|
Set(slug string)
|
|
}
|
|
|
|
type slug struct {
|
|
mu sync.RWMutex
|
|
slug string
|
|
}
|
|
|
|
func New() Slug {
|
|
return &slug{
|
|
slug: "",
|
|
}
|
|
}
|
|
|
|
func (s *slug) String() string {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return s.slug
|
|
}
|
|
|
|
func (s *slug) Set(slug string) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.slug = slug
|
|
}
|