mirror of
https://github.com/soypat/lneto.git
synced 2026-08-19 06:04:01 +00:00
HTTP and Listener improvements and bugfixes (#17)
* listener revamp * improvements to conn lifetimes
This commit is contained in:
+27
-16
@@ -15,6 +15,7 @@ type TCPPool struct {
|
||||
mu sync.Mutex
|
||||
naqcuired int
|
||||
conns []tcp.Conn
|
||||
userData []any
|
||||
acquiredAt []time.Time
|
||||
closingAt []time.Time
|
||||
abortedAt []time.Time
|
||||
@@ -31,9 +32,11 @@ func _() {
|
||||
}
|
||||
|
||||
type TCPPoolConfig struct {
|
||||
PoolSize int
|
||||
QueueSize int
|
||||
BufferSize int
|
||||
PoolSize int
|
||||
QueueSize int
|
||||
TxBufSize int
|
||||
RxBufSize int
|
||||
|
||||
Logger *slog.Logger
|
||||
ConnLogger *slog.Logger
|
||||
Now func() time.Time
|
||||
@@ -43,6 +46,8 @@ type TCPPoolConfig struct {
|
||||
// ClosingTimeout sets the timeout for a TCP connection to close and be returned to Pool.
|
||||
// If the connection is not closed in this time it will be aborted by the pool.
|
||||
ClosingTimeout time.Duration
|
||||
// NewUserData is used to create user data used for each individual TCP connection and returned on GetTCP.
|
||||
NewUserData func() any
|
||||
}
|
||||
|
||||
func NewTCPPool(cfg TCPPoolConfig) (*TCPPool, error) {
|
||||
@@ -50,29 +55,34 @@ func NewTCPPool(cfg TCPPoolConfig) (*TCPPool, error) {
|
||||
return nil, errors.New("invalid timeout")
|
||||
}
|
||||
n := cfg.PoolSize
|
||||
bufsize := cfg.BufferSize
|
||||
pool := &TCPPool{
|
||||
acquiredAt: make([]time.Time, n),
|
||||
closingAt: make([]time.Time, n),
|
||||
abortedAt: make([]time.Time, n),
|
||||
conns: make([]tcp.Conn, n),
|
||||
userData: make([]any, n),
|
||||
_now: cfg.Now,
|
||||
estbTimeout: cfg.EstablishedTimeout,
|
||||
closingTimeout: cfg.ClosingTimeout,
|
||||
logger: cfg.Logger,
|
||||
}
|
||||
bufSpace := make([]byte, 2*n*bufsize)
|
||||
allocPerConn := cfg.TxBufSize + cfg.RxBufSize
|
||||
bufSpace := make([]byte, n*allocPerConn)
|
||||
for i := range pool.conns {
|
||||
bufoff := 2 * i * bufsize
|
||||
bufoff := i * allocPerConn
|
||||
txOff := bufoff + cfg.RxBufSize
|
||||
err := pool.conns[i].Configure(tcp.ConnConfig{
|
||||
RxBuf: bufSpace[bufoff : bufoff+bufsize],
|
||||
TxBuf: bufSpace[bufoff+bufsize : bufoff+2*bufsize],
|
||||
RxBuf: bufSpace[bufoff:txOff],
|
||||
TxBuf: bufSpace[txOff : txOff+cfg.TxBufSize],
|
||||
TxPacketQueueSize: cfg.QueueSize,
|
||||
Logger: cfg.ConnLogger,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cfg.NewUserData != nil {
|
||||
pool.userData[i] = cfg.NewUserData()
|
||||
}
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
@@ -83,7 +93,7 @@ func (p *TCPPool) NumberOfAcquired() int {
|
||||
return p.naqcuired
|
||||
}
|
||||
|
||||
func (p *TCPPool) GetTCP() (*tcp.Conn, tcp.Value) {
|
||||
func (p *TCPPool) GetTCP() (conn *tcp.Conn, userData any, SuggestedISS tcp.Value) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.debug("TCPPool:get")
|
||||
@@ -92,10 +102,10 @@ func (p *TCPPool) GetTCP() (*tcp.Conn, tcp.Value) {
|
||||
p.acquiredAt[i] = p.now()
|
||||
p.nextISS += 1000
|
||||
p.naqcuired++
|
||||
return &p.conns[i], p.nextISS
|
||||
return &p.conns[i], p.userData[i], p.nextISS
|
||||
}
|
||||
}
|
||||
return nil, 0
|
||||
return nil, nil, 0
|
||||
}
|
||||
|
||||
func (p *TCPPool) PutTCP(conn *tcp.Conn) {
|
||||
@@ -122,7 +132,8 @@ func (p *TCPPool) CheckTimeouts() {
|
||||
defer p.mu.Unlock()
|
||||
p.debug("TCPPool:checktimeouts", slog.Int("acq", p.naqcuired))
|
||||
for i := range p.conns {
|
||||
st := p.conns[i].State()
|
||||
conn := &p.conns[i]
|
||||
st := conn.State()
|
||||
if st == tcp.StateEstablished {
|
||||
continue
|
||||
}
|
||||
@@ -134,18 +145,18 @@ func (p *TCPPool) CheckTimeouts() {
|
||||
} else if st.IsPreestablished() && p.since(acq) > p.estbTimeout {
|
||||
// Was acquired and did not reach establishment state so we close.
|
||||
// This is part of a syn-flood defense mechanism.
|
||||
p.conns[i].Close()
|
||||
conn.Close()
|
||||
} else if st.IsClosed() || st.IsClosing() {
|
||||
// p.mu.Lock()
|
||||
if p.closingAt[i].IsZero() {
|
||||
p.closingAt[i] = p.now()
|
||||
} else if p.abortedAt[i].IsZero() && p.since(p.closingAt[i]) > p.closingTimeout {
|
||||
p.abortedAt[i] = p.now()
|
||||
p.conns[i].Abort()
|
||||
} else if p.since(p.abortedAt[i]) > 10*time.Second {
|
||||
conn.Abort()
|
||||
} else if !p.abortedAt[i].IsZero() && p.since(p.abortedAt[i]) > 10*time.Second {
|
||||
println("connection aborted and still not returned to TCPPool")
|
||||
println("source", conn.LocalPort(), "remote", conn.RemotePort(), "state", conn.State().String())
|
||||
}
|
||||
// p.mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user