Skip to content

Commit 2fb9331

Browse files
committed
fix: some resources are not released in listener
1 parent 793ce45 commit 2fb9331

File tree

2 files changed

+102
-17
lines changed

2 files changed

+102
-17
lines changed

common/net/listener.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package net
2+
3+
import (
4+
"context"
5+
"net"
6+
"sync"
7+
)
8+
9+
type handleContextListener struct {
10+
net.Listener
11+
ctx context.Context
12+
cancel context.CancelFunc
13+
conns chan net.Conn
14+
err error
15+
once sync.Once
16+
handle func(context.Context, net.Conn) (net.Conn, error)
17+
panicLog func(any)
18+
}
19+
20+
func (l *handleContextListener) init() {
21+
go func() {
22+
for {
23+
c, err := l.Listener.Accept()
24+
if err != nil {
25+
l.err = err
26+
close(l.conns)
27+
return
28+
}
29+
go func() {
30+
defer func() {
31+
if r := recover(); r != nil {
32+
if l.panicLog != nil {
33+
l.panicLog(r)
34+
}
35+
}
36+
}()
37+
if c, err := l.handle(l.ctx, c); err == nil {
38+
l.conns <- c
39+
} else {
40+
// handle failed, close the underlying connection.
41+
_ = c.Close()
42+
}
43+
}()
44+
}
45+
}()
46+
}
47+
48+
func (l *handleContextListener) Accept() (net.Conn, error) {
49+
l.once.Do(l.init)
50+
if c, ok := <-l.conns; ok {
51+
return c, nil
52+
}
53+
return nil, l.err
54+
}
55+
56+
func (l *handleContextListener) Close() error {
57+
l.cancel()
58+
l.once.Do(func() { // l.init has not been called yet, so close related resources directly.
59+
l.err = net.ErrClosed
60+
close(l.conns)
61+
})
62+
defer func() {
63+
// at here, listener has been closed, so we should close all connections in the channel
64+
for c := range l.conns {
65+
go func(c net.Conn) {
66+
defer func() {
67+
if r := recover(); r != nil {
68+
if l.panicLog != nil {
69+
l.panicLog(r)
70+
}
71+
}
72+
}()
73+
_ = c.Close()
74+
}(c)
75+
}
76+
}()
77+
return l.Listener.Close()
78+
}
79+
80+
func NewHandleContextListener(ctx context.Context, l net.Listener, handle func(context.Context, net.Conn) (net.Conn, error), panicLog func(any)) net.Listener {
81+
ctx, cancel := context.WithCancel(ctx)
82+
return &handleContextListener{
83+
Listener: l,
84+
ctx: ctx,
85+
cancel: cancel,
86+
conns: make(chan net.Conn),
87+
handle: handle,
88+
panicLog: panicLog,
89+
}
90+
}

listener/reality/reality.go

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net"
1010
"time"
1111

12+
N "github.com/metacubex/mihomo/common/net"
1213
C "github.com/metacubex/mihomo/constant"
1314
"github.com/metacubex/mihomo/listener/inner"
1415
"github.com/metacubex/mihomo/log"
@@ -79,11 +80,17 @@ type Builder struct {
7980
}
8081

8182
func (b Builder) NewListener(l net.Listener) net.Listener {
82-
l = utls.NewRealityListener(l, b.realityConfig)
83-
// Due to low implementation quality, the reality server intercepted half close and caused memory leaks.
84-
// We fixed it by calling Close() directly.
85-
l = realityListenerWrapper{l}
86-
return l
83+
return N.NewHandleContextListener(context.Background(), l, func(ctx context.Context, conn net.Conn) (net.Conn, error) {
84+
c, err := utls.RealityServer(ctx, conn, b.realityConfig)
85+
if err != nil {
86+
return nil, err
87+
}
88+
// Due to low implementation quality, the reality server intercepted half-close and caused memory leaks.
89+
// We fixed it by calling Close() directly.
90+
return realityConnWrapper{c}, nil
91+
}, func(a any) {
92+
log.Errorln("reality server panic: %s", a)
93+
})
8794
}
8895

8996
type realityConnWrapper struct {
@@ -97,15 +104,3 @@ func (c realityConnWrapper) Upstream() any {
97104
func (c realityConnWrapper) CloseWrite() error {
98105
return c.Close()
99106
}
100-
101-
type realityListenerWrapper struct {
102-
net.Listener
103-
}
104-
105-
func (l realityListenerWrapper) Accept() (net.Conn, error) {
106-
c, err := l.Listener.Accept()
107-
if err != nil {
108-
return nil, err
109-
}
110-
return realityConnWrapper{c.(*utls.Conn)}, nil
111-
}

0 commit comments

Comments
 (0)