Skip to content

Commit

Permalink
Fix URLTest outbound
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Dec 2, 2023
1 parent fc8e499 commit 5269231
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 58 deletions.
2 changes: 1 addition & 1 deletion adapter/experimental.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type OutboundGroup interface {

type URLTestGroup interface {
OutboundGroup
URLTest(ctx context.Context, url string) (map[string]uint16, error)
URLTest(ctx context.Context) (map[string]uint16, error)
}

func OutboundTag(detour Outbound) string {
Expand Down
1 change: 1 addition & 0 deletions adapter/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

type Router interface {
Service
PostStarter

Outbounds() []Outbound
Outbound(tag string) (Outbound, bool)
Expand Down
15 changes: 8 additions & 7 deletions box.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func (s *Box) start() error {
return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
}
}
return nil
return s.postStart()
}

func (s *Box) postStart() error {
Expand All @@ -269,16 +269,17 @@ func (s *Box) postStart() error {
return E.Cause(err, "start ", serviceName)
}
}
for serviceName, service := range s.outbounds {
if lateService, isLateService := service.(adapter.PostStarter); isLateService {
s.logger.Trace("post-starting ", service)
err := lateService.PostStart()
for _, outbound := range s.outbounds {
if lateOutbound, isLateOutbound := outbound.(adapter.PostStarter); isLateOutbound {
s.logger.Trace("post-starting outbound/", outbound.Tag())
err := lateOutbound.PostStart()
if err != nil {
return E.Cause(err, "post-start ", serviceName)
return E.Cause(err, "post-start outbound/", outbound.Tag())
}
}
}
return nil
s.logger.Trace("post-starting router")
return s.router.PostStart()
}

func (s *Box) Close() error {
Expand Down
2 changes: 1 addition & 1 deletion experimental/clashapi/api_meta_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)

var result map[string]uint16
if urlTestGroup, isURLTestGroup := group.(adapter.URLTestGroup); isURLTestGroup {
result, err = urlTestGroup.URLTest(ctx, url)
result, err = urlTestGroup.URLTest(ctx)
} else {
outbounds := common.FilterNotNil(common.Map(group.All(), func(it string) adapter.Outbound {
itOutbound, _ := server.router.Outbound(it)
Expand Down
78 changes: 31 additions & 47 deletions outbound/urltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package outbound
import (
"context"
"net"
"sort"
"sync"
"time"

Expand Down Expand Up @@ -38,7 +37,6 @@ type URLTest struct {
tolerance uint16
group *URLTestGroup
interruptExternalConnections bool
started bool
}

func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.URLTestOutboundOptions) (*URLTest, error) {
Expand Down Expand Up @@ -84,8 +82,7 @@ func (s *URLTest) Start() error {
}

func (s *URLTest) PostStart() error {
s.started = true
go s.CheckOutbounds()
s.group.PostStart()
return nil
}

Expand All @@ -103,18 +100,16 @@ func (s *URLTest) All() []string {
return s.tags
}

func (s *URLTest) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
return s.group.URLTest(ctx, link)
func (s *URLTest) URLTest(ctx context.Context) (map[string]uint16, error) {
return s.group.URLTest(ctx)
}

func (s *URLTest) CheckOutbounds() {
s.group.CheckOutbounds(true)
}

func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
if s.started {
s.group.Start()
}
s.group.Touch()
outbound := s.group.Select(network)
conn, err := outbound.DialContext(ctx, network, destination)
if err == nil {
Expand All @@ -126,9 +121,7 @@ func (s *URLTest) DialContext(ctx context.Context, network string, destination M
}

func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if s.started {
s.group.Start()
}
s.group.Touch()
outbound := s.group.Select(N.NetworkUDP)
conn, err := outbound.ListenPacket(ctx, destination)
if err == nil {
Expand Down Expand Up @@ -170,9 +163,11 @@ type URLTestGroup struct {
interruptGroup *interrupt.Group
interruptExternalConnections bool

access sync.Mutex
ticker *time.Ticker
close chan struct{}
access sync.Mutex
ticker *time.Ticker
close chan struct{}
started bool
lastActive atomic.TypedValue[time.Time]
}

func NewURLTestGroup(
Expand Down Expand Up @@ -214,8 +209,18 @@ func NewURLTestGroup(
}
}

func (g *URLTestGroup) Start() {
func (g *URLTestGroup) PostStart() {
g.started = true
g.lastActive.Store(time.Now())
go g.CheckOutbounds(false)
}

func (g *URLTestGroup) Touch() {
if !g.started {
return
}
if g.ticker != nil {
g.lastActive.Store(time.Now())
return
}
g.access.Lock()
Expand Down Expand Up @@ -266,51 +271,30 @@ func (g *URLTestGroup) Select(network string) adapter.Outbound {
return minOutbound
}

func (g *URLTestGroup) Fallback(used adapter.Outbound) []adapter.Outbound {
outbounds := make([]adapter.Outbound, 0, len(g.outbounds)-1)
for _, detour := range g.outbounds {
if detour != used {
outbounds = append(outbounds, detour)
}
}
sort.SliceStable(outbounds, func(i, j int) bool {
oi := outbounds[i]
oj := outbounds[j]
hi := g.history.LoadURLTestHistory(RealTag(oi))
if hi == nil {
return false
}
hj := g.history.LoadURLTestHistory(RealTag(oj))
if hj == nil {
return false
}
return hi.Delay < hj.Delay
})
return outbounds
}

func (g *URLTestGroup) loopCheck() {
go g.CheckOutbounds(true)
if time.Now().Sub(g.lastActive.Load()) > g.interval {
g.CheckOutbounds(false)
}
for {
g.pauseManager.WaitActive()
select {
case <-g.close:
return
case <-g.ticker.C:
g.CheckOutbounds(false)
}
g.pauseManager.WaitActive()
g.CheckOutbounds(false)
}
}

func (g *URLTestGroup) CheckOutbounds(force bool) {
_, _ = g.urlTest(g.ctx, g.link, force)
_, _ = g.urlTest(g.ctx, force)
}

func (g *URLTestGroup) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
return g.urlTest(ctx, link, false)
func (g *URLTestGroup) URLTest(ctx context.Context) (map[string]uint16, error) {
return g.urlTest(ctx, false)
}

func (g *URLTestGroup) urlTest(ctx context.Context, link string, force bool) (map[string]uint16, error) {
func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint16, error) {
result := make(map[string]uint16)
if g.checking.Swap(true) {
return result, nil
Expand All @@ -337,7 +321,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, link string, force bool) (ma
b.Go(realTag, func() (any, error) {
ctx, cancel := context.WithTimeout(context.Background(), C.TCPTimeout)
defer cancel()
t, err := urltest.URLTest(ctx, link, p)
t, err := urltest.URLTest(ctx, g.link, p)
if err != nil {
g.logger.Debug("outbound ", tag, " unavailable: ", err)
g.history.DeleteURLTestHistory(realTag)
Expand Down
13 changes: 11 additions & 2 deletions route/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type Router struct {
platformInterface platform.Interface
needWIFIState bool
wifiState adapter.WIFIState
started bool
}

func NewRouter(
Expand Down Expand Up @@ -571,6 +572,11 @@ func (r *Router) Close() error {
return err
}

func (r *Router) PostStart() error {
r.started = true
return nil
}

func (r *Router) Outbound(tag string) (adapter.Outbound, bool) {
outbound, loaded := r.outboundByTag[tag]
return outbound, loaded
Expand Down Expand Up @@ -1015,8 +1021,11 @@ func (r *Router) notifyNetworkUpdate(event int) {
}
}

r.ResetNetwork()
return
if !r.started {
return
}

_ = r.ResetNetwork()
}

func (r *Router) ResetNetwork() error {
Expand Down

0 comments on commit 5269231

Please sign in to comment.