mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Improve multiplex
This commit is contained in:
parent
f61c5600e0
commit
9c287094e2
@ -41,7 +41,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConne
|
||||
}
|
||||
}
|
||||
|
||||
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (N.Dialer, error) {
|
||||
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (*Client, error) {
|
||||
if !options.Enabled {
|
||||
return nil, nil
|
||||
}
|
||||
@ -120,17 +120,16 @@ func (c *Client) offer() (abstractSession, error) {
|
||||
sessions = append(sessions, element.Value)
|
||||
element = element.Next()
|
||||
}
|
||||
sLen := len(sessions)
|
||||
if sLen == 0 {
|
||||
session := common.MinBy(common.Filter(sessions, abstractSession.CanTakeNewRequest), abstractSession.NumStreams)
|
||||
if session == nil {
|
||||
return c.offerNew()
|
||||
}
|
||||
session := common.MinBy(sessions, abstractSession.NumStreams)
|
||||
numStreams := session.NumStreams()
|
||||
if numStreams == 0 {
|
||||
return session, nil
|
||||
}
|
||||
if c.maxConnections > 0 {
|
||||
if sLen >= c.maxConnections || numStreams < c.minStreams {
|
||||
if len(sessions) >= c.maxConnections || numStreams < c.minStreams {
|
||||
return session, nil
|
||||
}
|
||||
} else {
|
||||
@ -159,6 +158,15 @@ func (c *Client) offerNew() (abstractSession, error) {
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (c *Client) Reset() {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
for _, session := range c.connections.Array() {
|
||||
session.Close()
|
||||
}
|
||||
c.connections.Init()
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
|
235
common/mux/h2mux.go
Normal file
235
common/mux/h2mux.go
Normal file
@ -0,0 +1,235 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/transport/v2rayhttp"
|
||||
"github.com/sagernet/sing/common/atomic"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
const idleTimeout = 30 * time.Second
|
||||
|
||||
var _ abstractSession = (*H2MuxServerSession)(nil)
|
||||
|
||||
type H2MuxServerSession struct {
|
||||
server http2.Server
|
||||
active atomic.Int32
|
||||
conn net.Conn
|
||||
inbound chan net.Conn
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewH2MuxServer(conn net.Conn) *H2MuxServerSession {
|
||||
session := &H2MuxServerSession{
|
||||
conn: conn,
|
||||
inbound: make(chan net.Conn),
|
||||
done: make(chan struct{}),
|
||||
server: http2.Server{
|
||||
IdleTimeout: idleTimeout,
|
||||
},
|
||||
}
|
||||
go func() {
|
||||
session.server.ServeConn(conn, &http2.ServeConnOpts{
|
||||
Handler: session,
|
||||
})
|
||||
_ = session.Close()
|
||||
}()
|
||||
return session
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
s.active.Add(1)
|
||||
defer s.active.Add(-1)
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
conn := newHTTP2Wrapper(&v2rayhttp.ServerHTTPConn{
|
||||
HTTP2Conn: v2rayhttp.NewHTTPConn(request.Body, writer),
|
||||
Flusher: writer.(http.Flusher),
|
||||
})
|
||||
s.inbound <- conn
|
||||
select {
|
||||
case <-conn.done:
|
||||
case <-s.done:
|
||||
}
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) Open() (net.Conn, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) Accept() (net.Conn, error) {
|
||||
select {
|
||||
case conn := <-s.inbound:
|
||||
return conn, nil
|
||||
case <-s.done:
|
||||
return nil, os.ErrClosed
|
||||
}
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) NumStreams() int {
|
||||
return int(s.active.Load())
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) Close() error {
|
||||
select {
|
||||
case <-s.done:
|
||||
default:
|
||||
close(s.done)
|
||||
}
|
||||
return s.conn.Close()
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) IsClosed() bool {
|
||||
select {
|
||||
case <-s.done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *H2MuxServerSession) CanTakeNewRequest() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type h2MuxConnWrapper struct {
|
||||
N.ExtendedConn
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func newHTTP2Wrapper(conn net.Conn) *h2MuxConnWrapper {
|
||||
return &h2MuxConnWrapper{
|
||||
ExtendedConn: bufio.NewExtendedConn(conn),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *h2MuxConnWrapper) Write(p []byte) (n int, err error) {
|
||||
select {
|
||||
case <-w.done:
|
||||
return 0, net.ErrClosed
|
||||
default:
|
||||
}
|
||||
return w.ExtendedConn.Write(p)
|
||||
}
|
||||
|
||||
func (w *h2MuxConnWrapper) WriteBuffer(buffer *buf.Buffer) error {
|
||||
select {
|
||||
case <-w.done:
|
||||
return net.ErrClosed
|
||||
default:
|
||||
}
|
||||
return w.ExtendedConn.WriteBuffer(buffer)
|
||||
}
|
||||
|
||||
func (w *h2MuxConnWrapper) Close() error {
|
||||
select {
|
||||
case <-w.done:
|
||||
default:
|
||||
close(w.done)
|
||||
}
|
||||
return w.ExtendedConn.Close()
|
||||
}
|
||||
|
||||
func (w *h2MuxConnWrapper) Upstream() any {
|
||||
return w.ExtendedConn
|
||||
}
|
||||
|
||||
var _ abstractSession = (*H2MuxClientSession)(nil)
|
||||
|
||||
type H2MuxClientSession struct {
|
||||
transport *http2.Transport
|
||||
clientConn *http2.ClientConn
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewH2MuxClient(conn net.Conn) (*H2MuxClientSession, error) {
|
||||
session := &H2MuxClientSession{
|
||||
transport: &http2.Transport{
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
return conn, nil
|
||||
},
|
||||
ReadIdleTimeout: idleTimeout,
|
||||
},
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
session.transport.ConnPool = session
|
||||
clientConn, err := session.transport.NewClientConn(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
session.clientConn = clientConn
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) GetClientConn(req *http.Request, addr string) (*http2.ClientConn, error) {
|
||||
return s.clientConn, nil
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) MarkDead(conn *http2.ClientConn) {
|
||||
s.Close()
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) Open() (net.Conn, error) {
|
||||
pipeInReader, pipeInWriter := io.Pipe()
|
||||
request := &http.Request{
|
||||
Method: http.MethodConnect,
|
||||
Body: pipeInReader,
|
||||
URL: &url.URL{Scheme: "https", Host: "localhost"},
|
||||
}
|
||||
conn := v2rayhttp.NewLateHTTPConn(pipeInWriter)
|
||||
go func() {
|
||||
response, err := s.transport.RoundTrip(request)
|
||||
if err != nil {
|
||||
conn.Setup(nil, err)
|
||||
} else if response.StatusCode != 200 {
|
||||
response.Body.Close()
|
||||
conn.Setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status))
|
||||
} else {
|
||||
conn.Setup(response.Body, nil)
|
||||
}
|
||||
}()
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) Accept() (net.Conn, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) NumStreams() int {
|
||||
return s.clientConn.State().StreamsActive
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) Close() error {
|
||||
select {
|
||||
case <-s.done:
|
||||
default:
|
||||
close(s.done)
|
||||
}
|
||||
return s.clientConn.Close()
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) IsClosed() bool {
|
||||
select {
|
||||
case <-s.done:
|
||||
return true
|
||||
default:
|
||||
}
|
||||
return s.clientConn.State().Closed
|
||||
}
|
||||
|
||||
func (s *H2MuxClientSession) CanTakeNewRequest() bool {
|
||||
return s.clientConn.CanTakeNewRequest()
|
||||
}
|
@ -25,6 +25,7 @@ var Destination = M.Socksaddr{
|
||||
const (
|
||||
ProtocolSMux Protocol = iota
|
||||
ProtocolYAMux
|
||||
ProtocolH2Mux
|
||||
)
|
||||
|
||||
type Protocol byte
|
||||
@ -35,8 +36,10 @@ func ParseProtocol(name string) (Protocol, error) {
|
||||
return ProtocolSMux, nil
|
||||
case "yamux":
|
||||
return ProtocolYAMux, nil
|
||||
case "h2mux":
|
||||
return ProtocolH2Mux, nil
|
||||
default:
|
||||
return ProtocolYAMux, E.New("unknown multiplex protocol: ", name)
|
||||
return ProtocolSMux, E.New("unknown multiplex protocol: ", name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +52,13 @@ func (p Protocol) newServer(conn net.Conn) (abstractSession, error) {
|
||||
}
|
||||
return &smuxSession{session}, nil
|
||||
case ProtocolYAMux:
|
||||
return yamux.Server(conn, yaMuxConfig())
|
||||
session, err := yamux.Server(conn, yaMuxConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &yamuxSession{session}, nil
|
||||
case ProtocolH2Mux:
|
||||
return NewH2MuxServer(conn), nil
|
||||
default:
|
||||
panic("unknown protocol")
|
||||
}
|
||||
@ -64,7 +73,13 @@ func (p Protocol) newClient(conn net.Conn) (abstractSession, error) {
|
||||
}
|
||||
return &smuxSession{session}, nil
|
||||
case ProtocolYAMux:
|
||||
return yamux.Client(conn, yaMuxConfig())
|
||||
session, err := yamux.Client(conn, yaMuxConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &yamuxSession{session}, nil
|
||||
case ProtocolH2Mux:
|
||||
return NewH2MuxClient(conn)
|
||||
default:
|
||||
panic("unknown protocol")
|
||||
}
|
||||
@ -90,6 +105,8 @@ func (p Protocol) String() string {
|
||||
return "smux"
|
||||
case ProtocolYAMux:
|
||||
return "yamux"
|
||||
case ProtocolH2Mux:
|
||||
return "h2mux"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
@ -115,9 +132,6 @@ func ReadRequest(reader io.Reader) (*Request, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if protocol > byte(ProtocolYAMux) {
|
||||
return nil, E.New("unsupported protocol: ", protocol)
|
||||
}
|
||||
return &Request{Protocol: Protocol(protocol)}, nil
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/smux"
|
||||
|
||||
"github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type abstractSession interface {
|
||||
@ -17,6 +19,7 @@ type abstractSession interface {
|
||||
NumStreams() int
|
||||
Close() error
|
||||
IsClosed() bool
|
||||
CanTakeNewRequest() bool
|
||||
}
|
||||
|
||||
var _ abstractSession = (*smuxSession)(nil)
|
||||
@ -33,6 +36,18 @@ func (s *smuxSession) Accept() (net.Conn, error) {
|
||||
return s.AcceptStream()
|
||||
}
|
||||
|
||||
func (s *smuxSession) CanTakeNewRequest() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type yamuxSession struct {
|
||||
*yamux.Session
|
||||
}
|
||||
|
||||
func (y *yamuxSession) CanTakeNewRequest() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type protocolConn struct {
|
||||
net.Conn
|
||||
protocol Protocol
|
||||
|
@ -28,6 +28,7 @@ Multiplex protocol.
|
||||
|----------|------------------------------------|
|
||||
| smux | https://github.com/xtaci/smux |
|
||||
| yamux | https://github.com/hashicorp/yamux |
|
||||
| h2mux | https://golang.org/x/net/http2 |
|
||||
|
||||
SMux is used by default.
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
|-------|------------------------------------|
|
||||
| smux | https://github.com/xtaci/smux |
|
||||
| yamux | https://github.com/hashicorp/yamux |
|
||||
| h2mux | https://golang.org/x/net/http2 |
|
||||
|
||||
默认使用 SMux。
|
||||
|
||||
|
@ -30,7 +30,7 @@ type Shadowsocks struct {
|
||||
serverAddr M.Socksaddr
|
||||
plugin sip003.Plugin
|
||||
uotClient *uot.Client
|
||||
multiplexDialer N.Dialer
|
||||
multiplexDialer *mux.Client
|
||||
}
|
||||
|
||||
func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) {
|
||||
@ -127,8 +127,15 @@ func (h *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn
|
||||
return NewPacketConnection(ctx, h, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *Shadowsocks) InterfaceUpdated() error {
|
||||
if h.multiplexDialer != nil {
|
||||
h.multiplexDialer.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Shadowsocks) Close() error {
|
||||
return common.Close(h.multiplexDialer)
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer))
|
||||
}
|
||||
|
||||
var _ N.Dialer = (*shadowsocksDialer)(nil)
|
||||
|
@ -27,7 +27,7 @@ type Trojan struct {
|
||||
dialer N.Dialer
|
||||
serverAddr M.Socksaddr
|
||||
key [56]byte
|
||||
multiplexDialer N.Dialer
|
||||
multiplexDialer *mux.Client
|
||||
tlsConfig tls.Config
|
||||
transport adapter.V2RayClientTransport
|
||||
}
|
||||
@ -103,8 +103,15 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met
|
||||
return NewPacketConnection(ctx, h, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *Trojan) InterfaceUpdated() error {
|
||||
if h.multiplexDialer != nil {
|
||||
h.multiplexDialer.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Trojan) Close() error {
|
||||
return common.Close(h.multiplexDialer, h.transport)
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||
}
|
||||
|
||||
type trojanDialer Trojan
|
||||
|
@ -27,7 +27,7 @@ type VMess struct {
|
||||
dialer N.Dialer
|
||||
client *vmess.Client
|
||||
serverAddr M.Socksaddr
|
||||
multiplexDialer N.Dialer
|
||||
multiplexDialer *mux.Client
|
||||
tlsConfig tls.Config
|
||||
transport adapter.V2RayClientTransport
|
||||
packetAddr bool
|
||||
@ -97,8 +97,15 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func (h *VMess) InterfaceUpdated() error {
|
||||
if h.multiplexDialer != nil {
|
||||
h.multiplexDialer.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *VMess) Close() error {
|
||||
return common.Close(h.multiplexDialer, h.transport)
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||
}
|
||||
|
||||
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
|
19
test/go.mod
19
test/go.mod
@ -9,9 +9,9 @@ replace github.com/sagernet/sing-box => ../
|
||||
require (
|
||||
github.com/docker/docker v20.10.18+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d
|
||||
github.com/gofrs/uuid/v5 v5.0.0
|
||||
github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507
|
||||
github.com/spyzhov/ajson v0.7.1
|
||||
github.com/stretchr/testify v1.8.2
|
||||
go.uber.org/goleak v1.2.0
|
||||
@ -36,7 +36,6 @@ require (
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/go-chi/render v1.0.2 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/gofrs/uuid/v5 v5.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
@ -51,7 +50,7 @@ require (
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
github.com/mholt/acmez v1.1.0 // indirect
|
||||
github.com/miekg/dns v1.1.53 // indirect
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
github.com/ooni/go-libtor v1.1.7 // indirect
|
||||
@ -71,10 +70,10 @@ require (
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.0 // indirect
|
||||
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.3 // indirect
|
||||
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect
|
||||
github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
|
||||
@ -103,5 +102,3 @@ require (
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
)
|
||||
|
||||
//replace github.com/sagernet/sing => ../../sing
|
||||
|
30
test/go.sum
30
test/go.sum
@ -43,8 +43,6 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
|
||||
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
@ -84,8 +82,8 @@ github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
||||
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c h1:RC8WMpjonrBfyAh6VN/POIPtYD5tRAq0qMqCRjQNK+g=
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
@ -128,18 +126,18 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31 h1:qgq8jeY/rbnY9NwYXByO//AP0ByIxnsKUxQx1tOB3W0=
|
||||
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 h1:UDSeJZ2xB3dj1lySnM5LpF48dGlphGstw2BqtkJwcZI=
|
||||
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322/go.mod h1:2wjxSr1Gbecq9A0ESA9cnR399tQTcpCZEOGytekb+qI=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d h1:UUxtLujzp5jmtOXqXpSOGvHwHSZcBveKVDzRJ4GlnFU=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d/go.mod h1:Co3PJXcaZoLwHGBfT0rbSnn9C7ywc41zVYWtDeoeI/Q=
|
||||
github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 h1:aPb0T2HQRTG2t7fEwLvFLZSXmhmnBh+SMs2NufhmrsI=
|
||||
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302/go.mod h1:bvcVzlf9q9dgxt8qKluW+zOXCFoN1+SpBG3sHTq8/9Q=
|
||||
github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
|
||||
github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
|
||||
github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1 h1:CdzNL25lzfVo0NMeghPqsupNsWvkzrbrUt5t8DoDPcQ=
|
||||
github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
|
||||
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507/go.mod h1:UJjvQGw0lyYaDGIDvUraL16fwaAEH1WFw1Y6sUcMPog=
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
|
||||
github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae h1:yNKqOPKX9GnnEMvnm9ZVsIyMuMsU0x6uCJQMwAhGafA=
|
||||
github.com/sagernet/sing-tun v0.1.4-0.20230420014302-db67add64fae/go.mod h1:F7hYqaFR7RRs0aLj3gHDt+v18mpD5apJwPUfTd4e5HQ=
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||
|
@ -29,6 +29,10 @@ func TestShadowsocksMux(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShadowsockH2Mux(t *testing.T) {
|
||||
testShadowsocksMux(t, mux.ProtocolH2Mux.String())
|
||||
}
|
||||
|
||||
func testShadowsocksMux(t *testing.T, protocol string) {
|
||||
method := shadowaead_2022.List[0]
|
||||
password := mkBase64(t, 16)
|
||||
|
@ -19,7 +19,7 @@ func TestUDPNatClose(t *testing.T) {
|
||||
defer cancel()
|
||||
connCtx, connCancel := common.ContextWithCancelCause(context.Background())
|
||||
defer connCancel(net.ErrClosed)
|
||||
service := udpnat.New[int](ctx, 1, &testUDPNatCloseHandler{connCancel})
|
||||
service := udpnat.New[int](1, &testUDPNatCloseHandler{connCancel})
|
||||
service.NewPacket(ctx, 0, buf.As([]byte("Hello")), M.Metadata{}, func(natConn N.PacketConn) N.PacketWriter {
|
||||
return &testPacketWriter{}
|
||||
})
|
||||
|
@ -199,13 +199,13 @@ func (c *HTTP2Conn) NeedAdditionalReadDeadline() bool {
|
||||
|
||||
type ServerHTTPConn struct {
|
||||
HTTP2Conn
|
||||
flusher http.Flusher
|
||||
Flusher http.Flusher
|
||||
}
|
||||
|
||||
func (c *ServerHTTPConn) Write(b []byte) (n int, err error) {
|
||||
n, err = c.writer.Write(b)
|
||||
if err == nil {
|
||||
c.flusher.Flush()
|
||||
c.Flusher.Flush()
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -246,6 +246,11 @@ func (w *HTTP2ConnWrapper) CloseWrapper() {
|
||||
w.closed = true
|
||||
}
|
||||
|
||||
func (w *HTTP2ConnWrapper) Close() error {
|
||||
w.CloseWrapper()
|
||||
return w.ExtendedConn.Close()
|
||||
}
|
||||
|
||||
func (w *HTTP2ConnWrapper) Upstream() any {
|
||||
return w.ExtendedConn
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user