Fix leaks and add test

This commit is contained in:
世界 2022-09-23 13:14:31 +08:00
parent 9856b73cb5
commit 407509c985
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
19 changed files with 167 additions and 59 deletions

View file

@ -14,6 +14,7 @@ import (
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/common/task"
)
func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error {
@ -25,14 +26,21 @@ func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Ha
if err != nil {
return err
}
var stream net.Conn
for {
stream, err = session.Accept()
if err != nil {
return err
var group task.Group
group.Append0(func(ctx context.Context) error {
var stream net.Conn
for {
stream, err = session.Accept()
if err != nil {
return err
}
go newConnection(ctx, router, errorHandler, logger, stream, metadata)
}
go newConnection(ctx, router, errorHandler, logger, stream, metadata)
}
})
group.Cleanup(func() {
session.Close()
})
return group.Run(ctx)
}
func newConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, stream net.Conn, metadata adapter.InboundContext) {

2
go.mod
View file

@ -27,7 +27,7 @@ require (
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
github.com/spf13/cobra v1.5.0

4
go.sum
View file

@ -153,8 +153,8 @@ github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDe
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 h1:DOQQXQbB2gq4n2FuMHrL07HRs2naCCsuiu/9l1JFb9A=
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM=
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f h1:xyJ3Wbibcug4DxLi/FCHX2Td667SfieyZv645b8+eEE=
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 h1:w7JlEa4xHXuuPTL3Opb+Z5f/l66SYi54rSfobzuxSF8=
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=

View file

@ -38,6 +38,7 @@ type Hysteria struct {
recvBPS uint64
connAccess sync.Mutex
conn quic.Connection
rawConn net.Conn
udpAccess sync.RWMutex
udpSessions map[uint32]chan *hysteria.UDPMessage
udpDefragger hysteria.Defragger
@ -149,7 +150,6 @@ func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) {
if err != nil {
return nil, err
}
h.conn = conn
if common.Contains(h.network, N.NetworkUDP) {
for _, session := range h.udpSessions {
close(session)
@ -201,6 +201,8 @@ func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) {
return nil, E.New("remote error: ", serverHello.Message)
}
quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS)))
h.conn = quicConn
h.rawConn = udpConn
return quicConn, nil
}
@ -240,6 +242,7 @@ func (h *Hysteria) Close() error {
defer h.udpAccess.Unlock()
if h.conn != nil {
h.conn.CloseWithError(0, "")
h.rawConn.Close()
}
for _, session := range h.udpSessions {
close(session)

View file

@ -103,6 +103,10 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met
return NewPacketConnection(ctx, h, conn, metadata)
}
func (h *Trojan) Close() error {
return common.Close(h.multiplexDialer, h.transport)
}
type trojanDialer Trojan
func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {

View file

@ -74,10 +74,6 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
return outbound, nil
}
func (h *VLESS) Close() error {
return common.Close(h.transport)
}
func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag
@ -145,3 +141,7 @@ func (h *VLESS) NewConnection(ctx context.Context, conn net.Conn, metadata adapt
func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return NewPacketConnection(ctx, h, conn, metadata)
}
func (h *VLESS) Close() error {
return common.Close(h.transport)
}

View file

@ -96,7 +96,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
}
func (h *VMess) Close() error {
return common.Close(h.transport)
return common.Close(h.multiplexDialer, h.transport)
}
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {

View file

@ -162,9 +162,8 @@ func (w *WireGuard) Start() error {
}
func (w *WireGuard) Close() error {
return common.Close(
w.tunDevice,
common.PtrOrNil(w.device),
common.PtrOrNil(w.bind),
)
if w.device != nil {
w.device.Close()
}
return common.Close(w.tunDevice)
}

View file

@ -15,9 +15,14 @@ import (
"github.com/sagernet/sing/protocol/socks"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
)
func startInstance(t *testing.T, options option.Options) {
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}
func startInstance(t *testing.T, options option.Options) *box.Box {
if debug.Enabled {
options.Log = &option.LogOptions{
Level: "trace",
@ -27,10 +32,12 @@ func startInstance(t *testing.T, options option.Options) {
Level: "warning",
}
}
// ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
var instance *box.Box
var err error
for retry := 0; retry < 3; retry++ {
instance, err = box.New(context.Background(), options)
instance, err = box.New(ctx, options)
require.NoError(t, err)
err = instance.Start()
if err != nil {
@ -42,7 +49,9 @@ func startInstance(t *testing.T, options option.Options) {
require.NoError(t, err)
t.Cleanup(func() {
instance.Close()
cancel()
})
return instance
}
func testSuit(t *testing.T, clientPort uint16, testPort uint16) {

View file

@ -7,7 +7,6 @@ import (
"errors"
"io"
"net"
"net/http"
_ "net/http/pprof"
"net/netip"
"sync"
@ -101,12 +100,6 @@ func init() {
io.Copy(io.Discard, imageStream)
}
go func() {
err = http.ListenAndServe("0.0.0.0:8965", nil)
if err != nil {
log.Debug(err)
}
}()
}
func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) {

View file

@ -10,10 +10,11 @@ require (
github.com/docker/docker v20.10.18+incompatible
github.com/docker/go-connections v0.4.0
github.com/gofrs/uuid v4.3.0+incompatible
github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/spyzhov/ajson v0.7.1
github.com/stretchr/testify v1.8.0
go.uber.org/goleak v1.2.0
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
)
@ -67,8 +68,8 @@ require (
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b // indirect
github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617 // indirect
github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d // indirect
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 // indirect
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 // indirect
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
@ -78,7 +79,7 @@ require (
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.22.0 // indirect
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220913120320-3275c407cedc // indirect

View file

@ -165,16 +165,16 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea h1:ZAWvZdeByPBBz3Vs+w3Erbh+DDo7D4biokoPhXl0nNU=
github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f h1:GX416thAwyc0vHBOal/qplvdhFgYO2dHD5GqADCJ0Ig=
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b h1:cXCMNJ9heZ+c6l+qUcku60x9KyXo4SOAaJfg/6spOmU=
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617 h1:fNTNmylhB/UjoBLusmrFu2B1fat4OCkDkQXTgrE7ZsE=
github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM=
github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d h1:/GNWxSrQj4chFYk2jahIXNPdvUa9DW8IdgyqYFbq9oQ=
github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0=
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 h1:DOQQXQbB2gq4n2FuMHrL07HRs2naCCsuiu/9l1JFb9A=
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM=
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 h1:w7JlEa4xHXuuPTL3Opb+Z5f/l66SYi54rSfobzuxSF8=
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
@ -205,8 +205,9 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
@ -220,8 +221,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
@ -229,6 +230,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=

View file

@ -107,3 +107,64 @@ func TestMuxCoolClient(t *testing.T) {
})
testSuit(t, clientPort, testPort)
}
func TestMuxCoolSelf(t *testing.T) {
user := newUUID()
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.ListenAddress(netip.IPv4Unspecified()),
ListenPort: clientPort,
},
},
},
{
Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.ListenAddress(netip.IPv4Unspecified()),
ListenPort: serverPort,
},
Users: []option.VMessUser{
{
Name: "sekai",
UUID: user.String(),
},
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeDirect,
},
{
Type: C.TypeVMess,
Tag: "vmess-out",
VMessOptions: option.VMessOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
UUID: user.String(),
PacketEncoding: "xudp",
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"},
Outbound: "vmess-out",
},
},
},
},
})
testSuit(t, clientPort, testPort)
}

View file

@ -17,6 +17,10 @@ var muxProtocols = []mux.Protocol{
mux.ProtocolSMux,
}
func TestVMessSMux(t *testing.T) {
testVMessMux(t, mux.ProtocolSMux.String())
}
func TestShadowsocksMux(t *testing.T) {
for _, protocol := range muxProtocols {
t.Run(protocol.String(), func(t *testing.T) {
@ -25,14 +29,6 @@ func TestShadowsocksMux(t *testing.T) {
}
}
func TestVMessMux(t *testing.T) {
for _, protocol := range muxProtocols {
t.Run(protocol.String(), func(t *testing.T) {
testVMessMux(t, protocol.String())
})
}
}
func testShadowsocksMux(t *testing.T, protocol string) {
method := shadowaead_2022.List[0]
password := mkBase64(t, 16)

View file

@ -18,7 +18,7 @@ func newUUID() uuid.UUID {
return user
}
func _TestVMessAuto(t *testing.T) {
func TestVMessAuto(t *testing.T) {
security := "auto"
t.Run("self", func(t *testing.T) {
testVMessSelf(t, security, 0, false, false, false)

View file

@ -25,8 +25,9 @@ type Client struct {
serverAddr M.Socksaddr
tlsConfig *tls.STDConfig
quicConfig *quic.Config
conn quic.Connection
connAccess sync.Mutex
conn quic.Connection
rawConn net.Conn
}
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
@ -64,7 +65,6 @@ func (c *Client) offer() (quic.Connection, error) {
if err != nil {
return nil, err
}
c.conn = conn
return conn, nil
}
@ -80,6 +80,8 @@ func (c *Client) offerNew() (quic.Connection, error) {
packetConn.Close()
return nil, err
}
c.conn = quicConn
c.rawConn = udpConn
return quicConn, nil
}
@ -94,3 +96,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
}
return &hysteria.StreamWrapper{Conn: conn, Stream: stream}, nil
}
func (c *Client) Close() error {
return common.Close(c.conn, c.rawConn)
}

View file

@ -20,6 +20,7 @@ type ClientBind struct {
peerAddr M.Socksaddr
connAccess sync.Mutex
conn *wireConn
done chan struct{}
}
func NewClientBind(ctx context.Context, dialer N.Dialer, peerAddr M.Socksaddr) *ClientBind {
@ -63,6 +64,12 @@ func (c *ClientBind) connect() (*wireConn, error) {
}
func (c *ClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint16, err error) {
select {
case <-c.done:
err = net.ErrClosed
return
default:
}
return []conn.ReceiveFunc{c.receive}, 0, nil
}
@ -75,7 +82,12 @@ func (c *ClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) {
n, err = udpConn.Read(b)
if err != nil {
udpConn.Close()
err = &wireError{err}
select {
case <-c.done:
default:
err = &wireError{err}
}
return
}
ep = Endpoint(c.peerAddr)
return
@ -85,6 +97,16 @@ func (c *ClientBind) Close() error {
c.connAccess.Lock()
defer c.connAccess.Unlock()
common.Close(common.PtrOrNil(c.conn))
if c.done == nil {
c.done = make(chan struct{})
return nil
}
select {
case <-c.done:
return net.ErrClosed
default:
close(c.done)
}
return nil
}

View file

@ -35,7 +35,6 @@ type StackDevice struct {
events chan tun.Event
outbound chan *stack.PacketBuffer
dispatcher stack.NetworkDispatcher
done chan struct{}
addr4 tcpip.Address
addr6 tcpip.Address
}
@ -51,7 +50,6 @@ func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (*StackDevice, er
mtu: mtu,
events: make(chan tun.Event, 1),
outbound: make(chan *stack.PacketBuffer, 256),
done: make(chan struct{}),
}
err := ipStack.CreateNIC(defaultNIC, (*wireEndpoint)(tunDevice))
if err != nil {
@ -193,11 +191,11 @@ func (w *StackDevice) Events() chan tun.Event {
func (w *StackDevice) Close() error {
select {
case <-w.done:
case <-w.events:
return os.ErrClosed
default:
close(w.events)
}
close(w.done)
w.stack.Close()
for _, endpoint := range w.stack.CleanupEndpoints() {
endpoint.Abort()

View file

@ -106,5 +106,11 @@ func (w *SystemDevice) Events() chan wgTun.Event {
}
func (w *SystemDevice) Close() error {
select {
case <-w.events:
return os.ErrClosed
default:
close(w.events)
}
return w.device.Close()
}