diff --git a/common/mux/client.go b/common/mux/client.go index c66dd7ae..55ad3138 100644 --- a/common/mux/client.go +++ b/common/mux/client.go @@ -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() diff --git a/common/mux/h2mux.go b/common/mux/h2mux.go new file mode 100644 index 00000000..1449dcc7 --- /dev/null +++ b/common/mux/h2mux.go @@ -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() +} diff --git a/common/mux/protocol.go b/common/mux/protocol.go index 26abebb1..594d66ca 100644 --- a/common/mux/protocol.go +++ b/common/mux/protocol.go @@ -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 } diff --git a/common/mux/session.go b/common/mux/session.go index 04d1426e..fa91dc44 100644 --- a/common/mux/session.go +++ b/common/mux/session.go @@ -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 diff --git a/docs/configuration/shared/multiplex.md b/docs/configuration/shared/multiplex.md index 02e3c90a..e2962070 100644 --- a/docs/configuration/shared/multiplex.md +++ b/docs/configuration/shared/multiplex.md @@ -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. diff --git a/docs/configuration/shared/multiplex.zh.md b/docs/configuration/shared/multiplex.zh.md index c336e8ec..0a9fa16f 100644 --- a/docs/configuration/shared/multiplex.zh.md +++ b/docs/configuration/shared/multiplex.zh.md @@ -28,6 +28,7 @@ |-------|------------------------------------| | smux | https://github.com/xtaci/smux | | yamux | https://github.com/hashicorp/yamux | +| h2mux | https://golang.org/x/net/http2 | 默认使用 SMux。 diff --git a/outbound/shadowsocks.go b/outbound/shadowsocks.go index e196c03a..08c0a688 100644 --- a/outbound/shadowsocks.go +++ b/outbound/shadowsocks.go @@ -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) diff --git a/outbound/trojan.go b/outbound/trojan.go index 2e4bc96a..4a72b22d 100644 --- a/outbound/trojan.go +++ b/outbound/trojan.go @@ -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 diff --git a/outbound/vmess.go b/outbound/vmess.go index cb6ba40f..e0030bf3 100644 --- a/outbound/vmess.go +++ b/outbound/vmess.go @@ -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) { diff --git a/test/go.mod b/test/go.mod index 86a55171..bb338fd8 100644 --- a/test/go.mod +++ b/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 diff --git a/test/go.sum b/test/go.sum index 63a47ae1..f345989a 100644 --- a/test/go.sum +++ b/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= diff --git a/test/mux_test.go b/test/mux_test.go index 32e32b76..f77ac8c3 100644 --- a/test/mux_test.go +++ b/test/mux_test.go @@ -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) diff --git a/test/udpnat_test.go b/test/udpnat_test.go index b4db86ae..0956d812 100644 --- a/test/udpnat_test.go +++ b/test/udpnat_test.go @@ -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{} }) diff --git a/transport/v2rayhttp/conn.go b/transport/v2rayhttp/conn.go index 3e1716d1..27f88134 100644 --- a/transport/v2rayhttp/conn.go +++ b/transport/v2rayhttp/conn.go @@ -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 }