Fix gLazyConn race

This commit is contained in:
世界 2025-06-13 11:35:09 +08:00
parent 494b0ef858
commit 3df19f464e
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -6,6 +6,7 @@ import (
"context" "context"
"net" "net"
"os" "os"
"sync"
"time" "time"
"github.com/sagernet/gvisor/pkg/tcpip" "github.com/sagernet/gvisor/pkg/tcpip"
@ -17,19 +18,25 @@ import (
) )
type gLazyConn struct { type gLazyConn struct {
tcpConn *gonet.TCPConn tcpConn *gonet.TCPConn
parentCtx context.Context parentCtx context.Context
stack *stack.Stack stack *stack.Stack
request *tcp.ForwarderRequest request *tcp.ForwarderRequest
localAddr net.Addr localAddr net.Addr
remoteAddr net.Addr remoteAddr net.Addr
handshakeDone bool handshakeAccess sync.Mutex
handshakeErr error handshakeDone bool
handshakeErr error
} }
func (c *gLazyConn) HandshakeContext(ctx context.Context) error { func (c *gLazyConn) HandshakeContext(ctx context.Context) error {
if c.handshakeDone { if c.handshakeDone {
return nil return c.handshakeErr
}
c.handshakeAccess.Lock()
defer c.handshakeAccess.Unlock()
if c.handshakeDone {
return c.handshakeErr
} }
defer func() { defer func() {
c.handshakeDone = true c.handshakeDone = true
@ -64,6 +71,11 @@ func (c *gLazyConn) HandshakeContext(ctx context.Context) error {
} }
func (c *gLazyConn) HandshakeFailure(err error) error { func (c *gLazyConn) HandshakeFailure(err error) error {
if c.handshakeDone {
return os.ErrInvalid
}
c.handshakeAccess.Lock()
defer c.handshakeAccess.Unlock()
if c.handshakeDone { if c.handshakeDone {
return os.ErrInvalid return os.ErrInvalid
} }
@ -78,25 +90,17 @@ func (c *gLazyConn) HandshakeSuccess() error {
} }
func (c *gLazyConn) Read(b []byte) (n int, err error) { func (c *gLazyConn) Read(b []byte) (n int, err error) {
if !c.handshakeDone { err = c.HandshakeContext(context.Background())
err = c.HandshakeContext(context.Background()) if err != nil {
if err != nil { return
return
}
} else if c.handshakeErr != nil {
return 0, c.handshakeErr
} }
return c.tcpConn.Read(b) return c.tcpConn.Read(b)
} }
func (c *gLazyConn) Write(b []byte) (n int, err error) { func (c *gLazyConn) Write(b []byte) (n int, err error) {
if !c.handshakeDone { err = c.HandshakeContext(context.Background())
err = c.HandshakeContext(context.Background()) if err != nil {
if err != nil { return
return
}
} else if c.handshakeErr != nil {
return 0, c.handshakeErr
} }
return c.tcpConn.Write(b) return c.tcpConn.Write(b)
} }
@ -110,79 +114,80 @@ func (c *gLazyConn) RemoteAddr() net.Addr {
} }
func (c *gLazyConn) SetDeadline(t time.Time) error { func (c *gLazyConn) SetDeadline(t time.Time) error {
if !c.handshakeDone { err := c.HandshakeContext(context.Background())
err := c.HandshakeContext(context.Background()) if err != nil {
if err != nil { return err
return err
}
} else if c.handshakeErr != nil {
return c.handshakeErr
} }
return c.tcpConn.SetDeadline(t) return c.tcpConn.SetDeadline(t)
} }
func (c *gLazyConn) SetReadDeadline(t time.Time) error { func (c *gLazyConn) SetReadDeadline(t time.Time) error {
if !c.handshakeDone { err := c.HandshakeContext(context.Background())
err := c.HandshakeContext(context.Background()) if err != nil {
if err != nil { return err
return err
}
} else if c.handshakeErr != nil {
return c.handshakeErr
} }
return c.tcpConn.SetReadDeadline(t) return c.tcpConn.SetReadDeadline(t)
} }
func (c *gLazyConn) SetWriteDeadline(t time.Time) error { func (c *gLazyConn) SetWriteDeadline(t time.Time) error {
if !c.handshakeDone { err := c.HandshakeContext(context.Background())
err := c.HandshakeContext(context.Background()) if err != nil {
if err != nil { return err
return err
}
} else if c.handshakeErr != nil {
return c.handshakeErr
} }
return c.tcpConn.SetWriteDeadline(t) return c.tcpConn.SetWriteDeadline(t)
} }
func (c *gLazyConn) Close() error { func (c *gLazyConn) Close() error {
if !c.handshakeDone { if !c.handshakeDone {
c.request.Complete(true) c.handshakeAccess.Lock()
c.handshakeErr = net.ErrClosed if !c.handshakeDone {
return nil c.request.Complete(true)
} else if c.handshakeErr != nil { c.handshakeErr = net.ErrClosed
return nil c.handshakeDone = true
return nil
}
c.handshakeAccess.Unlock()
} }
return c.tcpConn.Close() return c.tcpConn.Close()
} }
func (c *gLazyConn) CloseRead() error { func (c *gLazyConn) CloseRead() error {
if !c.handshakeDone { if !c.handshakeDone {
c.request.Complete(true) c.handshakeAccess.Lock()
c.handshakeErr = net.ErrClosed if !c.handshakeDone {
return nil c.request.Complete(true)
} else if c.handshakeErr != nil { c.handshakeErr = net.ErrClosed
return nil c.handshakeDone = true
return nil
}
c.handshakeAccess.Unlock()
} }
return c.tcpConn.CloseRead() return c.tcpConn.CloseRead()
} }
func (c *gLazyConn) CloseWrite() error { func (c *gLazyConn) CloseWrite() error {
if !c.handshakeDone { if !c.handshakeDone {
c.request.Complete(true) c.handshakeAccess.Lock()
c.handshakeErr = net.ErrClosed if !c.handshakeDone {
return nil c.request.Complete(true)
} else if c.handshakeErr != nil { c.handshakeErr = net.ErrClosed
return nil c.handshakeDone = true
return nil
}
c.handshakeAccess.Unlock()
} }
return c.tcpConn.CloseRead() return c.tcpConn.CloseRead()
} }
func (c *gLazyConn) ReaderReplaceable() bool { func (c *gLazyConn) ReaderReplaceable() bool {
c.handshakeAccess.Lock()
defer c.handshakeAccess.Unlock()
return c.handshakeDone && c.handshakeErr == nil return c.handshakeDone && c.handshakeErr == nil
} }
func (c *gLazyConn) WriterReplaceable() bool { func (c *gLazyConn) WriterReplaceable() bool {
c.handshakeAccess.Lock()
defer c.handshakeAccess.Unlock()
return c.handshakeDone && c.handshakeErr == nil return c.handshakeDone && c.handshakeErr == nil
} }