mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-27 12:49:03 +03:00
Add Snell protocol. Refactor MASQUE HTTP/2, Fair Queue. Update XHTTP, OpenVPN, Sudoku, Fallback. Fixes
This commit is contained in:
153
transport/snell/pool.go
Normal file
153
transport/snell/pool.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package snell
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// poolEntry holds a pooled item with its insertion time.
|
||||
|
||||
// connPool is a small connection pool with age-based eviction.
|
||||
|
||||
// milliseconds
|
||||
|
||||
// Pool is a pool of reusable snell connections.
|
||||
type Pool struct {
|
||||
pool *connPool
|
||||
}
|
||||
|
||||
func (p *Pool) Get() (net.Conn, error) {
|
||||
return p.GetContext(context.Background())
|
||||
}
|
||||
|
||||
func (p *Pool) GetContext(ctx context.Context) (net.Conn, error) {
|
||||
elm, err := p.pool.GetContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PoolConn{Snell: elm, pool: p}, nil
|
||||
}
|
||||
|
||||
func (p *Pool) Put(conn *Snell) {
|
||||
if err := HalfClose(conn); err != nil {
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
p.pool.put(conn)
|
||||
}
|
||||
|
||||
// PoolConn wraps a pooled snell connection and returns it to the pool on Close.
|
||||
type PoolConn struct {
|
||||
*Snell
|
||||
pool *Pool
|
||||
closeWriteOnce sync.Once
|
||||
closeWriteErr error
|
||||
closeOnce sync.Once
|
||||
closeErr error
|
||||
}
|
||||
|
||||
func (pc *PoolConn) Read(b []byte) (int, error) {
|
||||
n, err := pc.Snell.Read(b)
|
||||
if err == ErrZeroChunk {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (pc *PoolConn) Write(b []byte) (int, error) {
|
||||
return pc.Snell.Write(b)
|
||||
}
|
||||
|
||||
func (pc *PoolConn) CloseWrite() error {
|
||||
pc.closeWriteOnce.Do(func() {
|
||||
pc.closeWriteErr = writeZeroChunk(pc.Snell)
|
||||
})
|
||||
return pc.closeWriteErr
|
||||
}
|
||||
|
||||
func (pc *PoolConn) Close() error {
|
||||
pc.closeOnce.Do(func() {
|
||||
if err := pc.CloseWrite(); err != nil {
|
||||
pc.closeErr = err
|
||||
_ = pc.Snell.Close()
|
||||
return
|
||||
}
|
||||
_ = pc.Snell.Conn.SetReadDeadline(time.Time{})
|
||||
pc.Snell.reply = false
|
||||
pc.pool.pool.put(pc.Snell)
|
||||
})
|
||||
return pc.closeErr
|
||||
}
|
||||
|
||||
// NewPool creates a new snell connection pool using the given factory.
|
||||
func NewPool(factory func(context.Context) (*Snell, error)) *Pool {
|
||||
cp := &connPool{
|
||||
ch: make(chan *poolEntry, 10),
|
||||
factory: factory,
|
||||
maxAge: 15000,
|
||||
evict: func(item *Snell) {
|
||||
_ = item.Close()
|
||||
},
|
||||
}
|
||||
p := &Pool{pool: cp}
|
||||
runtime.SetFinalizer(p, recycle)
|
||||
return p
|
||||
}
|
||||
|
||||
type poolEntry struct {
|
||||
elm *Snell
|
||||
time time.Time
|
||||
}
|
||||
|
||||
type connPool struct {
|
||||
ch chan *poolEntry
|
||||
factory func(context.Context) (*Snell, error)
|
||||
evict func(*Snell)
|
||||
maxAge int64
|
||||
}
|
||||
|
||||
func (p *connPool) GetContext(ctx context.Context) (*Snell, error) {
|
||||
now := time.Now()
|
||||
for {
|
||||
select {
|
||||
case item := <-p.ch:
|
||||
if p.maxAge != 0 && now.Sub(item.time).Milliseconds() > p.maxAge {
|
||||
if p.evict != nil {
|
||||
p.evict(item.elm)
|
||||
}
|
||||
continue
|
||||
}
|
||||
return item.elm, nil
|
||||
default:
|
||||
return p.factory(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *connPool) put(item *Snell) {
|
||||
e := &poolEntry{
|
||||
elm: item,
|
||||
time: time.Now(),
|
||||
}
|
||||
select {
|
||||
case p.ch <- e:
|
||||
return
|
||||
default:
|
||||
if p.evict != nil {
|
||||
p.evict(item)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func recycle(p *Pool) {
|
||||
for item := range p.pool.ch {
|
||||
if p.pool.evict != nil {
|
||||
p.pool.evict(item.elm)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user