fix: StreamGunWithConn not synchronously close the incoming net.Conn

This commit is contained in:
wwqgtxx 2025-04-03 23:41:24 +08:00
parent 622d99d000
commit 7de24e26b4
6 changed files with 42 additions and 23 deletions

View file

@ -281,7 +281,7 @@ func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
epc := N.NewEnhancePacketConn(pc)
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
epc = N.NewRefPacketConn(epc, a) // add ref for autoCloseProxyAdapter
epc = N.NewRefPacketConn(epc, a) // add ref for autoCloseProxyAdapter
}
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
}

View file

@ -313,7 +313,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
}
if option.Network == "grpc" {
dialFn := func(network, addr string) (net.Conn, error) {
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(t.Base.DialOptions()...)
if len(t.option.DialerProxy) > 0 {
@ -322,7 +322,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
return nil, err
}
}
c, err := cDialer.DialContext(context.Background(), "tcp", t.addr)
c, err := cDialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error())
}

View file

@ -571,7 +571,7 @@ func NewVless(option VlessOption) (*Vless, error) {
option.HTTP2Opts.Host = append(option.HTTP2Opts.Host, "www.example.com")
}
case "grpc":
dialFn := func(network, addr string) (net.Conn, error) {
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(v.Base.DialOptions()...)
if len(v.option.DialerProxy) > 0 {
@ -580,7 +580,7 @@ func NewVless(option VlessOption) (*Vless, error) {
return nil, err
}
}
c, err := cDialer.DialContext(context.Background(), "tcp", v.addr)
c, err := cDialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}

View file

@ -478,7 +478,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
option.HTTP2Opts.Host = append(option.HTTP2Opts.Host, "www.example.com")
}
case "grpc":
dialFn := func(network, addr string) (net.Conn, error) {
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
var err error
var cDialer C.Dialer = dialer.NewDialer(v.Base.DialOptions()...)
if len(v.option.DialerProxy) > 0 {
@ -487,7 +487,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
return nil, err
}
}
c, err := cDialer.DialContext(context.Background(), "tcp", v.addr)
c, err := cDialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}

View file

@ -36,12 +36,12 @@ var defaultHeader = http.Header{
"user-agent": []string{"grpc-go/1.36.0"},
}
type DialFn = func(network, addr string) (net.Conn, error)
type DialFn = func(ctx context.Context, network, addr string) (net.Conn, error)
type Conn struct {
initFn func() (io.ReadCloser, netAddr, error)
writer io.Writer
flusher http.Flusher
initFn func() (io.ReadCloser, netAddr, error)
writer io.Writer
closer io.Closer
netAddr
reader io.ReadCloser
@ -149,8 +149,8 @@ func (g *Conn) Write(b []byte) (n int, err error) {
err = g.err
}
if g.flusher != nil {
g.flusher.Flush()
if flusher, ok := g.writer.(http.Flusher); ok {
flusher.Flush()
}
return len(b), err
@ -172,8 +172,8 @@ func (g *Conn) WriteBuffer(buffer *buf.Buffer) error {
err = g.err
}
if g.flusher != nil {
g.flusher.Flush()
if flusher, ok := g.writer.(http.Flusher); ok {
flusher.Flush()
}
return err
@ -185,14 +185,27 @@ func (g *Conn) FrontHeadroom() int {
func (g *Conn) Close() error {
g.close.Store(true)
var errorArr []error
if reader := g.reader; reader != nil {
reader.Close()
if err := reader.Close(); err != nil {
errorArr = append(errorArr, err)
}
}
if closer, ok := g.writer.(io.Closer); ok {
return closer.Close()
if err := closer.Close(); err != nil {
errorArr = append(errorArr, err)
}
}
return nil
if closer := g.closer; closer != nil {
if err := closer.Close(); err != nil {
errorArr = append(errorArr, err)
}
}
return errors.Join(errorArr...)
}
func (g *Conn) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) }
@ -212,7 +225,7 @@ func (g *Conn) SetDeadline(t time.Time) error {
func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap {
dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
pconn, err := dialFn(network, addr)
pconn, err := dialFn(ctx, network, addr)
if err != nil {
return nil, err
}
@ -327,10 +340,17 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er
}
func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) {
dialFn := func(network, addr string) (net.Conn, error) {
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
return conn, nil
}
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig)
return StreamGunWithTransport(transport, cfg)
c, err := StreamGunWithTransport(transport, cfg)
if err != nil {
return nil, err
}
if c, ok := c.(*Conn); ok { // The incoming net.Conn should be closed synchronously with the generated gun.Conn
c.closer = conn
}
return c, nil
}

View file

@ -56,8 +56,7 @@ func NewServerHandler(options ServerOption) http.Handler {
}
return request.Body, nAddr, nil
},
writer: writer,
flusher: writer.(http.Flusher),
writer: writer,
}
wrapper := &h2ConnWrapper{